我正在开发一种类似于IDE的东西,它可以处理成千上万个非常大的(文本)文件,并且我正在调查该主题的最新技术水平。
作为一个例子,Intellij的标准(非正则表达式)表达式的搜索算法非常直接。他们是如何做到这一点的?他们只是在内存中保留所有可搜索文件的某种后缀树吗?他们只是将文件内容的很大一部分保存在内存中,这样他们只需要几乎完全在内存中使用标准KMP来避免任何磁盘IO吗?
由于
答案 0 :(得分:9)
目前,IntelliJ IDEA索引项目中的文件,并记住哪些文件中出现了3克(3个字母或数字的序列)。搜索时,它将查询分成3-gram,从索引中获取包含所有三元组的文件,与这些集合相交,并在每个文件中使用相对简单的文本搜索来检查它们是否真的包含整个搜索字符串。
答案 1 :(得分:1)
您可以查看Apache Lucene。它是一个完全用java编写的文本搜索引擎库。它可能对您的使用来说有点太重,但由于它是开源的,您可以看看它是如何工作的。
它有一个demo,可以引导您构建索引并搜索库源代码,这听起来与您想要的完全一样。
另外,请查看Boyer-Moore字符串搜索算法。这显然 常用于提供ctrl + f样式文档搜索的应用程序中。它涉及预处理搜索项,以便尽可能少地进行比较。
答案 2 :(得分:0)
正如js441所指出的,Apache Lucene是一个不错的选择,但前提是您要进行基于术语的搜索,类似于Google的工作方式。如果您需要搜索跨越术语的任意字符串,Lucene将无法帮助您。
在后一种情况下,你是对的,你必须构建某种后缀树。在构建后缀树之后,您可以做的一个巧妙的技巧是将其写入文件并将其映射到内存空间。这样您就不会浪费内存来将整个树保存在RAM中,但是您将经常访问树的部分自动缓存。 mmap的缺点是初始搜索可能有点慢。如果您的文件经常更改,也不会这样。
为了帮助搜索刚编辑过的文件,您可以保留两个索引,一个用于大量文件,另一个用于最近编辑的文件。因此,当您进行搜索时,您将在两个索引中进行搜索。您应该定期使用新文件的内容重建永久索引并替换旧文件。
这里有一些Lucene好的时候和后缀树好的例子:
假设您有一个包含以下内容的文档:
一只快速的棕色狗跳过了懒惰的狐狸。
Lucene适合以下搜索:
q * b
通过一些技巧,您可以使以下搜索工作正常:
' * ick *拥有'
此类搜索的运行速度非常慢
' q * ick brown d * g'
此类搜索将永远找不到任何内容
" ick brown d"
当你将文件视为文字袋时,Lucene也很好。所以你可以轻松地进行这样的搜索
快狐
无论中间是什么,都会找到所有包含快速和狐狸文字的文件。
另一方面,后缀树可以很好地搜索文档中子字符串的精确匹配,即使在搜索范围跨越术语并且在术语中间开始和结束时也是如此。
描述了构建大型数组后缀树的非常好的算法here(Warnign paywalled)。