如何有效地搜索大型数据集的子串?

时间:2012-08-02 17:38:10

标签: database algorithm data-structures lucene

我有一大堆短字符串。有哪些算法和索引策略可以过滤包含子字符串的项目上的列表?例如,假设我有一个列表:

val words = List(
  "pick",
  "prepick",
  "picks",
  "picking",
  "kingly"
  ...
)

我怎样才能找到包含子串“king”的字符串?我可以像这样强行解决这个问题:

words.filter(_.indexOf("king") != -1) // yields List("picking", "kingly")

这仅适用于小型套装;今天我需要支持1000万个字符串,未来的目标是数十亿。显然我需要建立一个索引。 什么样的索引?

我已经看过使用存储在MySQL中的ngram索引,但我不确定这是否是最好的方法。当搜索字符串长于ngram大小时,我不确定如何以最佳方式查询索引。

我还考虑过使用Lucene,但这是围绕令牌匹配进行优化的,而不是子串匹配,并且似乎不支持简单子串匹配的要求。 Lucene确实有一些与ngrams相关的类(org.apache.lucene.analysis.ngram.NGramTokenFilter就是一个例子),但这些类似乎是用于拼写检查和自动完成用例,而不是子字符串匹配,文档很薄。

我应该考虑哪些其他算法和索引策略?有没有支持这个的开源库?可以使SQL或Lucene策略(上面)工作吗?

另一种说明要求的方法是使用SQL:

SELECT word FROM words WHERE word LIKE CONCAT('%', ?, '%');

其中?是用户提供的搜索字符串,结果是包含搜索字符串的单词列表。

2 个答案:

答案 0 :(得分:1)

最长的单词有多大? 如果那个约为7-8个字符,你可以找到每个字符串的所有子字符串并在trie中插入子字符串(在Aho-Corasik中使用的那个 - http://en.wikipedia.org/wiki/Aho-Corasick) 构建树需要一些时间,但搜索所有出现的将是O(长度(搜索的单词))。

答案 1 :(得分:0)

Postgres有一个模块可以执行trigram index

这似乎也是一个有趣的想法 - 构建一个三元组索引。

关于如何分解大于n-gram长度的文本搜索的问题中的注释:

这是一种可行的方法:

假设我们将搜索字符串设置为“abcde”,并且我们已经构建了一个trigram索引。 (你的琴弦长度较短 - 这可能会给你带来一个甜蜜点) 让搜索结果abc = S1,bcd = S2,cde = S3(其中S1,S2,S3是索引集)

然后S1,S2,S3的最长公共子串将给出我们想要的索引。

我们可以在执行LCS之前将每组索引转换为由分隔符(例如空格)分隔的单个字符串。

在找到LCS之后,我们必须在索引中搜索完整模式,因为我们已经分解了搜索词。即我们必须修剪具有“abc-XYZ-bcd-HJI-def”的结果

可以有效地找到一组字符串的LCS Suffix Arrays。或后缀树