2011-03-27 3 views
0

여러 개의 GB 메일 서버 로그 파일과 ~ 350k 개의 메시지 ID 목록이 있습니다. 나는 긴 목록에서 ID가 큰 로그 파일 행에서 빼 할 ... 내가 지금보다 더 빨리 원하는 ... 현재 나는 펄에서 할 :메일 서버 로그 필터링

#!/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 ... 그러나 그것은 단지 요약합니다. 예 : 단지 변수를 증가 - 동일 pflogsumm 등입니다 ... 나는

grep -c "status=sent" maillog 

그것은 빠르지 만 쓸모가있을 것입니다 사용할 수 있습니다 그리고 내 로그 파일을 필터링 후 사용한다.

제안 사항?

-------------------

감사합니다. Dallaylaen, 나는 (@lista_id 대신 내부 foreach 문)이 함께 succeded :

%lista_id_hash 키를 내 ID 목록에서 가져온 항목은 해시 테이블입니다
if (exists $lista_id_hash{$wiersz_split[5]}) { print "$wiersz"; } 

. 그것은 초고속으로 작동합니다. 350KB 이상의 ID를 가진 4,6GB 로그 파일을 처리하는 데는 흥미로운 로그를 필터링하는 데 1 분도 걸리지 않습니다.

답변

2

해시를 사용하십시오.

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

P. 로그의 크기가 클 경우 예를 들어. $ id의 마지막 두 글자는 256 (또는 36 ** 2?) 개의 작은 파일로 나뉩니다. 가난한 사람의 MapReduce와 같은 것. 한 번에 메모리에 저장할 ID의 수가 줄어 듭니다 (예 : maillog.split.cf를 처리 할 때 해시에서 "cf"로 끝나는 ID 만 유지해야 함).

+0

내 제안은 비슷한 접근 방식을 제공합니다 :'my % known = map {$ _ => 1} @lista_id; ' –

+0

@wk :'map' 또는'for'는 여기에 해당하지만 더 신중한 접근 방법은 '@ lista_id'를 건너 뛰고'while ()'루프 안에'% known '을 채우려면 약간 메모리 사용량을 줄일 수 있습니다. – Dallaylaen