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
在沒有索引的冷檔案系統上正常搜尋需要 1.02 秒,卸載drive
並再次掛載以清除 FS 快取以記錄索引的效果:
$ 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
相較之下,使用索引,在卸載drive
並再次掛載以清除 FS 快取以記錄索引的效果後,使用 ugrep 搜尋冷檔系統只需 0.0487 秒,速度提高了 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 秒,產生的搜尋時間範圍為 0.0487(21 倍加速)到 0.0983 秒(10 倍加速)。
與這個小型演示相比,速度的提升通常會明顯更高,具體取決於幾個因素:索引文件的大小、文件系統的讀取速度以及假設大多數文件是冷的。
我設計的索引演算法被證明是單調的:更高的精度透過降低誤報率來保證提高搜尋效能,但也增加了索引儲存開銷。同樣,較低的精度會降低搜尋效能,但也會減少索引儲存開銷。因此,我將我的索引器命名為單調索引器。
如果檔案儲存空間非常寶貴,那麼我們可以透過指定較低的索引精度來降低索引儲存開銷。
使用等級 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
在此範例中,索引搜尋仍然比非索引搜尋快 12 倍,實際搜尋了 16 個檔案(15 個誤報):
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
),對於使用適度複雜性的正規表示式模式進行搜尋來說,它往往非常有效。
一句警告。檢查索引總是會產生一點點開銷。這意味著,如果所有文件都已快取在 RAM 中,因為最近搜尋或讀取了文件,那麼索引顯然不一定會加快搜尋速度。在這種情況下,非索引搜尋可能會更快。此外,基於索引的搜尋啟動時間較長。當使用必須轉換為雜湊表的 Unicode 字元類別和通配符時,啟動時間會增加。
總而言之,當搜尋大量冷文件並且正則表達式模式不匹配太多時,基於索引的搜尋是最有效的,即我們希望限制無限重複*
和+
的使用,並限制 Unicode 字元類的使用可能的。這減少了 ugrep 啟動時間並限制了誤報模式匹配的比率(另請參閱下面的問答)。
遞歸地增量索引所有顯示進度的非二進位檔案:
ugrep-indexer -I -v
遞歸地增量索引所有非二進位文件,包括儲存在存檔和壓縮檔案中的非二進位文件,顯示進度:
ugrep-indexer -z -I -v
增量索引所有非二進位文件,包括存檔和壓縮文件,顯示進度,追蹤文件的符號連結(但不追蹤目錄),但不索引與 .gitignore 中的 glob 匹配的文件和目錄:
ugrep-indexer -z -I -v -S -X
強制重新索引所有非二進位檔案(包括存檔和壓縮檔案),遵循檔案的符號連結(但不是目錄),但不索引與 .gitignore 中的 glob 相符的檔案和目錄:
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
新增一個選項來建立一個索引文件,例如明確指定為ugrep。如果索引檔案位於快速檔案系統上,這可以進一步提高索引搜尋速度。否則,不要期望有太大的改進,甚至可能會減慢,因為無法同時搜尋單個索引文件,並且實際上會跳過目錄(也跳過它們的索引),並且會檢查更多索引條目。實驗會告訴你答案。這種方法的一個重要警告是,使用ugrep --index
基於索引的搜尋不再安全:尚未建立索引的新檔案和修改後的檔案將不會被搜尋。
每個 N-gram 布隆過濾器在哈希表中都有自己的“位元層”,以避免哈希衝突。例如,2-gram 不與 3-gram 共用任何位元。這確保了我們永遠不會出現任何誤報,即錯誤匹配實際上不屬於模式的字元。然而,1-gram(單一字元)位元空間很小(最多 256 位元)。因此,當哈希表較大時,我們會浪費一些位元。減少浪費的一種可能方法是將 1-gram 與 2-gram 組合起來共享相同的位元空間。如果我們認為 1-gram 等於 2-gram,而第二個字元設定為