추가 파일 공간없이 큰 파일에서 병렬 awk 명령 실행 awk를 실행하여

상당히 큰 탭으로 구분 된 파일 (~ 30GB)을 처리하려고합니다. awk를 실행하여 열을 다시 정렬 할 수 있지만 8 코어 시스템의 단일 코어 만 사용합니다. 모든 코어를 어떻게 사용할 수 있습니까? 파일을 물리적으로 분할하지 않고 더 많은 디스크 공간을 사용하지 않고 (처리 시간을 대폭 단축)?

cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged.tsv

디스크 공간을 많이 사용하지 않고 다음과 같이하고 싶습니다.

split -l 50000 original.tsv sp
for i in $(dir sp*); do ./process_file.sh $i & done;

여기서 process_file.sh는 본질적으로 위의 cut / awk 문입니다.

여기서도 핵심 문제는 다른 30GB를 사용하지 않고이 프로세스를 수행하는 것입니다! 어떤 제안?



답변

“분할”을 사용하여 파일을 줄 수로 구분 한 다음 개별 파일로 출력하여 개별적으로 처리합니다 (추천). 줄 번호에 따라 파일의 일부만 처리하는 여러 개의 “awk”명령을 수행 할 수 있습니다.

$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; (NR < 50000){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged01.tsv
$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; ((NR >= 50000) && (NR < 100000)){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged02.tsv
$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; ((NR >= 100000) && (NR < 150000)){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged03.tsv

NR은 현재 줄 번호를 포함하는 “awk”에 대한 내부 변수입니다. 각 명령은 해당 범위의 행만 처리합니다. 그러나 , 그들은 모두 계산해야하기 때문에 모두 다른 라인을 거치게됩니다. IO 병목 현상에 빠질 수 있기 때문에 도움이되지 않을 것이라고 확신합니다. 그러나 여러 프로세스가 있으므로 원하는 경우 여러 CPU를 사용할 수 있습니다. 😉

이제, IF 는 바이트 단위로 같은 길이의 모든 라인을 가지고, 당신은 분명히 진정한 병렬화 할 수 있습니다. 이 경우 “dd”를 사용하여 각 “awk”프로세스의 정확한 부분을 추출합니다. 당신은 비슷한 것을 할 것입니다 :

dd if=original.tsv bs=30 count=50000 skip=0 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged01.tsv

dd if=original.tsv bs=30 count=50000 skip=50000 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged02.tsv

dd if=original.tsv bs=30 count=50000 skip=100000 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged03.tsv

여기서 30은 각 줄의 바이트 수입니다. 당신의 라인 바이트 모두 같은 크기되지 않습니다 (가장 가능성이있는) 경우 하지만 당신이 정확한 라인의 당신의 블록이 시작 바이트과 끝을 알고, 당신은 여전히 DD를 사용 할 수 있습니다. 매개 변수를 연구하십시오. 마지막으로, 블록의 시작과 끝을 모르는 경우 추가 awk 명령으로 블록을 찾을 수 있습니다. 그러나 파일에 추가로 전체 읽기가 추가됩니다. original.tsv 파일을 다른 방식으로 여러 번 처리하지 않는 한 사전 처리 (라인 블록이 시작하고 끝나는 바이트 계산) 및 처리 (확실히 약간의 이득이있을 것이므로 아마도 더 많은 시간을 소비 할 것입니다) 이미 알고있는 솔루션을 사용했을 때보 다 IO 병목 현상이 발생했습니다.

어쨌든 이제 정보와 옵션이 있습니다. 😉 행운을 빕니다! (와이)


답변

Fwiw에는 split명령 --filter=./myscript.sh에 출력 파일에 쓰기 전에 데이터를 처리 하는 옵션 이 있습니다. 따라서 ./myscript.sh변환을 포함 하는 사전 처리 스크립트를 가질 수 있습니다.

cut ... | awk '...' > $FILE

어디에서 $FILE생성 된 출력 파일이 있습니까 split(예 : xaa…). 또는 모든 임시 파일을 피하려면 단순히 단일 파일로 연결하십시오.

cut ... | awk '...' >> abridged.tsv

split그러나 이것을 사용하지 않는 것보다 빠를 것이라고 믿을 이유는 없습니다 .

“빅 데이터”처리 (및이 질문을 몇 년 동안 요청한지 몇 년이 지 났는지)를 수행하고 있다는 것을 고려하면이 30GB 파일을 hdfs에 복사하는 것 (또는 데이터를 저장하고 보관하는 것) original) 및 apache hive를 사용하여 원하는대로 데이터를 선택 / 형식화하십시오.