F.18. fuzzystrmatch — определение сходства и расстояния между строками#
F.18. fuzzystrmatch — определение сходства и расстояния между строками #
Модуль fuzzystrmatch
предоставляет несколько функций для определения сходства и расстояния между строками.
Предостережение
В настоящее время функции soundex
, metaphone
,
dmetaphone
и dmetaphone_alt
не работают хорошо с многобайтовыми кодировками (такими как UTF-8).
Используйте daitch_mokotoff
или levenshtein
с такими данными.
Этот модуль считается "доверенным", то есть его можно установить
недоступным пользователям, у которых есть привилегия CREATE
в текущей базе данных.
F.18.1. Soundex #
Система Soundex - это метод сопоставления похожих по звучанию имен, преобразуя их в одинаковый код. Изначально он был использован Всемирной переписью населения США в 1880, 1900 и 1910 годах. Обратите внимание, что Soundex не очень полезен для неанглийских имен.
Модуль fuzzystrmatch
предоставляет две функции для работы с кодами Soundex:
soundex(text) returns text difference(text, text) returns int
Функция soundex
преобразует строку в ее код Soundex.
Функция difference
преобразует две строки в их коды Soundex
и затем сообщает количество совпадающих позиций кодов. Поскольку
коды Soundex имеют четыре символа, результат может быть от нуля до четырех,
где ноль означает отсутствие совпадения, а четыре - точное совпадение. (Таким образом,
функция имеет неправильное название — similarity
было бы
более подходящим названием).
Вот несколько примеров использования:
SELECT soundex('hello world!'); SELECT soundex('Anne'), soundex('Ann'), difference('Anne', 'Ann'); SELECT soundex('Anne'), soundex('Andrew'), difference('Anne', 'Andrew'); SELECT soundex('Anne'), soundex('Margaret'), difference('Anne', 'Margaret'); CREATE TABLE s (nm text); INSERT INTO s VALUES ('john'); INSERT INTO s VALUES ('joan'); INSERT INTO s VALUES ('wobbly'); INSERT INTO s VALUES ('jack'); SELECT * FROM s WHERE soundex(nm) = soundex('john'); SELECT * FROM s WHERE difference(s.nm, 'john') > 2;
F.18.2. Дайч-Мокотофф Саундекс #
Как и оригинальная система Soundex, Daitch-Mokotoff Soundex сопоставляет похожие по звучанию имена, преобразуя их в один и тот же код. Однако Daitch-Mokotoff Soundex значительно более полезна для неанглийских имен, чем оригинальная система. Основные улучшения по сравнению с оригинальной системой включают:
Код основан на первых шести значимых буквах, а не на четырех.
Буква или комбинация букв отображается в десять возможных кодов, а не в семь.
Где две последовательные буквы имеют один звук, они кодируются как одна цифра.
Когда буква или комбинация букв может иметь разные звуки, выдаются несколько кодов, чтобы охватить все возможности.
Эта функция генерирует коды soundex Дайча-Мокотоффа для своего ввода:
daitch_mokotoff(source
text) returns text[]
Результат может содержать один или несколько кодов в зависимости от того, сколько существует правдоподобных произношений, поэтому он представлен в виде массива.
Поскольку код soundex Дайча-Мокотоффа состоит всего из 6 цифр,
source
должен быть предпочтительно одним словом или именем.
Вот несколько примеров:
SELECT daitch_mokotoff('George'); daitch_mokotoff ----------------- {595000} SELECT daitch_mokotoff('John'); daitch_mokotoff ----------------- {160000,460000} SELECT daitch_mokotoff('Bierschbach'); daitch_mokotoff ----------------------------------------------------------- {794575,794574,794750,794740,745750,745740,747500,747400} SELECT daitch_mokotoff('Schwartzenegger'); daitch_mokotoff ----------------- {479465}
Для сопоставления одиночных имен, возвращенные массивы текста могут быть сопоставлены
напрямую с использованием оператора &&
: любое пересечение
может считаться совпадением. Для повышения эффективности может быть использован GIN-индекс, см. Глава 67 и этот пример:
CREATE TABLE s (nm text); CREATE INDEX ix_s_dm ON s USING gin (daitch_mokotoff(nm)) WITH (fastupdate = off); INSERT INTO s (nm) VALUES ('Schwartzenegger'), ('John'), ('James'), ('Steinman'), ('Steinmetz'); SELECT * FROM s WHERE daitch_mokotoff(nm) && daitch_mokotoff('Swartzenegger'); SELECT * FROM s WHERE daitch_mokotoff(nm) && daitch_mokotoff('Jane'); SELECT * FROM s WHERE daitch_mokotoff(nm) && daitch_mokotoff('Jens');
Для индексирования и сопоставления любого количества имен в любом порядке можно использовать функции полнотекстового поиска. См. Глава 12 и этот пример:
CREATE FUNCTION soundex_tsvector(v_name text) RETURNS tsvector BEGIN ATOMIC SELECT to_tsvector('simple', string_agg(array_to_string(daitch_mokotoff(n), ' '), ' ')) FROM regexp_split_to_table(v_name, '\s+') AS n; END; CREATE FUNCTION soundex_tsquery(v_name text) RETURNS tsquery BEGIN ATOMIC SELECT string_agg('(' || array_to_string(daitch_mokotoff(n), '|') || ')', '&')::tsquery FROM regexp_split_to_table(v_name, '\s+') AS n; END; CREATE TABLE s (nm text); CREATE INDEX ix_s_txt ON s USING gin (soundex_tsvector(nm)) WITH (fastupdate = off); INSERT INTO s (nm) VALUES ('John Doe'), ('Jane Roe'), ('Public John Q.'), ('George Best'), ('John Yamson'); SELECT * FROM s WHERE soundex_tsvector(nm) @@ soundex_tsquery('john'); SELECT * FROM s WHERE soundex_tsvector(nm) @@ soundex_tsquery('jane doe'); SELECT * FROM s WHERE soundex_tsvector(nm) @@ soundex_tsquery('john public'); SELECT * FROM s WHERE soundex_tsvector(nm) @@ soundex_tsquery('besst, giorgio'); SELECT * FROM s WHERE soundex_tsvector(nm) @@ soundex_tsquery('Jameson John');
Если требуется избежать пересчета кодов soundex во время повторных проверок индекса, можно использовать индекс на отдельном столбце вместо индекса на выражении. Для этого можно использовать сгенерированный столбец; см. Раздел 5.3.
F.18.3. Левенштейн #
Эта функция вычисляет расстояние Левенштейна между двумя строками:
levenshtein(source text, target text, ins_cost int, del_cost int, sub_cost int) returns int levenshtein(source text, target text) returns int levenshtein_less_equal(source text, target text, ins_cost int, del_cost int, sub_cost int, max_d int) returns int levenshtein_less_equal(source text, target text, max_d int) returns int
И source
и target
могут быть любой непустой строкой, с максимальной длиной 255 символов. Параметры стоимости определяют, сколько стоит вставка, удаление или замена одного символа соответственно. Вы можете опустить параметры стоимости, как во второй версии функции; в этом случае все они устанавливаются по умолчанию равными 1.
levenshtein_less_equal
- это ускоренная версия функции Levenshtein, которая используется, когда интересуют только малые расстояния. Если фактическое расстояние меньше или равно max_d
, то levenshtein_less_equal
возвращает правильное расстояние; в противном случае возвращает значение, большее, чем max_d
. Если max_d
отрицательное, то поведение такое же, как у levenshtein
.
Примеры:
test=# SELECT levenshtein('GUMBO', 'GAMBOL'); levenshtein ------------- 2 (1 row) test=# SELECT levenshtein('GUMBO', 'GAMBOL', 2, 1, 1); levenshtein ------------- 3 (1 row) test=# SELECT levenshtein_less_equal('extensive', 'exhaustive', 2); levenshtein_less_equal ------------------------ 3 (1 row) test=# SELECT levenshtein_less_equal('extensive', 'exhaustive', 4); levenshtein_less_equal ------------------------ 4 (1 row)
F.18.4. Метафон #
Metaphone, как и Soundex, основан на идее создания представительного кода для входной строки. Затем две строки считаются похожими, если у них есть одинаковые коды.
Эта функция вычисляет код метафона входной строки:
metaphone(source text, max_output_length int) returns text
Входной параметр source
должен быть непустой строкой с максимальной длиной 255 символов. Параметр max_output_length
устанавливает максимальную длину кода metaphone в выводе; если длина превышает это значение, вывод будет обрезан до указанной длины.
Пример:
test=# SELECT metaphone('GUMBO', 4); metaphone ----------- KM (1 row)
F.18.5. Double Metaphone #
Система Double Metaphone вычисляет две строки "звучит как" для заданной входной строки - "основную" и "альтернативную". В большинстве случаев они одинаковы, но для неанглийских имен, особенно, они могут немного отличаться в зависимости от произношения. Эти функции вычисляют основной и альтернативные коды:
dmetaphone(source text) returns text dmetaphone_alt(source text) returns text
Входные строки не имеют ограничений по длине.
Пример:
test=# SELECT dmetaphone('gumbo'); dmetaphone ------------ KMP (1 row)