2016-12-15 113 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