В зависимости от того, насколько сложным может стать ваш сценарий, это будет много работы, и тоже медленно.Но есть более гибкий подход.Рассмотрим что-то вроде этого, называемое initialTable
:
| id | lastname | firstname |
| 1 | o'malley | josé |
| 2 | omállèy | dònáld |
| 3 | o'neill | jámès |
| 4 | onackers | sharon |
Может быть, немного, но это иллюстрирует общую проблему.Мне пришлось реализовать «нечеткий» поиск для нашего веб-сайта интрасети, основанный на символьных данных, которые выглядели очень похожими - например, во французских или испанских названиях или улицах много акцентов.
Я определил функцию, котораявыполнил все замены для данной строки, например (псевдокод):
function string replacestuff(string input)
{
input = replace(input, "è", "e");
input = replace(input, "é", "e");
input = replace(input, "ò", "o");
input = replace(input, "ó", "o");
input = replace(input, "'", "");
...
return input;
}
Используя эту функцию преобразования, создайте вторую таблицу fuzzyTable
, которая имеет следующее содержимое:
| id | lastname | firstname |
| 1 | omalley | jose |
| 2 | omalley | donald |
| 3 | oneill | james |
| 4 | onackers | sharon |
Теперь предположим, что вы получите строку ввода для поиска josè
.Это не может быть найдено ни в одной таблице.То, что вам нужно сделать, это:
declare @input varchar(50)
declare @input_mod varchar(50)
set @input = 'josè'
set @input_mod = replacestuff(@input)
SELECT id FROM initialTable WHERE firstname like @input OR firstname like @input_mod
UNION
SELECT id FROM fuzzyTable WHERE firstname like @input OR firstname like @input_mod
GROUP BY id
(Конечно, вы должны добавить %
, чтобы LIKE
работал.) Здесь ключ заключается в том, чтобы изменить строку входного поискаиспользуя функцию замены;таким образом, вы получите совпадение, если будете искать sè
с контентом sé
, потому что оба возвращаются к se
при обработке функцией замены.
Вы могли бы даже выполнить двауровень поиска;сначала сравните только неизмененную строку с соответствующей таблицей, а затем с помощью показанного выше оператора выполните нечеткий поиск, если пользователь так говорит.
Это очень гибкий подход, который может обрабатывать все виды вещей, например, поиск немецкого языка.буквы ä, ö, ü, ß с использованием двухбуквенных выражений ae, oe, ue, ss.Недостатком является то, что вам придется хранить дубликаты некоторых данных и изменять их в fuzzyTable при изменении initialTable (или функции замены).В нашем текущем сценарии использования база данных интрасети обновляется один раз в ночь, поэтому это не проблема.
EDIT
Вы должны знать, что, используя это,в некоторых случаях вы получите ложные срабатывания.Например, мы используем это для поиска сотрудников, и если у вас есть голландское имя, написанное Hoek
, вы также найдете это имя в поиске Hök
, потому что в немецком языке замена для ö
будетбыть oe
.Эту проблему можно решить с помощью функций замены, учитывающих особенности страны, но мы никогда не заходили так далеко.В зависимости от ваших входных данных это более или менее академично, для нашего случая использования я не могу вспомнить, чтобы кто-то жаловался.
Основная причина, по которой мы в первую очередь придумали этот подход, заключалась в том, что некоторые данныес которым нам приходилось работать было пронизано орфографическими ошибками, т.е.на французском многие гласные были акцентированы неправильно, но все же нам нужно было добиться результата.