博客又双叒叕一个多月没更了,今天(好吧,我承认这是之前的存稿)就来比较下Linux下对数据去重处理的几种方式,更具体一点讲就是比较sort -u、uniq、awk '!x[$0]++' 等方法的效果与效率。
输入文件为Nginx的日志文件,共100万行,文件名为nginx.log,其格式为“时间|用户IP|主机名|发送流量(字节)|下载流量(字节)|耗时(毫秒)”
具体内容截取如下(部分内容已被隐藏):
2018-03-03T20:00:52+08:00 | 116.237.***.205 | *****.********.com | 780 | 4319 | 1.495 2018-03-03T20:00:52+08:00 | 39.181.***.45 | *****.********.com | 3820 | 3777 | 1.480 2018-03-03T20:00:52+08:00 | 101.87.***.203 | *****.********.com | 617 | 4427 | 29.249 2018-03-03T20:00:52+08:00 | 183.206.***.72 | *****.********.com | 2481 | 5164 | 20.894 2018-03-03T20:00:52+08:00 | 59.56.***.98 | *****.********.com | 825 | 4425 | 1.679 2018-03-03T20:00:53+08:00 | 27.198.***.59 | www.******.**.** | 287 | 1034 | 240.426 2018-03-03T20:00:53+08:00 | 112.67.***.155 | *****.********.com | 2914 | 726 | 40.238 2018-03-03T20:00:53+08:00 | 153.34.***.97 | *****.********.com | 552 | 4420 | 185.736 2018-03-03T20:00:53+08:00 | 113.232.***.0 | www.******.com | 124 | 3221 | 1.022
接下来分别采用上面几种不同的方式去重提取出用户IP地址并比较其效率,每种方法各执行三次取消耗时间的平均值。注意,我这里仅仅保留了IP字段,请灵活运用!如保留整行的话请替换$2为$0。
第一种方式:sort+uniq:
提到文本去重,Linux下有个uniq工具,顾名思义就是用来取唯一值的嘛!uniq走起!但,但是,,,uniq命令只能对相邻的重复行去重,所以在使用uniq前需要先排序,使相同内容的行相邻,再去重才行,于是就有了下面的命令:
time awk 'BEGIN{FS="|"}{print $2}' nginx.log|sort|uniq >/dev/null
耗时:0m7.609s、0m7.538s、0m7.782s 平均:7.643s
注意:这种去重方式会改变待处理内容原本的行序!
第二种方式:sort -u:
uniq使用前还得保证相同行相邻,是不是觉得很鸡肋?sort命令其实是有取唯一值功能的,只需加个-u参数即可:
time awk 'BEGIN{FS="|"}{print $2}' nginx.log|sort -u >/dev/null
耗时:0m6.242s、 0m6.136s、0m5.920s 平均:6.099s
可以看到直接使用sort -u比sort后再uniq要节省一点时间!这种方式同样也是会改变原本的行序的。
第三种方式:awk:
哇!重量级工具出场了!awk是一个非常强大的文本分析处理工具,用起来非常爽!awk支持关联数组,下面三条命令原理和效果基本是一样的,都是把IP作为key进行处理,区别是前两条是直接把第一次出现的IP输出出来,非第一次出现的IP直接忽略;第三条是,遍历所有行后直接输出key实现去重操作。
#只保留第一次出现的字段,去除后续其他字段 time awk 'BEGIN{FS="|"}{print $2}' nginx.log|awk '!x[$0]++' >/dev/null
#只保留第一次出现的字段,去除后续其他字段 time awk 'BEGIN{FS="|"}{if(!x[$2]++){print $2}}' nginx.log >/dev/null
#乱序 time awk 'BEGIN{FS="|"}{a[$2]}END{for(i in a)print i }' nginx.log >/dev/null
#只保留最后一次出现的字段,去除之前其他字段(这条是后续加的,未测试耗时) awk 'BEGIN{FS="|"}{a[$2]=NR;b[NR]=$2}END{n=asort(a);for(i=1;i<=n;i++)print b[a[i]]}' nginx.log
耗时:
第一条:0m2.362s、0m2.405s、0m2.052s 平均:2.273s
第二条:0m2.116s、0m2.130s、0m2.151s 平均:2.132s
第三条:0m2.238s、0m1.944s、0m2.251s 平均:2.144s
这种利用awk关联数组的去重方式无需进行耗时的排序操作,也就没有那么高的时间复杂度,当处理的内容较多时,效率优势就非常明显了,而且前两条命令是不会改变原内容出现先后顺序的,各行出现的顺序还是原来的!可以说是非常完美的一种去重方式了!注意这里的第一条的第二条完全是一个东西,只是写法稍微有点不同罢了,只保留最后出现的字段还可以使用tac反序再去重然后再反序的思路。
总结:当待去重的数据量非常大或者有保留原有行序需求的时候,应该选择使用awk对数据进行去重!其他情况下嘛!看心情随便选一个就行~~~
啊啊啊啊啊啊啊啊
博主Pixiv是不支持了吗
支持且我这边正常
你好
你好
大神,请问怎么打赏?
@东方不妨去Pure DNS捐赠吧
https://puredns.cn/donate/
为什么不试试自己写一个cmp呢(划
@Woshiluocmp改kmp
大哥。pureDNS能不能增加对http://cnpolitics.org/ 政见网的支持?
博主求教翻墙,我新萌,你们讲的专业术语我都不懂 ,你可以直接告诉我该干嘛么!!please
鸟叔看不懂,哈哈
:mrgreen:多谢博主的dns
大佬,现在北方是用不了的对吗?
能用,就是目前宽带不够大家用,高峰时几秒解析不出来结果都正常,而南方节点目前使用人数才是满载人数的2%左右,强烈推荐只使用南方节点。
看不懂,但是赞一个!
看标题还以为是论文去重那种去重,好像进入了我完全 不了解的领域啊
@Aaron哇,论文去重。。。。太高级了,不会。仅仅是简单的文本按行去重而已……
看不懂,我就在下面喊喊666算了
看不懂.