簡體   English   中英

php : 加速 levensthein 比較,10k + 記錄

[英]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>");
        }
     }
 }

序言:這樣的任務總是很耗時,總會有一些對的漏掉。 盡管如此,一些想法:

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一個inserted_at列,並且仍然需要將新名稱與每個其他名稱條目進行比較。

3.5 做一些關於Insert的工作

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM