在我的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>");
}
}`
答案 0 :(得分:2)
序言:这样的任务总是耗费时间,并且总会有一些对的漏掉。 不过,有一些想法:
假设$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>");
}
}
网络中有levenshtein()实现作为MySQL函数的例子。有关SO的示例如下:How to add levenshtein function in mysql?
如果您对复杂(ish)SQL感到满意,可以将繁重的工作委派给MySQL,至少获得一点性能,因为您没有将整个16k行提取到PHP运行时。
当然,您必须为每条记录运行一次该函数,但在初始运行后,您只需检查自上次运行以来的新条目。安排每天/每周/每月一次的chronjob ..检查所有新记录。您需要在表中使用inserted_at
列,并且仍需要将新名称与其他所有名称条目进行比较。
a)如果等待是可接受的,则应在插入新记录后进行检查,以便将其写入日志或直接反馈给用户。 (切线:对于像http://gearman.org/这样的异步任务队列来说,这可能是一个很好的用例 - &gt;在后台启动一个新的检查过程,并立即返回插入的成功消息)
b)PHP还有另外两个函数来帮助搜索几乎相似的字符串:metaphone()和soundex()。这些函数生成抽象哈希,表示字符串在说出时的声音。您可以在每个插入中生成(一个或两个)这些哈希值,将它们存储为表中的单独字段,并使用简单的SQL函数查找具有类似哈希值的记录
答案 1 :(得分:0)
levenshtein的问题是它只将字符串a与字符串b进行比较。我曾经构建了一个拼写校正器,它将所有字符串放入一个大的trie中,并且用作字典。然后它会查找该字典中的任何字符串b,找到所有最匹配的单词。我先在Fortran(!),然后在Pascal中完成。在更现代的语言中这将是最简单的,但我怀疑php不会让它变得容易。 Look here.