ugrep-indexerユーティリティは、再帰的にファイルのインデックスを作成し、再帰的な grep を高速化します。
また、コマンドライン オプションで指定すると、アーカイブおよび圧縮ファイルの内容にインデックスが付けられます。これにより、指定されたパターンに一致するコンテンツがない場合に、それらを検索する必要がなくなります。
ugrep は、インデックスベースの検索をサポートする grep 互換の高速ファイル検索ツールです。インデックス ベースの検索は、遅いファイル システムやファイル システムのキャッシュが効果的でない場合に大幅に高速化されます。検索対象のドライブ上のファイル システムが RAM にキャッシュされていない、つまり「コールド」な場合、インデックスを作成すると検索が高速化されます。ファイルのインデックスを使用して、指定された正規表現パターンに一致する可能性のあるファイルのみを検索します。このインデックスにより、一致する可能性があるかどうかを簡単にチェックできるため、すべてのファイルを検索する必要がなくなります。
ugrep を使用したインデックスベースの検索は安全であり、一致する可能性のある更新されたファイルをスキップすることはありません。インデックス作成後にファイルやディレクトリが追加または変更された場合、検索ではファイルおよびディレクトリのタイムスタンプとインデックス作成のタイムスタンプを比較することにより、ファイル システムに加えられたこれらの追加や変更が常に検索されます。
インデックス作成後に多くのファイルが追加または変更された場合、インデックスを最新の状態にするために再インデックスが必要になる場合があります。再インデックス作成は増分であるため、最初のインデックス作成プロセスほど時間はかかりません。
インデックスベースの検索の典型的かつ小規模な例です。たとえば、別のドライブに配置された ugrep v3.12.6 リポジトリ上での検索です。
$ cd drive/ugrep
$ ugrep-indexer -I
12247077 bytes scanned and indexed with 19% noise on average
1317 files indexed in 28 directories
28 new directories indexed
1317 new files indexed
0 modified files indexed
0 deleted files removed from indexes
128 binary files ignored with --ignore-binary
0 symbolic links skipped
0 devices skipped
5605227 bytes indexing storage increase at 4256 bytes/file
インデックス作成を行わないコールド ファイル システムでの通常の検索には、 drive
をアンマウントし、再度マウントして FS キャッシュをクリアしてインデックス作成の効果を記録した後、1.02 秒かかります。
$ ugrep -I -l 'std::chrono' --stats
src/ugrep.cpp
Searched 1317 files in 28 directories in 1.02 seconds with 8 threads: 1 matching (0.07593%)
Ripgrep 13.0.0 では、同じコールド検索で 1.18 秒かかり、さらに時間がかかります (ripgrep はデフォルトでバイナリ ファイルをスキップするため、オプション-I
は指定されていません)。
$ time rg -l 'std::chrono'
src/ugrep.cpp
1.18 real 0.01 user 0.06 sys
対照的に、インデックス作成では、コールド ファイル システムの検索に ugrep を使用すると 0.0487 秒しかかかりません。これは、 drive
をアンマウントし、再度マウントして FS キャッシュをクリアしてインデックス作成の効果を記録した後、21 倍高速になります。
$ ugrep --index -I -l 'std::chrono' --stats
src/ugrep.cpp
Searched 1317 files in 28 directories in 0.0487 seconds with 8 threads: 1 matching (0.07593%)
Skipped 1316 of 1317 files with non-matching indexes
経過時間には常にある程度のばらつきがあり、検索時間の範囲が 0.0487 (21 倍の高速化) ~ 0.0983 秒 (10 倍の高速化) となった 4 回の検索実行の最良時間は 0.0487 秒です。
いくつかの要因、インデックス付けされたファイルのサイズ、ファイル システムの読み取り速度、およびほとんどのファイルがコールドであるとの仮定に応じて、この小規模なデモと比較して速度の向上は一般的に大幅に高くなる可能性があります。
私が設計したインデックス作成アルゴリズムはおそらく単調です。精度が高くなると、誤検知率が減り、検索パフォーマンスの向上が保証されますが、インデックス ストレージのオーバーヘッドも増加します。同様に、精度が低いと検索パフォーマンスが低下しますが、インデックス ストレージのオーバーヘッドも軽減されます。したがって、インデクサーをmonotonic インデクサーと名付けました。
ファイル ストレージ スペースが貴重な場合は、より低いインデックス作成精度を指定することで、インデックス ストレージのオーバーヘッドを減らすことができます。
レベル 0 (オプション-0
) で上記の例にインデックスを付けると、インデックス作成ストレージのオーバーヘッドが 8.6 倍減少し、ファイルあたり 4256 バイトからファイルあたりわずか 490 バイトに減少します。
12247077 bytes scanned and indexed with 42% noise on average
1317 files indexed in 28 directories
0 new directories indexed
1317 new files indexed
0 modified files indexed
0 deleted files removed from indexes
128 binary files ignored with --ignore-binary
0 symbolic links skipped
0 devices skipped
646123 bytes indexing storage increase at 490 bytes/file
この例では、実際に 16 個のファイルが検索されました (15 個の誤検知) ため、インデックス付き検索はインデックスなしの検索よりも 12 倍高速です。
Searched 1317 files in 28 directories in 0.0722 seconds with 8 threads: 1 matching (0.07593%)
Skipped 1301 of 1317 files with non-matching indexes
この例よりも複雑な正規表現パターンでは、自然に誤検知率が高くなる可能性があります。これは、一致しないにもかかわらず、一致する可能性があるとみなされるファイルの割合です。誤検知率が大きくなり影響がある場合、誤検知率が高くなると検索速度が低下する可能性があります。
次の表は、インデックス作成の精度がインデックス作成ストレージとインデックス付けされたファイルごとの平均ノイズにどのような影響を与えるかを示しています。右端の列は、 ugrep --index -I -l 'std::chrono'
の検索速度と誤検知率を示しています。
準拠 | インデックスストレージ (KB) | 平均ノイズ | 誤検知 | 検索時間(秒) |
---|---|---|---|---|
-0 | 631 | 42% | 15 | 0.0722 |
-1 | 1276 | 39% | 1 | 0.0506 |
-2 | 1576年 | 36% | 0 | 0.0487 |
-3 | 2692 | 31% | 0 | ウンチ |
-4 | 2966 | 28% | 0 | ウンチ |
-5 | 4953 | 23% | 0 | ウンチ |
-6 | 5474 | 19% | 0 | ウンチ |
-7 | 9513 | 15% | 0 | ウンチ |
-8 | 10889 | 11% | 0 | ウンチ |
-9 | 13388 | 7% | 0 | ウンチ |
指定された正規表現が、たとえばugrep --index -I -l '(todo|TODO)[: ]'
の検索で、より多くの考えられるパターンに一致する場合、検索された 1317 ファイルの中で誤検知の割合が高くなる可能性があります。その結果、検索時間がわずかに長くなります。
準拠 | 誤検知 | 検索時間(秒) |
---|---|---|
-0 | 189 | 0.292 |
-1 | 69 | 0.122 |
-2 | 43 | 0.103 |
-3 | 19 | 0.101 |
-4 | 16 | 0.097 |
-5 | 2 | 0.096 |
-6 | 1 | ウンチ |
-7 | 0 | ウンチ |
-8 | 0 | ウンチ |
-9 | 0 | ウンチ |
精度-4
がデフォルトです (以前のリリースでは-5
でした)。これは、それほど複雑でない正規表現パターンでの検索に非常にうまく機能する傾向があります。
注意点が 1 つあります。インデックスをチェックするには、常にわずかなオーバーヘッドが発生します。これは、ファイルが最近検索または読み取られたため、すべてのファイルがすでに RAM にキャッシュされている場合、明らかに、インデックス作成によって検索が高速化される必要はないことを意味します。その場合、インデックスを付けない検索の方が高速になる可能性があります。さらに、インデックスベースの検索は起動時間が長くなります。ハッシュ テーブルに変換する必要がある Unicode 文字クラスとワイルドカードが使用されている場合、この起動時間は長くなります。
要約すると、インデックス ベースの検索は、大量のコールド ファイルを検索する場合や、正規表現パターンがあまり一致しない場合に最も効果的です。つまり、無制限の繰り返し*
と+
の使用を制限し、Unicode 文字クラスの使用を制限したい場合です。可能。これにより、ugrep の起動時間が短縮され、誤検知パターンの一致率が制限されます (以下の Q&A も参照)。
すべての非バイナリ ファイルに再帰的かつ増分的にインデックスを作成し、進行状況を表示します。
ugrep-indexer -I -v
アーカイブや圧縮ファイルに保存されている非バイナリ ファイルを含む、すべての非バイナリ ファイルを再帰的かつ増分的にインデックス付けし、進行状況を表示します。
ugrep-indexer -z -I -v
アーカイブや圧縮ファイルを含むすべての非バイナリ ファイルの増分インデックスを作成し、進行状況を表示し、ファイルへのシンボリック リンクをたどります (ただし、ディレクトリへのシンボリック リンクはたどりません)。ただし、.gitignore 内のグロブに一致するファイルとディレクトリのインデックスは作成しません。
ugrep-indexer -z -I -v -S -X
アーカイブや圧縮ファイルを含むすべての非バイナリ ファイルのインデックスの再作成を強制的に行い、ファイルへのシンボリック リンクをたどりますが (ディレクトリへのリンクではありません)、.gitignore 内のグロブに一致するファイルとディレクトリのインデックスは作成しません。
ugrep-indexer -f -z -I -v -S -X
同じですが、インデックス作成の精度を 5 (デフォルト) から 0 に下げることで、インデックス ファイルのストレージを最小限に抑えます。
ugrep-indexer -f -0 -z -I -v -S -X
インデックス ファイルのサイズが大きくなりますが、インデックス作成の精度を 5 (デフォルト) から 7 に増やすことで、検索パフォーマンスを向上させます。
ugrep-indexer -f7zIvSX
すべての非表示の._UG#_Store
インデックス ファイルを再帰的に削除して、ディレクトリ ツリーをインデックスなしの状態に復元します。
ugrep-indexer -d
以下を使用して構成およびコンパイルします。
./build.sh
必須ではないが必要な場合は、次のようにインストールします。
sudo make install
1 つのインデックス ファイルを作成するオプションを追加します。たとえば、ugrep に明示的に指定します。これにより、インデックス ファイルが高速なファイル システム上にある場合、インデックス付きの検索速度がさらに向上する可能性があります。それ以外の場合は、単一のインデックス ファイルを同時に検索することができず、実際にディレクトリがスキップされる (インデックスもスキップする) ときにさらに多くのインデックス エントリがチェックされるため、大きな改善は期待できず、場合によっては速度が低下する可能性もあります。実験すれば分かるだろう。このアプローチの重要な注意点は、 ugrep --index
を使用したインデックス ベースの検索が安全ではなくなっていることです。インデックスが作成されていない新しいファイルや変更されたファイルは検索されません。
各 N-gram ブルーム フィルターには、ハッシュの競合を避けるためにハッシュ テーブル内に独自の「ビット層」があります。たとえば、2 グラムは 3 グラムとビットを共有しません。これにより、実際にはパターンの一部ではない文字が誤って一致するという誤検知が発生することがなくなります。ただし、1 グラム (単一文字) のビット空間は小さい (最大 256 ビット)。したがって、ハッシュ テーブルが大きい場合、一部のビットが無駄になります。無駄を減らすために考えられるアプローチは、1 グラムと 2 グラムを組み合わせて同じビット空間を共有することです。これは、2 番目の文字が