여러 파일에 여러 키워드를 Grep: 속도 향상

여러 파일에 여러 키워드를 Grep: 속도 향상

현재 grep을 사용하는 동안 "성능 문제"에 직면하고 있습니다. 나는 많은(Linux 커널 저장소 크기를 생각해 보세요) 파일에서 많은(10,000개 이상의) 키워드가 나타나는 것을 찾으려고 노력하고 있습니다. 목표는 각 키워드에 대해 한 종류의 색인을 생성하는 것입니다.

keyword: my_keyword
filepath 1
filepath 2
------
keyword: my_keyword2
...

저는 쉘 스크립팅을 처음 접했기 때문에 다음과 같은 간단한 것을 시도했습니다.

while read LINE; do
    echo "keyword: "$LINE >> $OUTPUT_FILE
    grep -E -r --include='Makefile*' "($LINE)" . >> "$OUTPUT_FILE"
    echo "-----"
done < $KEYWORD_FILE

이 작업을 완료하고 원하는 결과를 얻는 데 약 45분이 소요됩니다.

참고: 내가 검색하는 모든 키워드는 하나의 파일("KEYWORD_FILE"이므로 시작하기 전에 수정됨)에 있으며 검색을 시작하기 전에 검색할 파일을 결정할 수 있습니다. 검색하기 전에 검색할 파일 목록을 다음과 같이 저장해 보았습니다.

file_set=( $(find . -name "Kbuild*" -o -name "Makefile*") )

그런 다음 grep 호출을 다음으로 바꾸십시오.

echo {$file_set[*]} | parallel -k -j+0 -n 1000 -m grep -H -l -w "\($LINE\)" >> "$OUTPUT_FILE"

완료하는데 약 1시간 정도 소요됩니다...

질문: sh 사양을 준수하는 한 원하는 기술을 사용할 수 있다는 점을 고려하면 이 작업을 어떻게 "더 빠르게" 및/또는 더 효율적으로 수행할 수 있습니까?

어쩌면 grep사용된 도구가 아니고 제가 parallel잘못 사용하고 있는 것일 수도 있습니다... 어떤 아이디어든 환영합니다!

답변1

목표는 각 키워드에 대해 한 종류의 색인을 생성하는 것입니다.

그런 다음 grep 대신 인덱싱 소프트웨어를 사용하십시오. 나는 그것을 사용하여 큰 성공을 거두었습니다.코드 검색전반적인CPAN파일.

답변2

나는 10,000개의 키워드를 집어삼키고, 각 파일을 읽고, 각 줄에서 그 중 일부가 일치하는지 확인하는 Perl 스크립트(예, 현재 Python이 더 인기가 있다는 것을 알고 있습니다...)를 작성하겠습니다. 일치하는 항목이 있으면 키 아래에 파일/라인으로 저장합니다(여기서는 해싱이 제대로 작동함). 그룹 완성 후 해시를 확인하여 각 키워드에 대한 결과를 출력합니다.

Perl(및 Python)은 (반)컴파일된 언어이고, 스크립트는 내부 표현(매우 컴팩트하고 빠르게 해석하기 쉬움)으로 컴파일되며 이 내부 형식은 (일부) "최적화 프로그램"에서 선호됩니다. 속도는 직접 최적화한 C와 같지는 않지만 10배 느려서는 안 됩니다.

마지막으로 위의 귀하의 의견은 다음과 같습니다.당신의시간(작성, 디버깅 또는 얻기, 구축, 사용 방법 학습)은많은기계 시간보다 더 가치가 있습니다(밤새도록 놔두면 오후 10시나 오전 6시에 끝나더라도 누가 신경쓰겠습니까...).

답변3

grep에 -f 및 -F 스위치를 사용하면 작업 속도가 빨라질 수 있습니다. 그렙 캔꽤 똑똑하다여러 패턴 일치 처리에 관해

목표는 각 키워드에 대한 색인을 생성하는 것입니다.

그렇다면 해결책은 검색 엔진(예: mnogo)일까요?

답변4

나는 다음을 생각했습니다.

  1. 각 키워드에 대해 각 파일을 한 번 심각하게 grep할 수는 없습니다. 그런 다음 -l / --files-with-matches각 파일이 끝날 때까지 쓸데없이 grep할 수는 없습니다. 불행하게도 (내가 아는 한) 여러 모드의 조합은 없습니다 --files-with-matches(적어도 필요한 방식은 아닙니다). 이는 awk에서 수행할 수 있습니다. awk는 재귀적으로(AFAIK) 호출할 수 없지만 많은 수의 파일에 대해 찾기를 통해 호출할 수 있습니다.
  2. 내 경험에 따르면 먼저 find를 사용하여 트리를 탐색하면 많은 파일(또는 해당 인덱스 노드)에 액세스하는 속도가 크게 빨라질 수 있습니다. 디렉토리 항목과 inode가 블록 단위로 읽히고 메타데이터가 캐시되므로 디스크 헤드 이동이 크게 줄어들 것이라고 생각합니다. find가 전체 경로를 인쇄하도록 하지 마십시오. -printf .그것으로 충분합니다. 출력을 /dev/null에 쓰십시오.
  3. 가장 빠른 해결책은 셸 도구에 의존하지 않고 컴파일되는 항목(예: JIT가 포함된 Python(편집: ))을 작성하는 것입니다. 이렇게 하면 I/O(--files-with-matches 구현) 및 CPU(아직 일치하지 않은 키워드에 대해 모든 행을 테스트)를 최적화하고 동시에 각 인덱스 파일에 파일 경로를 추가할 수 있습니다(tmpfs?). ; 각 키워드에 대해 하나의 FD를 예약합니다(키워드가 1000개 미만이라고 가정). 그런 다음 파일을 연결하기만 하면 됩니다. 조회형 캐시도 이 방법으로 최적화할 수 있습니다. 먼저 일치하는 파일 이름이 1000개가 될 때까지 파일 이름을 읽은 다음 해당 inode(stat() 파일)를 읽은 다음 파일을 검색하고 다음 1000개 이름 가져오기를 읽습니다.

관련 정보