거대한 파일에서 많은 패턴을 가져 오기 Andres Smith student 7836472098652

나는 하루에 약 20 만 줄씩 성장하는 파일을 가지고 있으며 모두 3 줄의 블록으로 구성됩니다.

1358726575123       # key
    Joseph Muller   # name
    carpenter       # job
9973834728345
    Andres Smith
    student
7836472098652
    Mariah Anthony
    dentist

이제 약 10,000 개의 키 패턴을 추출하는 다른 파일이 있습니다 1358726575123. 그런 다음 for이 패턴 으로 루프를 실행 하고 첫 번째 파일과 비교하여 확인해야합니다. 파일에 이러한 패턴이 없으면 추가 처리를 위해 패턴을 세 번째 파일에 저장합니다.

for number in $(grep -o '[0-9]\{12\}' file2); do  # finds about 10.000 keys
     if ! grep -q ^$number$ file1; then           # file1 is a huge file
         printf "$number\n" >>file3               # we'll process file3 later
     fi
done

예제 코드는 거대한 파일을 10,000 번 그 리핑하며 하루 종일 1 분한 번씩 이 루프를 실행합니다 .

거대한 파일이 계속 커지므로이 모든 작업을 더 빠르게 수행하고 CPU를 절약하려면 어떻게해야합니까? 어떻게 든 키를 기준으로 파일을 정렬하거나 (그렇다면 어떻게?) 일반 텍스트 대신 db를 사용하는 것이 도움이 될지 궁금합니다 …



답변

이 답변은 potongawk 에 의해 게시 된 답변을 기반으로합니다 . 메인 파일 의 동일한 6 백만 줄10,000 개의 키에 대해 (내 시스템의) 방법
보다 두 배 빠릅니다 … (현재 FNR을 사용하도록 업데이트되었습니다. NR)
comm

하지만이 awk빠르게 현재의 시스템보다, 그리고, 당신과 당신의 컴퓨터 (들에게) 몇 가지 호흡 공간을 제공 당신이 설명한대로 데이터 처리와 같은 강렬한 때, 당신은 전용 데이터베이스로 전환하여 최적의 전체 결과를 얻을 것을 알고있을 것이다; 예. SQlite, MySQL …


awk '{ if (/^[^0-9]/) { next }              # Skip lines which do not hold key values
       if (FNR==NR) { main[$0]=1 }          # Process keys from file "mainfile"
       else if (main[$0]==0) { keys[$0]=1 } # Process keys from file "keys"
     } END { for(key in keys) print key }' \
       "mainfile" "keys" >"keys.not-in-main"

# For 6 million lines in "mainfile" and 10 thousand keys in "keys"

# The awk  method
# time:
#   real    0m14.495s
#   user    0m14.457s
#   sys     0m0.044s

# The comm  method
# time:
#   real    0m27.976s
#   user    0m28.046s
#   sys     0m0.104s


답변

물론 문제는 큰 파일에서 grep을 10,000 번 실행한다는 것입니다. 두 파일을 한 번만 읽어야합니다. 스크립팅 언어 외부에 머 무르려면 다음과 같이하십시오.

  1. 파일 1에서 모든 숫자를 추출하여 정렬
  2. 파일 2에서 모든 숫자를 추출하여 정렬
  3. comm정렬 된 목록에서 실행 하여 두 번째 목록에만있는 것을 얻으십시오.

이 같은:

$ grep -o '^[0-9]\{12\}$' file1 | sort -u -o file1.sorted
$ grep -o  '[0-9]\{12\}'  file2 | sort -u -o file2.sorted
$ comm -13 file1.sorted file2.sorted > file3

참조하십시오 man comm.

매일 큰 파일 (예 : 로그 파일)을자를 수 있다면 정렬 된 숫자의 캐시를 유지할 수 있으며 매번 파싱 할 필요가 없습니다.


답변

예, 확실히 데이터베이스를 사용하십시오. 그들은 이와 같은 작업을 위해 정확하게 만들어졌습니다.


답변

이것은 당신을 위해 일할 수 있습니다 :

 awk '/^[0-9]/{a[$0]++}END{for(x in a)if(a[x]==1)print x}' file{1,2} >file3

편집하다:

두 파일 모두에서 복제본과 알 수없는 키를 허용하도록 수정 된 스크립트는 여전히 두 번째 파일에없는 첫 번째 파일에서 키를 생성합니다.

 awk '/^[0-9]/{if(FNR==NR){a[$0]=1;next};if($0 in a){a[$0]=2}}END{for(x in a)if(a[x]==1)print x}' file{1,2} >file3


답변

많은 양의 데이터를 사용하면 실제로 데이터베이스로 전환해야합니다. 그 동안 적절한 성능을 발휘하기 위해해야 ​​할 한 가지는 file1각 키를 개별적 으로 검색하지 않는 것 입니다. 하나 grep를 실행하여 모든 제외되지 않은 키를 한 번에 추출하십시오. grep키가 포함되지 않은 행도 반환 하므로 해당 행을 필터링하십시오.

grep -o '[0-9]\{12\}' file2 |
grep -Fxv -f - file1 |
grep -vx '[0-9]\{12\}' >file3

( -Fx문자 그대로 전체 행을 검색하는 것을 의미합니다. -f -표준 입력에서 패턴 목록을 읽는 것을 의미합니다.)


답변

다른 사람들이 “데이터베이스에 데려다주십시오!”라고 말한 것을 강화하도록 허락하십시오.

대부분의 플랫폼에서 무료로 사용할 수 있는 MySQL 바이너리가 있습니다.

왜 SQLite가 아닌가? 메모리 기반이며 플랫 파일을 시작할 때로드 한 다음 완료되면 닫습니다. 이것은 컴퓨터가 고장 나거나 SQLite 프로세스가 사라지면 모든 데이터도 마찬가지라는 것을 의미합니다.

문제는 몇 줄의 SQL처럼 보이고 밀리 초 단위로 실행됩니다!

MySQL을 설치 한 후 (다른 선택을 권장합니다) Anthony Molinaro 의 O’Reilly의 SQL Cookbook 에 대해 40 달러를 깎았습니다 SELECT * FROM table.


답변

이것이 당신이 찾고있는 정확한 결과인지 확실하지 않지만 아마도 가장 쉬운 방법은 다음과 같습니다.

grep -o '[0-9]\{12\}' file2 | sed 's/.*/^&$/' > /tmp/numpatterns.grep
grep -vf /tmp/numpatterns.grep file1 > file3
rm -f /tmp/numpatterns.grep

다음을 사용할 수도 있습니다.

sed -ne '/.*\([0-9]\{12\}.*/^\1$/p' file2 > /tmp/numpatterns.grep
grep -vf /tmp/numpatterns.grep file1 > file3
rm -f /tmp/numpatterns.grep

이들 각각은 큰 파일 ( file1) 에서 숫자를 수집하는 데 사용되는 임시 패턴 파일을 만듭니다 .