【发布时间】:2013-11-29 13:01:00
【问题描述】:
我有一个包含 50K 到 100K 字符串的字典(最多可以包含 50+ 个字符),并且我正在尝试查找给定字符串是否在字典中并具有一些“编辑”距离容差。 (例如莱文斯坦)。在进行搜索之前,我可以预先计算任何类型的数据结构。
我的目标是尽可能快地对该字典运行数千个字符串并返回最近的邻居。如果有一个明显更快的算法可以这样做,我会得到一个布尔值来说明给定是否在字典中
为此,我首先尝试计算所有 Levenshtein 距离并取最小值,这显然非常慢。所以我尝试根据这篇文章实现一个Levenshtein Trie http://stevehanov.ca/blog/index.php?id=114
在此处查看我的要点以重现基准:https://gist.github.com/nicolasmeunier/7493947
以下是我在我的机器上获得的一些基准测试:
编辑距离为 0(完美匹配)
Benchmark.measure { 10.times { dictionary.search(random_word, 0) } }
<Benchmark::Tms:0x007fa59bad8908 @label="", @real=0.010889, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.00999999999999801, @total=0.00999999999999801>
*编辑距离为 2,它变得慢了很多 *
Benchmark.measure { 10.times { dictionary.search(random_word, 2) } }
<Benchmark::Tms:0x007fa58c9ca778 @label="", @real=3.404604, @cstime=0.0, @cutime=0.0, @stime=0.020000000000000018, @utime=3.3900000000000006, @total=3.4100000000000006>
它从那里开始走下坡路,并且对于大于 2 的编辑距离变得非常慢。(每个测试字符串平均 1 秒以上)。
我想知道如何/是否可以显着加快速度。如果已经在 ruby/gems 中实现了现有的解决方案,我也不想重新发明轮子......
编辑 1:就我而言,我希望我与字典匹配的大多数字符串都不在其中。因此,如果有任何算法可以快速丢弃字符串,那真的很有帮助。
谢谢, 尼古拉斯
【问题讨论】:
-
Nicolas,我不愿发表评论,因为我不熟悉文献,也不想偏离讨论,但我想起了很多个月前的一个问题,即确定文件是否与远程计算机上大型“库”中的任何文件相同。我在“文件签名”上对文件进行了索引,该签名是一种 CRC(循环冗余校验)计算的结果(一个 Fixnum,但我不记得有多少字节)。它非常快且 100% 准确。想法是计算每个字符串的签名,然后在索引中查找。
-
您是在寻找 100% 相同的文件还是允许任何误差范围?那是你能控制的吗?我会更多地研究它。感谢您的建议。
-
第一个似乎只计算 2 个单词之间的距离,并且在字典中搜索时没有实现任何索引/树/ngrams 数据结构来优化。到目前为止,我第一次尝试第二次的速度很慢......
-
尼古拉斯,实际上是 100%。要使用签名来区分两个长度相等的文件,可以肯定的是,签名必须至少与文件一样长,因此什么也得不到。但是,签名不需要很长时间,可能的签名数量就会大大超过世界上所有计算机上的文件数量。我使签名足够长,以至于两个不相等的文件具有相同签名的可能性太小而无需担心。这从来都不是问题。
标签: ruby performance algorithm levenshtein-distance fuzzy-search