2014-10-01 47 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" }'