子串搜索算法(非常大的干草堆,小针)

时间:2010-08-07 23:10:21

标签: algorithm language-agnostic substring

我知道这里已经有几个类似的问题,但我需要一些针对我案例的建议(找不到类似的东西)。

我必须搜索大量数据,以获得大约十亿倍的子字符串(10亿字节中的10个字节)。干草堆没有变化,所以如果需要我可以承受大量的预计算。我只需要搜索部分尽可能快。

我找到了 O(n)时间( n = haystack size, m =针头大小)的算法,以及天真的搜索取 O(n + m)。由于此特定情况下的 m 非常小,我还可以研究其他算法吗?

编辑: 谢谢大家的建议! 更多信息 - 数据可以被认为是随机位,所以我认为任何类型的索引/排序都不可能。要搜索的数据可以是任何内容,而不是英语单词或任何可预测的内容。

5 个答案:

答案 0 :(得分:7)

您正在寻找名为Trie或“前缀树”的数据结构。简而言之,这个数据结构编码可以在你的语料库中找到的所有可能的字符串前缀。

Here is a paper使用前缀树在DNA序列中搜索小子串。我想这可能对你有所帮助,因为你的情况听起来很相似。

如果您知道输入搜索字符串长度的明确限制,则可以限制Trie的增长,使其不存储长度超过此最大长度的任何前缀。通过这种方式,您可以将代表所有10G的Trie安装到小于10G的内存中。特别是对于高度重复的数据,任何类型的Trie都是压缩数据表示。 (或者应该,如果实施得当。)将Trie深度限制为最大输入搜索字符串可以进一步限制内存消耗。

答案 1 :(得分:3)

值得关注suffix arraystrees。它们都需要预计算和大量内存,但它们优于反向索引,因为您可以在O(m)(对于后缀树)和O(m + log n)中搜索任意子串(对于具有最少公共前缀的后缀数组)信息)。

如果你手上有很多时间,你可以查看compressed suffix arrays并简洁CSA,它们是你自己索引的数据的压缩版本(即数据)也是索引,没有外部索引)。这真是世界上最好的,因为你不仅拥有数据的压缩版本(你可以抛弃原始数据),但它也被编入索引!问题是理解研究论文并将其翻译成代码:)

如果您不需要完美的子字符串匹配,而是需要一般搜索功能,请查看Lucene

答案 2 :(得分:3)

鉴于Knuth-Morris-Pratt或Boyer-Moore你不会做得更好,你应该考虑的是你的搜索过程的并行化。

答案 3 :(得分:3)

在我看来,前缀/后缀树通常是标准的,最好的和最谨慎的解决方案。你不能错过他们。

但这是一个不同的想法,它转向Bloom filters。你可能知道这些是什么,但以防万一(和其他人阅读这个答案):布隆过滤器是非常小的,非常紧凑的位向量,近似集包含。如果你有一组S和一个Bloom过滤器用于该组B(S),那么

x ∈ S ⇒ x ∈ B(S)

但往复是假的。这就是结构的概率:Bloom过滤器会返回假阳性(quantifiable)概率。但是使用布隆过滤器的近似值比狂野更快,而不是完全在集合上测试。

一个简单的案例使用:在很多应用程序中,使用Bloom过滤器,作为过滤器。检查缓存是昂贵的,因为你必须做一个硬盘访问,所以像Squid这样的程序会首先在内存中检查一个小的Bloom过滤器,如果Bloom过滤器返回一个肯定的结果,那么Squid会检查缓存。如果是误报,那就没关系,因为Squid实际访问缓存时会发现这一点 - 但优点是Bloom过滤器可以避免Squid检查缓存中的大量请求,而这些请求本来就没用。)

使用Bloom过滤器在字符串搜索中取得了一些成功。这是一个草图(我可能还记得一些错误的细节)。文本文件是N行的序列。您正在寻找一个由M个字母组成的单词(并且任何单词都不能分布在两行中)。预处理阶段将为每一行构建ONE Bloom过滤器,方法是将该行的每个子序列添加到Bloom过滤器中;例如,对于这一行

 Touching this dreaded sight, twice seene of vs,

将使用“T”,“To”,“Tou”......“o”,“ou”,......“vs”,“s”,“s”创建相应的布隆过滤器,“,”。 (我可能有这个部分错了。或者你可能想要优化。)

然后,当搜索大小为M的子字时,只需对每个Bloom过滤器进行一次非常快速的检查,并且当有命中时,例如,与KMP算法紧密检查该行。在实践中,如果你很好地调整Bloom过滤器,那么权衡是非常值得的。搜索速度非常快,因为您消除了所有无用的行。

我相信这个概念你可以为你的情况推导出一个有用的方案。现在,我看到两个明显的改编:

  • 要么在大小为K的多个块中切割数据集(每个块都有Bloom过滤器,就像上一个示例中的行一样);

  • 或者使用一种二分法,你将这个集合分成两个子集,每个子​​集都有一个Bloom过滤器,然后每个子集分成两个带有自己的Bloom过滤器的子子集等(如果你要去要按照我所描述的方法建议添加所有子串,这第二个想法会有点过分 - 除了你不必添加所有子串,只有1到10的子串。

这两种想法可以通过创造性的方式结合起来创建多层方案。

答案 4 :(得分:0)

如果你能够负担得起空间(很多空间!)来创建一个索引,那么将你的小块(例如四个字节块)编入索引并将它们与它们在大海捞针中的偏移量一起存储肯定是值得的 - 然后搜索对于10个字节,涉及搜索搜索项的前四个字节的所有四个字节块并检查接下来的六个字节。

相关问题