Почему эта функция двойного метафона MySQL не работает правильно?
Я только что узнал об алгоритмах поиска Metaphone и Double Metaphone, и у меня есть несколько вопросов. На странице Metaphone Wiki я нашел пару источников с реализациями, в частности, с реализацией MySQL. Я хотел проверить это с моей тестовой базой данных, поэтому сначала импортировал файл metaphone.sql (содержащий функцию двойного метафона), найденный здесь.
Прямо сейчас у меня есть таблица, страна, в которой есть список всех стран в столбце "имя", например, "Афганистан", "Албания", "Алжир" и т. Д. Итак, во-первых, я хотел на самом деле создать новый столбец в таблице для хранения строки двойного метафона каждой страны. Я запустил следующий код:
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" на любой поисковый запрос, но я получил 0 результатов после каждого запроса SQL.
Может ли кто-нибудь объяснить эту проблему? Я что-то упускаю или просто неправильно понимаю алгоритм Metaphone?
Спасибо!
3 ответа
Внимательно посмотрите на сопоставление / набор символов / кодировку (это может быть определено вплоть до уровня столбца). Сличение определяет, как сравниваются строки, но набор символов может подразумевать использование определенного сопоставления. Возможно, ваша литеральная строка имеет другой набор символов, что приводит к сбою сравнения строк.
даже это может быть показательным
select name, length(name), char_length(name), @search, length(@search), char_length(@search) from tbl
,
show variables like 'character%'
,
show create table tbl
При сравнении dm()
Выходы Я использую следующую функцию, чтобы обеспечить дополнительный уровень размытости. Прямая проверка dm('smith') != dm('schmitt')
не удается для значительного числа имен, в том числе общих моих орфографических ошибок.
Функция создает вес совпадения между 0, 0 и 1, 0 (я надеюсь), что позволяет мне ранжировать каждую возвращаемую строку и выбирать те, которые приносят пользу, 0,3 является хорошим значением для захвата нечетных произношений, 0,5 более обычным.
т.е.dmcompare(dm("boothroyd"), dm("boofreed")) = 0.3
dmcompare(dm("smith"), dm("scmitt")) = 0.5
Обратите внимание, что это сравнение строк двойного метафона, а не исходных строк, это из-за проблем с производительностью, моя БД содержит столбец для метафона, а также исходную строку.
СОЗДАТЬ ФУНКЦИЮ `dmcompare`(leftValue VARCHAR(55), rightValue VARCHAR(55)) ВОЗВРАЩАЕТСЯ ДЕСЯТИЧНО (2,1) НЕТ SQL НАЧИНАЕТСЯ ---------------------- -------------------------------------------------- --------------- - Сравнить две (двойные) строки метафона на предмет потенциального сходства, т.е. - dm("smith")!= Dm("schmitt"):: "SM0;XMT"!= "XMT;SMT" - dmcompare( dm('smith'), dm('schmitt') возвращает 0,5 - @author: P.Boothroyd - @version: 0.9, 08/01/2013 - Значения здесь можно по-прежнему воспроизводить - (c) GNU P L - не стесняйтесь делиться и адаптировать, но, пожалуйста, подтвердите оригинальный код ------------------- -------------------------------------------------- ------------------ ОБЪЯВИТЬ leftPri, leftSec, rightPri, rightSec VARCHAR(55) DEFAULT ''; ОБЪЯВИТЬ sepPos INT; ОБЪЯВИТЬ retValue DECIMAL(2,1); ОБЪЯВИТЬ partMatch BOOLEAN; - Извлечь метафоновые теги SET sepPos = LOCATE(";", leftValue); IF, если sepPos = 0, ТО SET 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); ЕСЛИ sepPos = 0, ТО УСТАНОВИТЬ sepPos = ДЛИНА (rightValue) + 1; END IF; SET rightPri = LEFT(rightValue, sepPos - 1); SET rightSec = MID(rightValue, sepPos + 1, LENGTH( rightValue) - sepPos); - Рассчитать коэффициент подобия SET retValue = 0; SET partMatch = FALSE; - Первичные значения равны 50%, если IF leftPri = rightPri THEN SET retValue = retValue + 0.5; SET partMatch = TRUE; ИЛИ ЕСЛИ ЕСЛИ SOUNDEX(leftPri) = SOUNDEX(rightPri) ТОГДА УСТАНОВИТЬ retValue = retValue + 0.3; SET partMatch = TRUE; END IF; END IF; - Проверьте альтернативные первичные и вторичные, на 30% совпадение, если 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; - Проверьте альтернативные первичные и вторичные, достойные 30% совпадения, если leftPri = rightSec THEN SET retValue = retValue + 0.3; SET partMatch = TRUE; ЕСЛИ SOUNDEX(leftPri) = SOUNDEX(rightSec), то THEN SET retValue = retValue + 0.2; SET partMatch = TRUE; END IF; END IF; - Являются ли вторичные значения одинаковыми или равными NULL, ЕСЛИ leftSec = rightSec THEN - Нет вторичных... IF leftSec = '' THEN - Если есть предварительное соответствие, тогда никакие вторичные значения не равны 40% IF partMatch = TRUE THEN SET retValue = retValue + 0,4; END IF; ELSE - если вторичные совпадают, то 50% совпадают. SET retValue = retValue + 0.5; END 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; ВОЗВРАТ (retValue); КОНЕЦ
Пожалуйста, не стесняйтесь использовать этот код, но также, пожалуйста, укажите источники для этого кода P.Boothroyd при любом использовании - то есть изменение значений и т. Д.
Ура, Пол
SELECT * FROM country WHERE NameDM = dm(@search)
Это, вероятно, то, что вы хотите в конце, так что вы не вычисляете DM для каждой страны каждый раз, когда выполняете поиск. То, что у тебя было похоже, должно было сработать. Вы можете решить проблему, выполнив:
SELECT dm('Albania')
... должен получить тебя ALPN. Теперь, что вы получаете за...
SELECT * FROM country WHERE NameDM = 'ALPN'
?