2011-03-27 125 views
0

我有多GB的郵件服務器日誌文件和一個〜350k郵件ID列表。 我想從從一長串的ID大的日誌文件行拉出來......我希望它的速度比現在...... 目前我做在Perl:郵件服務器日誌過濾

#!/usr/bin/perl 

use warnings; 

#opening file with the list - over 350k unique ID 
open ID, maillog_id; 
@lista_id = <ID>; 
close ID; 
chomp @lista_id; 

open LOG, maillog; 
# while - foreach would cause out of memory 
while (<LOG>) { 
     $wiersz = $_; 
     my @wiersz_split = split (' ' , $wiersz); 
     # 
     foreach (@lista_id) { 
      $id = $_; 
      # ID in maillog is 6th column 
      if ($wiersz_split[5] eq $id) { 
      # print whole row when matched - can be STDOUT or file or anything 
      print "@wiersz_split\n"; 
      } 
     } 
} 
close LOG; 

它的工作原理但它很慢...每一條日誌都與ID列表進行比較。 我應該使用數據庫並執行一種連接?或比較子串?

有很多日誌分析工具 - 例如, pflogsumm ...但它只是總結。例如。我可以用

grep -c "status=sent" maillog 

這將是快,但無用的,我會用它過濾後我的日誌文件......這同樣適用於pflogsumm等 - 只是增加變數。

有什麼建議嗎?

-------------------- UPDATE -------------------

謝謝Dallaylaen, 我這個succeded(而不是內部的foreach上@lista_id):

if (exists $lista_id_hash{$wiersz_split[5]}) { print "$wiersz"; } 

其中%lista_id_hash是一個哈希表,其中鍵是從我的ID列表中拍攝的內容。它工作超快。 處理具有> 350k ID的4,6 GB日誌文件需要不到1分鐘的時間來過濾感興趣的日誌。

回答

2

使用散列。

my %known; 
$known{$_} = 1 for @lista_id; 
# ... 
while (<>) { 
    # ... determine id 
    if ($known{$id}) { 
     # process line 
    }; 
}; 

P.S.如果你的日誌很大,你可能會更好地按照例如後兩個$ id字母分成256個(或36 ** 2個)較小的文件。就像一個窮人的MapReduce。一次存儲在內存中的ID數量也會減少(即當你處理maillog.split.cf時,你應該只保留散列中以「cf」結尾的ID)。

+0

想要提供類似的方法,只使用map:'my%known = map {$ _ => 1} @lista_id;' – 2011-03-27 19:28:50

+0

@wk:'map'或'for'在這裏是等價的,但更謹慎的方法是在(')'循環中,完全跳過'@ lista_id'並填充'%known'',這可以減少內存使用量。 – Dallaylaen 2011-03-27 21:10:53