Mysql 从大型表中查找相似值的最佳方法

Mysql 从大型表中查找相似值的最佳方法,mysql,sql,Mysql,Sql,我有一个数据库,我在mysql中存储了超过1000000个名字。现在,我的应用程序的任务有点典型。我不仅在数据库中搜索名字,还找到相似的名字。假设输入的名字是christian,那么应用程序将显示christine、chris等建议的名字。在不使用like子句的情况下,最好的方法是什么。这些建议将仅针对名称最后部分的更改 我想你可以定期去看看。我对thme不在行,但有一个名为REGEXP的函数,可以放在WHERE子句中。LookLike通常是一个很好的解决方案,但是提高性能的另一种方法可能是创建

我有一个数据库,我在mysql中存储了超过1000000个名字。现在,我的应用程序的任务有点典型。我不仅在数据库中搜索名字,还找到相似的名字。假设输入的名字是christian,那么应用程序将显示christine、chris等建议的名字。在不使用like子句的情况下,最好的方法是什么。这些建议将仅针对名称最后部分的更改

我想你可以定期去看看。我对thme不在行,但有一个名为REGEXP的函数,可以放在WHERE子句中。Look

Like通常是一个很好的解决方案,但是提高性能的另一种方法可能是创建部分列索引,然后以与前缀相同的长度提交查询。请参阅关于col_namelength的说明。

如果您还希望通过声音获得类似的名称,如SOUNDEX可能会有所帮助:

否则…像“chri%”对我来说是个不错的主意


如果你真的想要第一个没有LIKE的字符,你可以使用SUBSTRING。

你可以使用SOUNDS LIKE,我认为它应该也很快


在左手边固定的地方使用LIKE不需要扫描表。我假设这就是为什么您不想使用LIKE:SELECT*fromtable,其中名称像CONCAT?,%很快,并且不需要扫描表来查找行。CONCAT允许您使用%语法的准备好的查询

您还可以执行以下操作:

从表中选择*名称<'christian'限制20

从表中选择*,其中名称>“christian”限制20


在已排序的列表中查找邻居

您可以使用php的变音函数为每个名称生成变音代码,并将其与名称一起存储

<?php
print "chris" . "\t" . metaphone("chris") . "\n";
print "christian" . "\t" . metaphone("christian") . "\n";
print "christine" . "\t" . metaphone("christine") . "\n";

# prints:
# chris      XRS
# christine  XRSTN
# christian  XRSXN
然后可以在php中使用levenshtein距离算法[http://php.net/manual/en/function.levenshtein.php]或者mysql[http://www.artfulsoftware.com/infotree/queries.php552]计算元代码之间的距离。在我下面的测试中,2或更少的距离似乎表明了你正在寻找的相似程度

<?php
$names = array(
        array('mike',metaphone('mike')),
        array('chris',metaphone('chris')),
        array('chrstian',metaphone('christian')),
        array('christine',metaphone('christine')),
        array('michelle',metaphone('chris')),
        array('mick',metaphone('mick')),
        array('john',metaphone('john')),
        array('joseph',metaphone('joseph'))
);

foreach ($names as $name) {
        _compare($name);
}

function _compare($n) {
        global $names;
        $name = $n[0];
        $meta = $n[1];

        foreach ($names as $cname) {
                printf("The distance between $name and {$cname[0]} is %d\n",                          
                  levenshtein($meta, $cname[1]));
        }
}

为什么不使用类似的子句呢?考虑切换到PASGRES.它允许使用您可以添加新字段来执行此操作吗?如果是这样的话,请查看我在my answer.REGEXP下的附加注释。对于更复杂的查询,REGEXP很方便,但速度会比LIKE慢得多。我想象我从未使用过它,它只是为了提出与LIKE不同的东西!我希望我能在这一点上投两次票。当然,如果您使用子字符串只比较第一个字符,那么xyz%似乎做了同样的事情。但是SOUNDEX。。。这是一个很好的建议,它让我想起了Lingua::EN::SimilarNames、Text::Soundex和Lingua::EN::NameLookup CPAN模块,这些模块对于Perl来说并没有帮助,因为它们需要先导入数据集。使用子字符串需要进行完整的表扫描。在这种情况下,LIKE会更快。SOUNDEX是一个很好的建议,但是应该存储为一个单独的索引字段,以便快速搜索。kalyoncu,这可能会做得很好,但需要像SOUNDEX一样进行完整的表扫描。如果您可以创建一个额外的字段,您可以避免这种情况。每次插入时,您都会将soundex插入该字段,在搜索时间内,它将非常快。还可以在该字段上建立索引。嗯,我想这是一个比以前更好的答案。你也可以将soundex字符串转换成数字,如果我没记错的话,它也是C格式的。其中C在1-26之间,最多6位数。但soundex不是一个非常精确的算法。chris生成的代码是C620,而christine和christian生成的代码是C623,因此他的上述相似性将失败。