複数のファイルに複数のキーワードを Grep: スピードアップ

複数のファイルに複数のキーワードを Grep: スピードアップ

現在、grepの使用中に「パフォーマンスの問題」に直面しています。私は多くの(Linuxカーネルリポジトリのサイズを考えてみてください)ファイルに多くの(10,000を超える)キーワードが表示されることを見つけようとしています。目標は、キーワードごとに1種類のインデックスを作成することです。

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分かかります。

注:私が検索するすべてのキーワードは1つのファイル(「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

目標は、キーワードごとに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?)。 ;各キーワードに対して1つのFDを予約します(キーワードが1000個未満であると仮定)。その後、ファイルをリンクするだけです。ルックアップキャッシュもこの方法で最適化できます。まず、一致するファイル名が1000個になるまでファイル名を読み、次に対応するinode(stat()ファイル)を読み、次にファイルを検索してから1000個の名前のインポートを読みます。

関連情報