php:加速levensthein比较,10k +记录

时间:2015-05-06 14:56:01

标签: php mysql performance

在我的mysql表中我有字段名称,这是唯一的。然而,该领域的内容被收集在不同的地方。因此,由于拼写错误,我有可能有2个名称非常相似的记录而不是第二个被丢弃的记录。

现在我想找到那些与另一个非常相似的条目。为此,我循环遍历所有记录,并通过再次循环遍历所有记录将名称与其他条目进行比较。问题是有超过15k的记录需要花费太多时间。有没有办法更快地做到这一点?

这是我的代码:

for($x=0;$x<count($serie1);$x++)
    {
    for($y=0;$y<count($serie2);$y++)
        {
        $sim=levenshtein($serie1[$x]['naam'],$serie2[$y]['naam']);
        if($sim==1)
            print("{$A[$x]['naam']} --> {$B[$y]['naam']} = {$sim}<br>");
        }
     }`

2 个答案:

答案 0 :(得分:2)

序言:这样的任务总是耗费时间,并且总会有一些对的漏掉。 不过,有一些想法:

1。实际上,算法可以(有点)改进

假设$series1$series2具有相同顺序的相同值,则不需要每次都在内循环中遍历整个第二个数组。在此用例中,您只需要评估每个值对一次 - levenshtein('a', 'b')就足够了,您也不需要levenshtein('b', 'a')(并且您也不需要levenstein('a', 'a')

在这些假设下,你可以像这样编写你的函数:

for($x=0;$x<count($serie1);$x++)
{
   for($y=$x+1;$y<count($serie2);$y++) // <-- $y doesn't need to start at 0
    {
      $sim=levenshtein($serie1[$x]['naam'],$serie2[$y]['naam']);
      if($sim==1)
        print("{$A[$x]['naam']} --> {$B[$y]['naam']} = {$sim}<br>");
    }
 }

2。也许MySQL更快

网络中有levenshtein()实现作为MySQL函数的例子。有关SO的示例如下:How to add levenshtein function in mysql?

如果您对复杂(ish)SQL感到满意,可以将繁重的工作委派给MySQL,至少获得一点性能,因为您没有将整个16k行提取到PHP运行时。

3。不要一次做所有事情/保存你的结果

当然,您必须为每条记录运行一次该函数,但在初始运行后,您只需检查自上次运行以来的新条目。安排每天/每周/每月一次的chronjob ..检查所有新记录。您需要在表中使用inserted_at列,并且仍需要将新名称与其他所有名称条目进行比较。

3.5做一些onInsert

的工作

a)如果等待是可接受的,则应在插入新记录后进行检查,以便将其写入日志或直接反馈给用户。 (切线:对于像http://gearman.org/这样的异步任务队列来说,这可能是一个很好的用例 - &gt;在后台启动一个新的检查过程,并立即返回插入的成功消息)

b)PHP还有另外两个函数来帮助搜索几乎相似的字符串:metaphone()soundex()。这些函数生成抽象哈希,表示字符串在说出时的声音。您可以在每个插入中生成(一个或两个)这些哈希值,将它们存储为表中的单独字段,并使用简单的SQL函数查找具有类似哈希值的记录

答案 1 :(得分:0)

levenshtein的问题是它只将字符串a与字符串b进行比较。我曾经构建了一个拼写校正器,它将所有字符串放入一个大的trie中,并且用作字典。然后它会查找该字典中的任何字符串b,找到所有最匹配的单词。我先在Fortran(!),然后在Pascal中完成。在更现代的语言中这将是最简单的,但我怀疑php不会让它变得容易。 Look here.