一种 IDE 的快速子串搜索算法,包含数万个非常大的文件

Fast substring search algorithm to be used by a sort of IDE with tens of thousands of very big files

我正在开发与 IDE 非常相似的东西,它将处理数万个非常大的(文本)文件,并且我正在调查该主题的最新技术水平。

例如,Intellij 的标准(非正则表达式)搜索算法非常直接。他们如何做到这一点?他们只是在内存中保留所有可搜索文件的某种后缀树吗?他们是否只是将文件内容的很大一部分保留在内存中,以便他们几乎完全在内存中执行标准 KMP 以避免任何磁盘 IO?

谢谢

你可以看看Apache Lucene。这是一个完全用 java 编写的文本搜索引擎库。它可能对您的使用来说有点太重了,但由于它是开源的,您可以看看它是如何工作的。

它有一个 demo 功能,可以引导您建立索引并搜索库源代码,这听起来与您想做的完全一样。

另外,看看 Boyer-Moore 字符串搜索算法。这 显然 通常用于提供 ctrl+f 样式文档搜索的应用程序。它涉及对搜索词进行预处理,以便 运行 尽可能少地进行比较。

正如 js441 指出的那样,Apache Lucene 是一个不错的选择,但前提是您要进行基于术语的搜索,类似于 google 的工作方式。如果您需要搜索跨越术语的任意字符串,Lucene 将无济于事。

在后一种情况下你是对的,你必须建立某种后缀树。构建后缀树后可以做的一个巧妙的技巧是将其写入文件并将其映射到内存 space。这样你就不会浪费内存来将整个树保存在 RAM 中,但你会经常访问树的部分自动缓存。 mmap 的缺点是初始搜索可能有点慢。如果您的文件经常更改,这也不会。

为了帮助搜索刚刚编辑过的文件,您可以保留两个索引,一个用于大部分文件,另一个仅用于最近编辑过的文件。因此,当您进行搜索时,您将在两个索引中进行搜索。您应该定期用新文件的内容重建永久索引并替换旧的。

以下是 Lucene 何时良好以及后缀树何时良好的一些示例:

假设您有一个包含以下内容的文档:

A quick brown dog has jumped over lazy fox.

Lucene 适用于以下搜索:

  • 快速棕色
  • q*
  • q* b

    通过一些技巧,您可以很好地进行以下搜索:

  • '*ick *own'

    这种类型的搜索 运行 非常慢

  • 'q*ick brown d*g'

    而且这种搜索永远找不到任何东西

  • "ick brown d"

    当您将文档视为词袋时,Lucene 也很不错。这样您就可以轻松地进行这样的搜索

  • 快狐

    无论中间是什么,它都会为您找到所有包含单词 quick 和 fox 的文档。

    另一方面,后缀树可以很好地搜索文档中子字符串的精确匹配,即使您的搜索跨越术语并且在术语的中间开始和结束时也是如此。

    描述了构造大型数组后缀树的非常好的算法here(Warnign 付费墙)。

目前,IntelliJ IDEA 对项目中的文件进行索引,并记住哪些 3-grams(3 个字母或数字的序列)出现在哪些文件中。搜索时,它也将查询拆分为 3-grams,从索引中获取包含所有这些 trigrams 的文件,将这些集合相交,并在每个文件中使用相对简单的文本搜索来检查它们是否真的包含整个搜索字符串.