2016-12-15 166 views
0

我正在用python編寫腳本來解析ldap日誌,然後獲取每個用戶的搜索/綁定數量。我在樣本文件和小文件上測試我的代碼,直到5-10MB的大小運行得很快,並在我的本地PC上在1分鐘內完成。但是,當我在一個價值18M的文件上運行該腳本時,其大約有150000行,大約需要5分鐘,我希望在100M的文件大小上運行此腳本,並且可能在每次運行時都有5-6個文件,這意味着腳本具有在每次運行中解析幾乎600-700M的數據。但是我想這需要很長時間才能運行,所以如果我的下面的代碼可以在執行時間方面獲得更好的性能,那麼我需要一些建議。需要很長時間才能運行的python腳本

import os,re,datetime 
from collections import defaultdict 

d=defaultdict(list) 
k=defaultdict(list) 
start_time=datetime.datetime.now() 

fh = open("C:\\Rohit\\ECD Utilization Script - Copy\\logdir\\access","r").read() 
pat=re.compile(' BIND REQ .*conn=([\d]*).*dn=(.*")') 

srchStr='\n'.join(re.findall(r' SEARCH REQ .*',fh)) 

bindlist=re.findall(pat,fh) 
for entry in bindlist: 
    d[entry[-1].split(",")[0]].append(entry[0]) 

for key in d: 
    for con in d[key]: 
     count = re.findall(con,srchStr) 
     k[key].append((con,len(count))) 

# 
for key in k: 
    print("Number of searches by ",key, " : ",sum([i[1] for i in k[key]])) 

for key in d: 
    print("No of bind ",key," = ",len(d[key])) 


end_time=datetime.datetime.now() 
print("Total time taken - {}".format(end_time-start_time)) 

回答

0

我能用下面的代碼解決我的問題。

import os,re,datetime 
from collections import defaultdict 



start_time=datetime.datetime.now() 

bind_count=defaultdict(int) 
search_conn=defaultdict(int) 
bind_conn=defaultdict(str) 
j=defaultdict(int) 



fh = open("C:\\access","r") 
total_searches=0 
total_binds=0 

for line in fh: 
    reg1=re.search(r' BIND REQ .*conn=(\d+).*dn=(.*")', line) 
    reg2=re.search(r' SEARCH REQ .*conn=(\d+).*', line) 
    if reg1: 
     total_binds+=1 
     uid,con=reg1.group(2,1) 
     bind_count[uid]=bind_count[uid]+1 
     bind_conn[con]=uid 

    if reg2: 
     total_searches+=1 
     skey=reg2.group(1) 
     search_conn[skey] = search_conn[skey]+1 


for conid in search_conn: 
    if conid in bind_conn: 
     new_key=bind_conn[conid] 
     j[new_key]=j[new_key]+search_conn[conid] 




for k,v in bind_count.items(): 
    print(k," = ",v) 

print("*"*80) 

for k,v in j.items(): 
    print(k,"-->",v) 

fh.close() 

del search_conn 
del bind_conn 

end_time=datetime.datetime.now() 
print("Total time taken - {}".format(end_time-start_time)) 
0

使用itertools庫而不是這麼多的循環。

+0

你可以請分享一些見解如何做到這一點,我很新,並沒有使用itertools到現在。任何開始將是很大的幫助。 – Rohit

+0

我該如何使用itertools來避免下面的循環 '對於key in d:for con in d [key]:count = re.findall(con,fh1)k [key] .append((con,len(count) ))' – Rohit

+0

你可以在上面的評論中回答我的問題嗎? – Rohit

0

您的腳本具有二次複雜性:對於文件中的每一行,您將再次進行讀取以匹配日誌條目。 我的建議是隻讀一次文件並計算所需條目(匹配的一個(「BIND REQ」))的出現次數。

+0

我已經在一定程度上編輯了我的代碼,但是我仍然無法擺脫這個冗長的循環,這是問題的關鍵。你能否建議一個更好的方法來做到這一點。 '用於d鍵: 在d [鍵] CON: 計數= re.findall(CON,srchStr) K [鍵] .append((CON,LEN(計數)))' 該循環贏得」 t對小文件來說是一個問題,但在大文件中,d [key]的值列表長度也可以達到34000,所以有很大的計算 – Rohit

+0

你好,請你回答? – Rohit

+0

我在這裏。我認爲它更容易(如果我理解你的代碼)一次處理一行輸入文件。在其上搜索你需要的字符串,並在數據結構中添加事件(就像保存計數的字典)。 – pinturic

1

你上線做對整個文件多次掃描

count = re.findall('SEARCH REQ.*'+conid,fh1)

避免這一點。這是你的主要問題。獲取列表中的所有conid,並重新迭代文件並列出,而內部循環應由conid組成。將它從外部循環中移出。你會做兩個文件掃描。

此外,由於它是普通的Python與PyPy運行更快的運行。

你可以用FSM和花更多的RAM來做到這一點。這是一個提示,你將不得不自己做你的FSM。

編輯1:這是我看到日誌文件後編寫的腳本版本。如果有任何錯誤,請糾正:

#!/usr/bin/env python 

import sys 
import re 


def parse(filepath): 
     d = {} 
     regex1 = re.compile(r'(.*)?BIND\sREQ(.*)uid=(\w+)') 
     regex2 = re.compile(r'(.*)?SEARCH\sREQ(.*)uid=(\w+)') 
     with open(filepath, 'r') as f: 
       for l in f: 
         m = re.search(regex1, l) 
         if m: 
           # print (m.group(3)) 
           uid = m.group(3) 
           if uid in d: 
             d[uid]['bind_count'] += 1 
           else: 
             d[uid] = {} 
             d[uid]['bind_count'] = 1 
             d[uid]['search_count'] = 0 
         m = re.search(regex2, l) 
         if m: 
           # print (m.group(3)) 
           uid = m.group(3) 
           if uid in d: 
             d[uid]['search_count'] += 1 
           else: 
             d[uid] = {} 
             d[uid]['search_count'] = 1 
             d[uid]['bind_count'] = 0 

     for k in d: 
       print('user id = ' + k, 'Bind count = ' + str(d[k]['bind_count']), 'Search count = ' + str(d[k]['search_count'])) 


def process_args(): 
     if sys.argv < 2: 
       print('Usage: parse_ldap_log.py log_filepath') 
       exit(1) 



if __name__ == '__main__': 
     process_args() 
    parse(sys.argv[1]) 

感謝上帝,它並不足以保證FSM。

+0

下面的代碼如何做得更好......在下面的迭代中會有很多重複,我怎麼能避免這種情況。 (con,srchStr) k [key] .append((con,len(count))) – Rohit

+0

構造FSM。這是最好的方法。 – user902384

+0

你能指導我在某個方向上,這樣我就可以開始了。 – Rohit

相關問題