[英]php : speed up levensthein comparing, 10k + records
在我的 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>");
}
}
}
序言:這樣的任務總是很耗時,總會有一些對的漏掉。 盡管如此,一些想法:
假設$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
一個inserted_at
列,並且仍然需要將新名稱與每個其他名稱條目進行比較。
a) 如果等待是可以接受的,則在應該插入新記錄后進行檢查,以便您將其寫入日志或直接向用戶反饋。 (切線:對於像http://gearman.org/這樣的異步任務隊列來說,這可能是一個很好的用例 -> 在后台啟動一個新進程進行檢查,立即返回插入的成功消息)
b) PHP 有另外兩個函數可以幫助搜索幾乎相似的字符串: metaphone()和soundex() 。 這些函數生成抽象散列,代表字符串在說話時的發音。 您可以在每次插入時生成(一個或兩個)這些哈希值,將它們作為單獨的字段存儲在表中,並使用簡單的 SQL 函數查找具有相似哈希值的記錄
levenshtein 的問題在於它只比較字符串 a 和字符串 b。 我曾經構建了一個拼寫校正器,它將所有字符串 a 放入一個大樹中,並起到字典的作用。 然后它會在該字典中查找任何字符串 b,找到所有最近匹配的單詞。 我首先在 Fortran (!) 中完成,然后在 Pascal 中完成。 用更現代的語言會最簡單,但我懷疑 php 不會讓它變得容易。 看這里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.