linux 下超级大日志文件统计问题,求 V 牛挤点儿奶来解渴!

2016-03-31 17:52:12 +08:00
 yifeng
用一行很长 linux shell 脚本,从格式为“ uid,timestamp ”的 10G 大小的日志中抽取前天 4 点到 5 点间,访问用户最多的前 5 名的 uid 的列表。

求 V 友们给指引方向,谢谢,谢谢,谢谢!
4896 次点击
所在节点    Linux
26 条回复
justfly
2016-03-31 17:58:13 +08:00
方向是 cat | grep | awk

awk 具体统计用法自己查下 我记不清了
visaxin
2016-03-31 17:59:12 +08:00
spark 应该就可以把
yifeng
2016-03-31 18:01:07 +08:00
@justfly 非常感谢,谢谢。
skydiver
2016-03-31 18:02:23 +08:00
这不是常见面试题么……
JamesRuan
2016-03-31 18:16:18 +08:00
10G 不算大吧……
shsfoolish
2016-03-31 18:43:28 +08:00
先用`split`切成多个小文件,每个小文件用`awk`统计前天 4-5 点内的访问量,将每个文件的中间结果输出到临时文件,最后将临时文件求合计算出 top5 ((基本上是 MR 过程..
chairuosen
2016-03-31 19:05:41 +08:00
cat a.txt | awk -F, '$2 < 1433001600500 && $2> 1433001600000 {print $1}' | uniq -c | sort -k1,1nr | head -5
不知道大文件有没有问题
chairuosen
2016-03-31 19:06:09 +08:00
@chairuosen 啊,两个时间戳替换掉。。。
hadoop
2016-03-31 19:11:49 +08:00
@chairuosen 少一步 cat 岂不是更好?
yifeng
2016-03-31 19:16:21 +08:00
@shsfoolish 非常感谢,我试试看
yifeng
2016-03-31 19:18:07 +08:00
@chairuosen 非常感谢, cat 的话效率是个问题,内存负载压力很大吧,还是非常感谢
SlipStupig
2016-03-31 20:54:55 +08:00
10G 一点也不多,给出一些方法
1.这里倒着读取日志,每次读取 10 万行,先搜索符合最后一天的日志(具体搜索算法可以用 bm 或者 kmp 反正数据量不大)记录一下尾部行号,然后接着往上读直到符合要求为止
2.bash 法,用 cat | xarg | unique | grep ""或 awk 这类
3.mysql 直接 loadfile ,建好索引,用 where 语句查询
4.mmap 读取大文件用 re2 写个 regex 匹配一下就好(内存可能会不够)
5.bozo 读取法(最神奇的算法),随机进行读取,然后记录一下,总有一天会完全读取完成的

觉得最省事的就是载入到 mysql 里面,如果你是嵌入式环境当我没说
@visaxin spark 是处理实时流量,这个场景犯不上用那么大的家伙
SlipStupig
2016-03-31 20:56:29 +08:00
v 站不能编辑真头疼,针对第一类可以采用半解析法,这样能更快速定位到行号
wsy2220
2016-03-31 21:22:49 +08:00
导入数据库吧
rrfeng
2016-03-31 21:37:11 +08:00
10G awk 毫无压力吧……

关键是 2 点:估计离文件头近还是尾近,当时间段过完之后(时间肯定是有序的啊)立刻退出,不要继续读文件了。

更高级的写法请用 seek ,跳跃式定位时间点(开始点),然后一直读到结束点。来个 awk 版本的:


awk -F, '$2>TIME_END{exit}$2>TIME_START{s[$1]++}END{for(i in a)print a[i],i}' FILE | sort -k1nr | head -5

这个只要你时间段内 uid 数量不过百万肯定没问题,主要是排序的开销

如果更接近文件末尾,用 tac FILE | awk 然后把 > < 条件改一下就好……
fishg
2016-03-31 21:38:25 +08:00
真不大。。
yifeng
2016-03-31 22:10:00 +08:00
@SlipStupig 非常非常感谢,谢谢你给的思路,感谢!
yifeng
2016-03-31 22:12:20 +08:00
@rrfeng 谢谢,非常感谢,我看大家都提到了 awk,我好好研究一下,谢谢。
ToughGuy
2016-04-01 01:52:57 +08:00
awk -F, '$NF>=1459281600&&$NF<=1459285200{a[$1]++}END{for(i in a){printf("%s\t%s\n",a[i],i)}}' abcd.txt | sort -rn | head -n 5
ToughGuy
2016-04-01 01:54:33 +08:00
@ToughGuy

补充下, 如果字段不止两个的话你需要把$NF 替换成$2

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/267692

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX