我刚学习Metaphone和Double Metaphone搜索算法,我有几个问题。根据Metaphone Wiki页面,我发现了几个带有实现的源,特别是MySQL实现。我想用我的测试数据库测试它,所以我首先导入了找到here
的metaphone.sql文件(包含双元电话功能)现在,我有一个表格,国家/地区,其中包含“名称”列中所有国家/地区的列表,例如'阿富汗','阿尔巴尼亚','阿尔及利亚'等等。首先,我想在表格中创建一个新专栏来存储每个国家的双重Metaphone字符串。我运行了以下代码:
UPDATE country SET NameDM = dm(name)
一切正常。阿富汗的互联网字符串是'AFKNSTN',阿尔巴尼亚是'ALPN',阿尔及利亚是'ALKR; ALJR'等等。“真棒,”我想。
然而,当我试图查询表时,我没有得到任何结果。根据metaphone.sql的作者,我坚持以下SQL语句的语法:
SELECT Name FROM tblPeople WHERE dm(Name) = dm(@search)
所以,我将此代码更改为以下内容:
SELECT * FROM country WHERE dm(name) = dm(@search)
当然,我将“@search”更改为我正在寻找的任何搜索词,但在每次SQL查询后我得到0个结果。
有人能解释这个问题吗?我错过了重要的事情,还是我只是误解了Metaphone算法?
谢谢!
答案 0 :(得分:3)
比较dm()
输出时,我使用以下函数来进一步提高模糊度。直接检查dm('smith') != dm('schmitt')
因大量名称而失败,包括我自己的常见拼写错误。
该函数创建一个0.0到1.0之间的匹配加权(我希望),它允许我对每个返回的行进行排名,并选择那些有益的,0.3对于捕获奇怪的发音非常好,0.5更常见。 / p>
即。
dmcompare(dm("boothroyd"), dm("boofreed")) = 0.3
dmcompare(dm("smith"), dm("scmitt")) = 0.5
请注意,这是双变音符字符串和不原始字符串的比较,这是针对性能问题,我的数据库包含metaphone的列以及原始字符串。
CREATE FUNCTION `dmcompare`(leftValue VARCHAR(55), rightValue VARCHAR(55)) RETURNS DECIMAL(2,1) NO SQL BEGIN --------------------------------------------------------------------------------------- -- Compare two (double) metaphone strings for potential similarlity, i.e. -- dm("smith") != dm("schmitt") :: "SM0;XMT" != "XMT;SMT" -- dmcompare( dm('smith'), dm('schmitt' ) returns 0,5 -- @author: P.Boothroyd -- @version: 0.9, 08/01/2013 -- The values here can still be played with -- (c) GNU P L - feel free to share and adapt, but please acknowledge the original code --------------------------------------------------------------------------------------- DECLARE leftPri, leftSec, rightPri, rightSec VARCHAR(55) DEFAULT ''; DECLARE sepPos INT; DECLARE retValue DECIMAL(2,1); DECLARE partMatch BOOLEAN; -- Extract the metaphone tags SET sepPos = LOCATE(";", leftValue); IF sepPos = 0 THEN SET sepPos = LENGTH(leftValue) + 1; END IF; SET leftPri = LEFT(leftValue, sepPos - 1); SET leftSec = MID(leftValue, sepPos + 1, LENGTH( leftValue ) - sepPos); SET sepPos = LOCATE(";", rightValue); IF sepPos = 0 THEN SET sepPos = LENGTH(rightValue) + 1; END IF; SET rightPri = LEFT(rightValue, sepPos - 1); SET rightSec = MID(rightValue, sepPos + 1, LENGTH( rightValue ) - sepPos); -- Calculate likeness factor SET retValue = 0; SET partMatch = FALSE; -- Primaries equal 50% match IF leftPri = rightPri THEN SET retValue = retValue + 0.5; SET partMatch = TRUE; ELSE IF SOUNDEX(leftPri) = SOUNDEX(rightPri) THEN SET retValue = retValue + 0.3; SET partMatch = TRUE; END IF; END IF; -- Test alternate primary and secondaries, worth 30% match IF leftSec = rightPri THEN SET retValue = retValue + 0.3; SET partMatch = TRUE; IF SOUNDEX(leftSec) = SOUNDEX(rightPri) THEN SET retValue = retValue + 0.2; SET partMatch = TRUE; END IF; END IF; -- Test alternate primary and secondaries, worth 30% match IF leftPri = rightSec THEN SET retValue = retValue + 0.3; SET partMatch = TRUE; IF SOUNDEX(leftPri) = SOUNDEX(rightSec) THEN SET retValue = retValue + 0.2; SET partMatch = TRUE; END IF; END IF; -- Are secondary values the same or both NULL IF leftSec = rightSec THEN -- No secondaries ... IF leftSec = '' THEN -- If there is prior matching then no secondaries is 40% IF partMatch = TRUE THEN SET retValue = retValue + 0.4; END IF; ELSE -- If the secondaries match then 50% match SET retValue = retValue + 0.5; END IF; ELSE IF SOUNDEX(leftSec) = SOUNDEX(rightSec) THEN IF leftSec = '' THEN IF partMatch = TRUE THEN SET retValue = retValue + 0.3; END IF; END IF; END IF; END IF; RETURN (retValue); END
请随意使用代码,但请提及此代码的来源 P.Boothroyd 以及任何用途 - 即更改值等。
干杯,保罗
答案 1 :(得分:2)
仔细查看排序/字符集/编码(可以将其定义为列级别)。排序规则定义了字符串的比较方式,但字符集可能意味着使用某种排序规则。也许你的文字字符串有不同的字符集,导致字符串比较失败。
即使这可能是揭示
select name, length(name), char_length(name), @search, length(@search), char_length(@search) from tbl
show variables like 'character%'
show create table tbl
答案 2 :(得分:2)
SELECT * FROM country WHERE NameDM = dm(@search)
最终可能是您想要的,因此您每次进行搜索时都不会为每个国家/地区计算DM。你看起来应该有什么用。你可以通过这样做来解决问题:
SELECT dm('Albania')
...应该让你ALPN。现在你得到什么......
SELECT * FROM country WHERE NameDM = 'ALPN'