현재 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
답변2
나는 10,000개의 키워드를 집어삼키고, 각 파일을 읽고, 각 줄에서 그 중 일부가 일치하는지 확인하는 Perl 스크립트(예, 현재 Python이 더 인기가 있다는 것을 알고 있습니다...)를 작성하겠습니다. 일치하는 항목이 있으면 키 아래에 파일/라인으로 저장합니다(여기서는 해싱이 제대로 작동함). 그룹 완성 후 해시를 확인하여 각 키워드에 대한 결과를 출력합니다.
Perl(및 Python)은 (반)컴파일된 언어이고, 스크립트는 내부 표현(매우 컴팩트하고 빠르게 해석하기 쉬움)으로 컴파일되며 이 내부 형식은 (일부) "최적화 프로그램"에서 선호됩니다. 속도는 직접 최적화한 C와 같지는 않지만 10배 느려서는 안 됩니다.
마지막으로 위의 귀하의 의견은 다음과 같습니다.당신의시간(작성, 디버깅 또는 얻기, 구축, 사용 방법 학습)은많은기계 시간보다 더 가치가 있습니다(밤새도록 놔두면 오후 10시나 오전 6시에 끝나더라도 누가 신경쓰겠습니까...).
답변3
grep에 -f 및 -F 스위치를 사용하면 작업 속도가 빨라질 수 있습니다. 그렙 캔꽤 똑똑하다여러 패턴 일치 처리에 관해
목표는 각 키워드에 대한 색인을 생성하는 것입니다.
그렇다면 해결책은 검색 엔진(예: mnogo)일까요?
답변4
나는 다음을 생각했습니다.
- 각 키워드에 대해 각 파일을 한 번 심각하게 grep할 수는 없습니다. 그런 다음
-l / --files-with-matches
각 파일이 끝날 때까지 쓸데없이 grep할 수는 없습니다. 불행하게도 (내가 아는 한) 여러 모드의 조합은 없습니다--files-with-matches
(적어도 필요한 방식은 아닙니다). 이는 awk에서 수행할 수 있습니다. awk는 재귀적으로(AFAIK) 호출할 수 없지만 많은 수의 파일에 대해 찾기를 통해 호출할 수 있습니다. - 내 경험에 따르면 먼저 find를 사용하여 트리를 탐색하면 많은 파일(또는 해당 인덱스 노드)에 액세스하는 속도가 크게 빨라질 수 있습니다. 디렉토리 항목과 inode가 블록 단위로 읽히고 메타데이터가 캐시되므로 디스크 헤드 이동이 크게 줄어들 것이라고 생각합니다. find가 전체 경로를 인쇄하도록 하지 마십시오.
-printf .
그것으로 충분합니다. 출력을 /dev/null에 쓰십시오. - 가장 빠른 해결책은 셸 도구에 의존하지 않고 컴파일되는 항목(예: JIT가 포함된 Python(편집: ))을 작성하는 것입니다. 이렇게 하면 I/O(--files-with-matches 구현) 및 CPU(아직 일치하지 않은 키워드에 대해 모든 행을 테스트)를 최적화하고 동시에 각 인덱스 파일에 파일 경로를 추가할 수 있습니다(tmpfs?). ; 각 키워드에 대해 하나의 FD를 예약합니다(키워드가 1000개 미만이라고 가정). 그런 다음 파일을 연결하기만 하면 됩니다. 조회형 캐시도 이 방법으로 최적화할 수 있습니다. 먼저 일치하는 파일 이름이 1000개가 될 때까지 파일 이름을 읽은 다음 해당 inode(stat() 파일)를 읽은 다음 파일을 검색하고 다음 1000개 이름 가져오기를 읽습니다.