【问题标题】:How to efficiently search large dataset for substrings?如何有效地在大型数据集中搜索子字符串?
【发布时间】:2012-08-02 17:38:09
【问题描述】:

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

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

如何找到包含子字符串“king”的字符串?我可以像这样暴力破解这个问题:

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

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

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

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

我应该考虑哪些其他算法和索引策略?有没有支持这个的开源库?能否使 SQL 或 Lucene 策略(如上)起作用?

说明需求的另一种方式是使用 SQL:

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

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

【问题讨论】:

标签: database algorithm data-structures lucene


【解决方案1】:

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

【讨论】:

  • 您的建议是构建一个包含每个子字符串的 trie,每个节点包含每个匹配单词的列表?
  • 结果会是这样,因为单独的字母也是子字符串。是的,会消耗太多内存。
  • 我们会从最初的字典中检查这个词吗?
  • 不,输入的搜索字符串不一定在字典中。我不确定高内存消耗点是否会破坏交易。我想知道是否可以在 SQL 中对 trie 和查询进行建模。这听起来很遥远。
  • 我怀疑是否有一个索引可以为 %something% 之类的查询提供服务。但是假设如果我们有常规的 B-tree 索引,应该快速处理类似 something% 的查询。因此,从字典中的每个单词中,我们可能会产生一些其他单词(pick -> pick、ick、ck、k)并放入单独的表(id、stringvalue、initial_string_id),然后根据like word% 进行选择。我想它应该比常规的 %word% 更快。
【解决方案2】:

Postgres 有一个执行trigram index 的模块

这似乎也是一个有趣的想法——建立一个三元索引。

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

这是一种可行的方法:

假设我们有一个搜索字符串“abcde”,我们已经建立了一个三元索引。 (您有长度较小的字符串 - 这可能会为您带来最佳效果) 设 abc= S1, bcd=S2,cde=S3 的搜索结果(其中 S1,S2,S3 是索引集)

那么 S1,S2,S3 的最长公共子串就会给出我们想要的索引。

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

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

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

【讨论】:

  • @landon9720 :当您有机会查看我的答案时,请发表评论。我想知道您对我建议的方法的看法。
猜你喜欢
  • 2017-12-02
  • 2017-08-02
  • 2017-09-21
  • 2011-11-04
  • 2011-08-28
  • 2022-12-18
  • 2018-08-05
  • 2012-03-04
  • 1970-01-01
相关资源
最近更新 更多