2011-08-16 8 views
8

큰 파일 (1 억 줄의 탭 구분 값 - 약 1.5GB 크기)이 있습니다. 필드 중 하나를 기준으로 정렬하는 가장 빠른 방법은 무엇입니까?큰 텍스트 데이터 정렬

하이브를 시도했습니다. 이 파이썬을 사용하여 더 빨리 수행 할 수 있는지보고 싶습니다.

답변

16

* nix sort 프로그램을 사용 해본 적이 있습니까? 원시 측면에서는 대부분의 Python 스크립트보다 빠를 것입니다.

사용 -t $'\t'는 탭으로 구분하면 출력에 새 파일로 결과를 원하는 경우 n 필드 번호, -o outputfile있는 필드를 지정하려면 -k n을 있다고 지정합니다. 예 :

sort -t $'\t' -k 4 -o sorted.txt input.txt 

이 다음에 관심이 필드에서 인덱스를, 내가 좋은 관계형 데이터베이스에 파일을 저장하는 것 sorted.txt

+0

unix sort 명령은 실제로 매우 강력한 도구입니다. 정렬 할 필드의 형식 (숫자, 날짜 등) 및 프로그램에서 할당 할 수있는 메모리 양을 제어하고 필요한 경우 분할 + 병합 정렬을 수행 할 수 있습니다. –

+0

알렉스 예를 들려 줄 수 있습니까? 정렬 프로그램 자체는 40 분 정도 걸리는 꽤 오랜 시간이 걸립니다. 이것은 메모리 할당이나 디스크 IO와 관련이있을 수 있습니다. 병목 현상이 무엇인지 파악하는 방법을 모르겠지만 제안이 유용 할 것으로 짐작됩니다. – fodon

+1

위의 솔루션에서 하나의 오류 : 두 번째 필드 만 사용하려면 하나는 -k 2,2 ...가 필요합니다. 따라서 제로 인덱싱되지 않습니다 (적어도 쿠분투 11.04 버전의 정렬에는 해당되지 않음). – fodon

1

그 결과를 자사의 4 번째 필드에 input.txt를 정렬 및 출력 것인가 주문한 품목을 읽으십시오.

7

당신은 파일에 대한 메모리 인덱스 구축하려는 : 만들 빈 목록을

  1. open 목록에서
  2. 이 라인 씩 (f.readline()를 사용하여 읽을 파일 저장 정렬 할 값 (line.split('\t').strip()으로 추출)과 파일의 줄 오프셋 (f.readline()에 호출하기 전에 f.tell()을 호출하여 얻을 수있는)로 구성된 튜플
  3. close 파일
  4. sort

그런 다음, 정렬 된 파일을 인쇄 파일을 다시 열어 목록의 각 요소에 대해, 읽기, 줄의 시작 부분에 f.readline()을 파일 포인터를 이동 f.seek(offset)을 사용하는 목록 라인 및 print 라인.

최적화 : 인쇄 단계에서 f.read(length)을 사용할 수 있도록 목록의 줄 길이를 저장할 수 있습니다. (가독성을 위해 최적화 된 속도를하지 않음)

샘플 코드 : 최대 메모리에 정렬 할 수있는 파일로

def build_index(filename, sort_col): 
    index = [] 
    f = open(filename) 
    while True: 
     offset = f.tell() 
     line = f.readline() 
     if not line: 
      break 
     length = len(line) 
     col = line.split('\t')[sort_col].strip() 
     index.append((col, offset, length)) 
    f.close() 
    index.sort() 
    return index 

def print_sorted(filename, col_sort): 
    index = build_index(filename, col_sort) 
    f = open(filename) 
    for col, offset, length in index: 
     f.seek(offset) 
     print f.read(length).rstrip('\n') 

if __name__ == '__main__': 
    filename = 'somefile.txt' 
    sort_col = 2 
    print_sorted(filename, sort_col) 
3

분할. 메모리에있는 각 파일을 정렬하십시오. 그런 다음 결과 파일을 병합하십시오.

병합 할 각 파일의 일부를 읽음으로써 병합합니다. 병합 된 결과를 위해 충분한 공간을 메모리에 남겨 두는 각 파일의 동일한 양. 한 번 병합이 저장합니다. 병합 된 데이터 블록을 파일에 반복적으로 추가.

이렇게하면 파일 입/출력이 최소화되고 디스크의 파일을 중심으로 이동합니다.