2014-10-01 184 views
1

我有一个awk脚本,用于计算某些事务完成所需的时间。脚本获取每个事务的唯一ID并存储每个事务的最小和最大时间戳。然后计算差异,最后显示超过60秒的结果。处理大文件时的AWK性能

使用数千个(200k)时效果很好,但在现实世界中使用需要更多时间。我测试了几次,大约需要15分钟处理大约2800万行。我可以考虑这个好的表现,还是可以改进它?

我愿意接受任何建议。

这里有完整的代码

zgrep -E "\(([a-z0-9]){15,}:" /path/to/very/big/log | awk '{ 
gsub("[()]|:.*","",$4); #just removing ugly chars 
++cont 
min=$4"min" #name for maximun value of current transaction 
max=$4"max" #same as previous, just for readability 
split($2,secs,/[:,]/) #split hours,minutes and seconds 
seconds = 3600*secs[1] + 60*secs[2] + secs[3] #turn everything into seconds 
if(arr[min] > seconds || arr[min] == 0) 
    arr[min]=seconds 
if(arr[max] < seconds) 
    arr[max]=seconds 
dif=arr[max] - arr[min] 
if(dif > 60) 
    result[$4] = dif 
} 
END{ 
for(x in result) 
    print x" - "result[x] 
print ":Processed "cont" lines" 
}' 
+0

关于编辑:零件打印“新的MO找到!”名称“开始于”秒(我将赋值给min [name]的块)仅执行〜= 800次,但是在最后,它报告最小长度约为80k,这是非价值指数的数量。 – Danielo515 2014-10-03 12:17:07

回答

6

你不需要每次读取记录的时间来计算的DIF。只需在END部分执行一次即可。

您不需要该连续变量,只需使用NR。

你不需要分别填充最小值和最大值字符串连接在awk中很慢。

您不应该更改$ 4,因为这将强制记录重新编译。

试试这个:

awk '{ 
    name = $4 
    gsub(/[()]|:.*/,"",name); #just removing ugly chars 

    split($2,secs,/[:,]/) #split hours,minutes and seconds 
    seconds = 3600*secs[1] + 60*secs[2] + secs[3] #turn everything into seconds 

    if (NR==1) { 
     min[name] = max[name] = seconds 
    } 
    else { 
     if (min[name] > seconds) { 
      min[name] = seconds 
     } 
     if (max[name] < seconds) { 
      max[name] = seconds 
     } 
    } 
} 

END { 
    for (name in min) { 
     diff = max[name] - min[name] 
     if (diff > 60) { 
      print name, "-", diff 
     } 
    } 
    print ":Processed", NR, "lines" 
}' 
+0

这很有道理。我明天会检查并告诉你。非常感谢 – Danielo515 2014-10-01 21:03:17

+0

Hello Ed,在尝试解决方案后,我有几条评论:NR == 1在我的场景中没有意义,因为任何行都可以成为事务的第一行。在删除该行并使用min [name] == 0作为启动程序之后,我进行了一些测试,得到了类似的结果:#您的建议:真正的13m45.390s用户18m9.014s#我的代码:真实13m0.101s用户17m47.016s #另外,请你解释为什么修改$ 4可以让awk重新编译整行?只是因为它是我想 – Danielo515 2014-10-02 08:21:12

+0

测试'min [name] ==“”',而不是'== 0'。这只是awk的一个功能,修改字段会重新编译用OFS替换FS的记录。在进行计时时 - 确保你运行每个例子3次,并采取每次第三次运行的结果,因此缓存不是一个因素。我的运行速度要明显快于你的速度,因为我只计算最后一个min/max对的dif,而不是每一行,并且不会重新编译记录并删除“cont”的增量。你在运行中包含'zgrep'吗?有没有可能这就是所有时间都在用的东西? – 2014-10-02 12:41:51

2

做一些测试后,并与建议给埃德莫顿(无论是代码的改进和性能测试),我发现瓶颈是zgrep命令。这里是做几件事情的例子:

  • 检查,如果我们有一个交易行(第一IF)
  • 清理事务ID
  • 检查,如果这已经被登记(第二如果)通过检查它是阵列
  • 在如果未注册,则检查它是否是适当的类型的事务,并且如果这样它注册如果已经登记在第二
  • 时间戳保存新的时间戳作为maximun
  • 毕竟它做了必要的操作来计算时差

非常感谢所有帮助我的人。

zcat /veryBigLog.gz | awk ' 
{if($4 ~ /^\([:alnum:]/){ 
    name=$4;gsub(/[()]|:.*/,"",name); 
    if(!(name in min)){ 
     if($0 ~ /TypeOFTransaction/){ 
      split($2,secs,/[:,]/) 
      seconds = 3600*secs[1] + 60*secs[2] + secs[3] 
      max[name] = min[name]=seconds 
      print lengt(min) "new "name " start at "seconds 
     } 
     }else{ 
      split($2,secs,/[:,]/) 
      seconds = 3600*secs[1] + 60*secs[2] + secs[3] 
      if(max[name] < seconds) max[name]=seconds 
      print name " new max " max[name] 
     } 
     }}END{ 
      for(x in min){ 
       dif=max[x]- min[x] 
       print max[x]" max - min "min[x]" : "dif 
      } 
      print "Processed "NR" Records" 
      print "Found "length(min)" MOs" }'