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,且第二个字符设置为