我有一个数据库,我在mysql中存储超过1000000个名称。现在我的应用程序的任务有点典型。我不仅搜索数据库中的名称,还查找类似的名称。假设名称输入为christian
,则应用程序将显示建议的名称,例如christine
,chris
等。在不使用like
的情况下,执行此操作的最佳方式是什么?条款。建议仅针对名称最后部分的更改。
答案 0 :(得分:5)
如果你想要类似的名字(通过声音)SOUNDEX()
之类的东西可以提供帮助:http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_soundex
否则… LIKE 'chri%'
似乎对我来说不是一个坏主意?
如果您真的只想要没有LIKE
的第一个字符,则可以使用SUBSTRING()
。
答案 1 :(得分:2)
您可以使用php的metaphone()函数为每个名称生成metaphone代码,并将其与名称一起存储。
<?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
然后你可以使用levenshtein距离算法(在php [http://php.net/manual/en/function.levenshtein.php]或mysql [http://www.artfulsoftware.com/infotree/queries] .php#552])计算元代码之间的距离。在我的测试中,距离为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]));
}
}
答案 2 :(得分:1)
Like
通常是一个很好的解决方案,但另一种提高性能的方法可能是创建部分列索引,然后以与前缀相同的长度提交查询。请参阅有关col_name(length)
的{{3}}。
答案 3 :(得分:0)
我认为你可以使用正则表达式。我不擅长它们但是有一个名为REGEXP的函数可以放在WHERE子句中。看here
答案 4 :(得分:0)
你可以使用SOUNDS LIKE,我认为它应该也很快。
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#operator_sounds-like
答案 5 :(得分:0)
使用左侧固定的LIKE不需要进行表扫描。我假设这就是你不想使用LIKE的原因:SELECT * FROM table WHERE name LIKE CONCAT(?, "%")
速度很快,不需要表扫描来查找行。 CONCAT允许您使用%语法准备的查询。
您还可以执行以下操作:
SELECT * from table WHERE name < 'christian' LIMIT 20
和
SELECT * FROM table WHERE name > 'christian' LIMIT 20
在排序列表中查找邻居。