Python] 대용량 파일 처리
파이썬에서 큰 파일(200MB)에 대하여 3가지 정규식을 기준으로 데이터를 추출 할 경우 다음과 같은 코드를 작성 할 수 있다.
코드 1
# -*-coding:utf-8-*-
import re
import time
def get_result(pattern, content):
return pattern.findall(content)
def append_data(name, pattern, content):
result = get_result(pattern, content)
if result:
dic[name] = result
if name == 'main':
start = time.time()
patterns = dict()
patterns['patternA'] = re.compile(
r'SESSION: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)-:angry:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)\((.+?)\),\s',
re.I)
patterns['patternB'] = re.compile(r"(?:\d\`){4}\w{6}\`\d{4}\`\d{8}\`(?:\d{2}\:){2}\d{2}\`", re.I)
patterns['patternC'] = re.compile(r"devname\=\S+\s(?:device_id|devid)\=\S+\s(?:log_id|logid)\=\S+\stype\=\S+\s",
re.I)
dic = dict() # RESULT DATA
with open('log-sample/500000.log', 'r') as log:
for content in log:
for name, pattern in patterns.iteritems():
append_data(name, pattern, content)
end = time.time() - start # end에 코드가 구동된 시간 저장
print (dic["patternA"][0][0])
print (" END TIME : [" + str(end) + "]")
결과는 각 정규식 별로 다르게 나온다. 1번 정규식은 4초, 2번 정규식은 6초, 3번 정규식은 8초 정도로 3개를 한번에 위의 코드같이 처리 할 경우 평균 16초의 시간이 걸린다.
코드 2
# -*-coding:utf-8-*-
import re
import time
from multiprocessing import Pool
def get_result(pattern, content):
return pattern.findall(content)
def append_data(dic, pattern, content):
result = get_result(pattern, content)
if result:
dic.append(result)
def processing(pattern):
dic = []
with open('log-sample/500000.log', 'r') as log:
for content in log:
append_data(dic, pattern, content)
print (len(dic))
if name == '__main__':
start = time.time()
patterns = []
patterns.append(re.compile(
r'SESSION: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)->(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)\((.+?)\),\s',
re.I))
patterns.append(re.compile(r"(?:\d\`){4}\w{6}\`\d{4}\`\d{8}\`(?:\d{2}\:){2}\d{2}\`", re.I))
patterns.append(re.compile(r"devname\=\S+\s(?:device_id|devid)\=\S+\s(?:log_id|logid)\=\S+\stype\=\S+\s",
re.I))
pool = Pool(processes=4)
pool.map(processing, patterns)
end = time.time() - start # end에 코드가 구동된 시간 저장
print ("END TIME : [" + str(end) + "]")
두번째 코드는 각 패턴별로 multiprocessing을 이용하여 실행하는 코드 이다.
이 경우 결과시간은 평균 10초의 시간이 걸린다.
코드 3
# -*-coding:utf-8-*-
import re
import time
import os
from multiprocessing import Pool
def get_result(pattern, content):
return pattern.findall(content)
def append_data(dic, pattern, content):
result = get_result(pattern, content)
if result:
dic.append(result)
filename = 'log-sample/500000.log'
def processing(args):
pattern = args[0]
position = args[1]
reple_dic = args[2]
start_offset = args[3]
end_line = args[4]
dic = []
line_cnt = 0
with open(filename, 'r') as log:
log.seek(start_offset)
for content in log:
append_data(dic, pattern, content)
line_cnt += 1
if line_cnt == end_line:
break;
# TODO use Dic
print (len(dic))
def to_list(*args):
return list(args)
if name == '__main__':
start = time.time()
# Read in the file once and build a list of line offsets
line_offset = []
offset = 0
with open(filename, 'r') as file:
for line in file:
line_offset.append(offset)
offset += len(line)
print "file Line Count : "+ str(len(line_offset))
patterns = []
patterns.append(to_list(re.compile(
r'SESSION: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)->(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)\((.+?)\),\s',
re.I), "0,1,2,3,4", dict(), 0, 250000))
patterns.append(to_list(re.compile(
r'SESSION: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)->(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)\((.+?)\),\s',
re.I), "0,1,2,3,4", dict(), line_offset[250000], 250000))
patterns.append(to_list(re.compile(r"(?:\d\`){4}\w{6}\`\d{4}\`\d{8}\`(?:\d{2}\:){2}\d{2}\`", re.I), "0,1,2,3,4", dict(), 0, 250000))
patterns.append(to_list(re.compile(r"(?:\d\`){4}\w{6}\`\d{4}\`\d{8}\`(?:\d{2}\:){2}\d{2}\`", re.I), "0,1,2,3,4", dict(), line_offset[250000], 250000))
patterns.append(to_list(re.compile(r"devname\=\S+\s(?:device_id|devid)\=\S+\s(?:log_id|logid)\=\S+\stype\=\S+\s", re.I), "0,1,2,3,4", dict(), 0, 250000))
patterns.append(to_list(re.compile(r"devname\=\S+\s(?:device_id|devid)\=\S+\s(?:log_id|logid)\=\S+\stype\=\S+\s", re.I), "0,1,2,3,4", dict(), line_offset[250000], 250000))
pool = Pool(processes=8)
pool.map(processing, patterns)
end = time.time() - start # end에 코드가 구동된 시간 저장
print ("END TIME : [" + str(end) + "]")
파일에 대하여 특정 ROW 부터 처리 하도록 병령 처리를 하면 3번 코드와 같은 형식으로 나온다.
이 경우 실행시간은 평균 5초 가 된다.
큰 파일에 대한 처리는 결국 file.seek를 이용하여 파일을 쪼개어 병렬로 처리 하는게 가장 빠른 방식 같다.