열의 하위 문자열을 기반으로 대용량 파일의 중복 행만 저장하는 방법은 무엇입니까?

열의 하위 문자열을 기반으로 대용량 파일의 중복 행만 저장하는 방법은 무엇입니까?

두 번째 열에 반복되는 하위 문자열이 포함된 Linux 시스템에 거대한 파일(약 100Gb)이 있습니다. 예:

92957ea93f634985;02a2a09322bbbb2d894c;acfb4aa85f577db320d5a0701210238f 62be40ee38d3d62e;1f433e74c9498f051bca;4ad1905e8ff598e9ea5b71c0e48424d9 08356a4e6e5edc25;5d41a09322bbbb2d894c;d92ef5610121033f34dd881b4b910820 c5a2cd0c4e2191e3;83fdc9498f051bcab9e8;5bcb136cfd3326br9d1f52ce7537b901 1e3a1f877316966d;12ff3e74c9498f051bca;a9547b3db00e821bf5e8db900121038e 00c5a857928fbfaf;547b3db00e821b1604eh;11919d5616e4306x4a495118f52c41d4 92ea3e74c9498f04;8faca09322bbbb2d894c;10256a9ff1787f483db00e862119030a

다음과 같은 결과가 나올 것으로 예상됩니다.

92957ea93f634985;02a2a09322bbbb2d894c;acfb4aa85f577db320d5a0701210238f 62be40ee38d3d62e;1f433e74c9498f051bca;4ad1905e8ff598e9ea5b71c0e48424d9 08356a4e6e5edc25;5d41a09322bbbb2d894c;d92ef5610121033f34dd881b4b910820 1e3a1f877316966d;12ff3e74c9498f051bca;a9547b3db00e821bf5e8db900121038e 92ea3e74c9498f04;8faca09322bbbb2d894c;10256a9ff1787f483db00e862119030a

(행 순서는 중요하지 않습니다)

다음 코드를 사용하여 더 작은 테스트 파일을 만들어 보았습니다.

awk -F";" '!_[substr($2,5,16)]++' test.csv

하지만 첫 번째 항목만 표시되므로 모두 저장해야 합니다. 대용량 파일이기 때문에 메모리에 로딩한다는 솔루션을 사용할 수 없기 때문에 위의 코드는 좋지 않다고 생각합니다. 위에서 정의한 대로 열 2에 동일한 하위 문자열 값을 포함하는 행만 저장하면 되므로 도움을 주시면 감사하겠습니다.

편집: 실수를 했습니다. 위의 코드는 작동하지 않습니다. 잘못된 구분 기호를 입력했기 때문에 첫 번째 중복이 표시됩니다. 정확하다면 파일의 전체 내용이 표시됩니다.

답변1

테스트할 하위 문자열이 각 줄의 약 20%이고 파일이 100GB인 경우 일반적인 awk솔루션에는 최대 20GB의 메모리가 필요할 수 있습니다. 이 솔루션을 사용하려면 파일을 두 번 구문 분석해야 합니다(또는 모든 줄을 메모리에 저장해야 하며 이는 더 나쁩니다). 먼저 부분 문자열을 연관 배열에 저장하면서 발생 횟수를 세고 고유한 내용이 아닌 내용을 인쇄해야 합니다.

awk 'FNR==NR{seen[substr($0,22,16)]++; next} seen[substr($0,22,16)] > 1' file file

그러나 귀하의 경우에는 이 연관 배열이 메모리에 맞지 않을 수 있습니다.


유형

메모리를 다루는 솔루션의 경우 사용 sort가능한 메모리만 사용하고 필요한 경우 임시 파일을 사용하여 병합 정렬합니다. 조금 느릴 수도 있지만 메모리가 부족한 경우에도 수행할 수 있습니다.

LC_ALL=C sort -k1.22,1.37 file | uniq -D -s21 -w16

LC_ALL=C파일에 UTF-8이 아닌 멀티바이트 문자가 포함된 경우 해당 문자를 제거할 수 있으며, 그렇지 않은 경우 100GB의 여유 공간과 필요한 권한이 있는 위치를 가리키는 sort명령에 대해 다른 tmp 위치를 정의 해야 할 수도 있습니다. 100GB의 여유 공간이 없습니다(때로는 파티션이 작습니다).-T, --temporary-directory=DIR/tmp/

위 코드는 uniq처음 21자를 건너뛰고 그 뒤의 처음 16자를 테스트하여 고유성을 테스트합니다. -D중복된 줄만 인쇄됩니다. 마찬가지로 위 sort명령은 각 줄에 대해 동일한 고정 문자 범위를 테스트합니다.


중복된 하위 문자열 및 awk만 추출

데이터를 기반으로 이 솔루션을 시도하고 위의 아이디어를 결합하여 메모리에 맞추고 더 빠르게 시도해 볼 수 있습니다. 실제로 이것이 awk메모리에 적합한 솔루션입니다. 이 명령은 다음과 같습니다.

cut -c22-37 file | sort | uniq -d > subs.txt

파일의 지정된 고정 위치에서 두 번 이상 발생하는 부분 문자열을 추출합니다. 각각 한 번씩만 인쇄됩니다 subs.txt. 고유 값이 제외되었기 때문에 의 크기는 subs.txt첫 번째 솔루션의 연관 배열 크기보다 작습니다.

이제 subs.txt크기가 충분히 작고 메모리에 맞는 경우(반복 빈도에 따라 다름) 파일을 한 번만 구문 분석할 수 있습니다.

awk 'FNR==NR{seen[$0]; next} (substr($0,22,16) in seen)' subs.txt file >> output

또는 이 파일을 N개의 부분으로 분할하고 split -l위 명령을 사용 및 실행하여 파일을 N번 구문 분석하고 매번 동일한 출력 파일에 추가할 수 있습니다. 크기에 따라 subs.txt1~2단계로 할 수 있다면 전체 분류 솔루션보다 더 빠를 것이라고 생각합니다.

관련 정보