将5000个字符串与PHP Levenshtein进行比较

将5000个字符串与PHP Levenshtein进行比较,php,database,similarity,street-address,levenshtein-distance,Php,Database,Similarity,Street Address,Levenshtein Distance,我在一个数组中有5000个(有时更多)街道地址字符串。我想把它们和莱文施泰因进行比较,找出相似的匹配。我如何才能做到这一点,而不循环遍历所有5000个,并直接与其他4999个进行比较 编辑:如果有人提出建议,我也对其他方法感兴趣。总体目标是根据用户提交的街道地址查找类似的条目(并消除重复条目)。我认为您无法避免在数组中循环,因为levenstein()函数只接受字符串而不接受数组作为输入 您可以执行以下操作: for($i=0;$i<count($array)-1;$i++) {

我在一个数组中有5000个(有时更多)街道地址字符串。我想把它们和莱文施泰因进行比较,找出相似的匹配。我如何才能做到这一点,而不循环遍历所有5000个,并直接与其他4999个进行比较


编辑:如果有人提出建议,我也对其他方法感兴趣。总体目标是根据用户提交的街道地址查找类似的条目(并消除重复条目)。

我认为您无法避免在数组中循环,因为levenstein()函数只接受字符串而不接受数组作为输入

您可以执行以下操作:

for($i=0;$i<count($array)-1;$i++)
{
    for($j=$i+1;$j<count($array);$j++)
    {
        $lev = levenshtein($array[$i],$array[$j]);
        if($lev == 0)
        {
            // exact match
        }
        else if($lev <= THRESHOLD)
        {
            // similar
        }
    }
}

for($i=0;$i由于Levenshtein算法的性质(特别是它是两个字符串之间的比较),我看不出这是怎么可能的

当然,您可以通过首先执行一些基本的匹配要求来减少比较次数,但这超出了您所要求的范围


作为一个(很可能是不相关的)选项,您可以始终使用类似于
soundex
的东西,它可以让您预先计算字符串值。(我相信您也可以直接在MySQL中使用它。)

您可以基于soundex对它们进行分组,然后将比较限制在最接近的N个情况下

 $mashed=array();
 foreach ($address as $key=>$val) {
      $mashed[$key]=soundex($val);
 }
 sort($mashed);
然后遍历$mashed的键


C.

考虑到您的问题,如果您想使用,我认为除了将每个地址与每个其他地址进行比较之外,没有其他方法

首先,你应该规范地址,去掉缩写等

  • 大道->大道
  • 路->路
对于类似的地址,您可以有一些固定的最大Lehvenstein距离(N)

如果是这样,您可以在确定当前地址对的编辑距离大于N时中止Lehvenstein算法。为此,您需要编写Lehvenstein算法的自定义版本。这将使该算法更快一些

还有一些相关的微不足道的优化。例如:如果地址A是10个字符长,地址B是20个字符长,那么你认为Levvestin距离小于8的地址是相似的。你可以查看地址的长度,并立即确定它们不相似。

< P>如果你想找到所有相似的值,你就可以。必须将所有项与所有其他项进行比较。但选择正确的数组函数将显著加快速度。下面是一个快速示例(结果数组可能更好):

您可以使用加速搜索/比较

说:

现在我们可以对Levenshtein距离做一个特别有用的观察:它形成一个度量空间。
[…]
假设我们有两个参数,query,我们在搜索中使用的字符串,n字符串与查询的最大距离,并且仍然可以返回。假设我们取一个任意字符串,测试并将其与查询进行比较。调用结果距离d。因为我们知道三角形不等式成立,所以我们所有的结果都必须具有最大距离d+n,且至少距离测试点d-n。
[…]
测试表明,距离为1的搜索查询不超过树的5-8%,两个错误的搜索查询不超过树的17-25%——与检查每个节点相比,这是一个显著的改进!
编辑:但这对你的(“12伯德路,6号公寓”和“12伯德路#6”)问题没有帮助。只有通过蛮力m*n比较。

我认为对类似地址进行分组的更好方法是:

  • 创建一个包含两个表的数据库-一个用于地址(和一个id),一个用于地址中单词或文字数字的音效(使用addresses表的外键)

  • 大写地址,将[A-Z]或[0-9]以外的任何内容替换为空格

  • 将地址按空格分割,计算每个“单词”的soundex,保留所有数字不变,并将其存储在soundexes表中,使用您开始使用的地址的外键

  • 对于每个地址(id为$target),查找最相似的地址:

    SELECT similar.id, similar.address, count(*) 
    FROM adress similar, word cmp, word src
    WHERE src.address_id=$target
    AND src.soundex=cmp.soundex
    AND cmp.address_id=similar.id
    ORDER BY count(*)
    LIMIT $some_value;
    
  • 计算源地址和查询返回的前几个值之间的levenstein差

  • (在数据库中,在大型数组上执行任何类型的操作通常都会更快)

    $stringA=“这是php编程语言”;
    $stringB=“这是一个完整的编程脚本,java php和所有其他次要语言都包含在其中”;
    回显“字符串1-->”。$stringA。“
    ”; 回显“字符串2-->”。$stringB。“
    ”; //将字符串更改为数组 $array1=爆炸(“”,$stringA); $array2=爆炸(“”,$stringB); //从两个字符串中获取相同的元素 $c=数组相交($array1,$array2); //将数组更改为字符串 $d=内爆(“”,$c); 回显“字符串相同元素-->”$d.“
    ”; //从两个数组中获取difrent元素 $result=array_diff($array2,$array1); //将数组更改为字符串 $zem=内爆(“”,$result); 如果(!空($zem)){ echo“字符串差异-->”$zem。“
    ”; }否则{ echo“字符串差异-->两个字符串相同
    ”; } 类似的文本($stringA,$d,$p); echo“字符串之间的相似性为“$p.”%
    ”;
    我从来没有使用过Soundex。你知道它们在街道地址类型缩写词“St.”中的作用有多好吗?Soundex()设计用于处理人名。如果你将它们应用于地址,则将Soundex算法应用于地址的每个部分是有意义的,例如“23 Bird Road”->Soundex(“Bird”)和Soundex(“Road”)此解决方案类似于
    O(2n)
    O(2nm)
    (均未简化),其中
    m
    是地址中的每个单词。这是对
    O(n^2)的极大改进
    。它不能插入缩写-但St可以是Street或Saint或…?取决于上下文。C.我担心这会导致2500万次比较。@phirschybar:实际上它将是1250万次,我们只比较不同的
    SELECT similar.id, similar.address, count(*) 
    FROM adress similar, word cmp, word src
    WHERE src.address_id=$target
    AND src.soundex=cmp.soundex
    AND cmp.address_id=similar.id
    ORDER BY count(*)
    LIMIT $some_value;
    
    $stringA = "this is php programming language";
    $stringB = "this is complete programming script in which java php and  all other minor languages include";
    
    echo "string 1---->".$stringA."<br />";
    echo "string 2---->".$stringB."<br />";
    // changing string to arrays
    $array1 = explode(' ', $stringA);
    $array2 = explode(' ', $stringB);
    
    // getting same element from two strings
    $c = array_intersect($array1, $array2);
    // changing array to the string
    $d=implode(' ',$c);
    
    echo "string same elements---> ".$d."<br />";
    
    
    // getting difrent  element from two arrays
    $result = array_diff($array2, $array1);
    // changing array to the string
    $zem = implode(' ',$result);
    
    if (!empty($zem)) {
      echo "string diffrence---> ".$zem."<br />";
    } else {
      echo "string diffrence--->both strings are same <br />";
    }
    
    similar_text($stringA, $d, $p);
    echo " similarity between the string is ".$p."% <br />";