在我的应用程序中,我有一个用户表,其中包含first_name
和last_name
。我目前有第三列full_name
(自动生成),如下所示:first_name + last_name + first_name(不包含特殊字符)。
"Etienne", "De Crécy", "Etienne De Crecy Etienne"
现在,我有一个简单的算法可以自动完成用户输入(删除了特殊字符):
SELECT * FROM users WHERE full_name LIKE "%input%"
该查询返回输入为
Crécy Etienne
,Etienne De
,Cré
,Cre
,Etienne
的Etienne我想在此查询中添加一些模糊性以允许用户拼写错误。用户编写以下代码时,该新算法应该能够返回Etienne:
Etiene
(类似于名字)Etienne Crecy
(与全名相似,不带微粒)Crecy Etienne
(类似于全名,无任何其他方向)De Cressi
(听起来像姓)Cressi
(听起来像姓氏一样,没有任何微粒)我做了很多搜索,最相关的想法是使用
SOUNDEX
方法(或Metaphone
过程)或levenstein
过程。我不能使用它,因为:Soundex基于第一个字母,因此
SOUNDEX(Cressy)
与SOUNDEX(De cressy)
不同,即使它们非常相似。Metaphone基于字母的位置(以“ kn”乞gg就像以“ n”乞,,但仅在第一个位置)
Levenstein并不关心字符串的长度:De Cressy与Cressy不同。
您是否有关于“混合”这些方法的想法,或者对我有其他想法?
最佳答案
我强烈建议您尝试使用Solr或Elasticsearch(以及更大的灵活性和更好的性能)。
但是,如果要在MySQL内部复制基本的语音搜索引擎,则需要能够在插入时(以及自动完成时的每个查询)为每个full_name
提取多个标记(单词或单词编码)。
1)。首先,请确保您的full_name
列为FULLTEXT
类型。然后切换到MATCH...AGAINST
查询语法代替LIKE %foo%
。
这将为您购买精确的内部令牌匹配,例如“ cressy”与“ de cressy”。
使用Levenshtein距离作为排序标准的想法不错,但是运行起来很昂贵,因此请确保已LIMIT
查询了MATCH...AGAINST
查询,如果要输出levenshtein,请确保ORDER BY MATCH... DESC
(查询,full_name)作为选择的一部分。
目标是避免在所有行上运行levenshtein
2)。如果您仍然有兴趣扩展结果以包含类似声音的内容:
创建一个带外键列回到您的主名称表的phonetic_token表(这是一对多关系的名称与令牌)。
在此表中添加列soundex
和metaphone
。
将记录插入主要名称表时,还需要在空格上对其进行解析,然后将每个名称词的soundex和metaphone编码插入phonetic_token
。
您可能需要添加一些解析逻辑以确保记录所有姓氏和名字的三倍(例如,在语音编码之前,请确保“ de cressy”标记化为“ de”,“ cressy”和“ decressy”,以便匹配预期的输入。)
现在,当查询要显示的听起来相似的名称完成时,您实际上将要与phonetic_token
一起连接您的主名称表WHERE soundex IN(查询令牌中的soundex代码列表)或metaphone IN(查询令牌中的metaphone代码列表) )。
如果MATCH(full_name)...AGAINST(query_text)
产生的结果太少,我建议将此语音匹配作为第二个查询运行。
同样,Solr或Elasticsearch将通过配置为您完成所有这些文本整理,同时为您提供出色的性能。根据应用程序的范围,从MySQL中退出文本匹配可能会节省大量时间和麻烦。
关于mysql - 模糊自动完成,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30591131/