Нечеткий алгоритм поиска (приближенный алгоритм сопоставления строк)
Я хочу создать алгоритм нечеткого поиска.
Однако, в часы исследований я действительно борется.
Я хочу создать алгоритм, который выполняет нечеткий поиск в списке имен школ.
Это то, на что я смотрел до сих пор:
Большинство моих исследований продолжают указывать " строковые показатели" в Google и Stackoverflow, например:
- Расстояние Левенштейна
- Расстояние Дамерау-Левенштейна
- Алгоритм Needleman-Wunsch
Однако это просто дает оценку того, как аналогичные 2 строки. Единственный способ, которым я могу представить его как алгоритм поиска, - это выполнить линейный поиск и выполнить алгоритм строковой метрики для каждой строки и вернуть строки с оценками выше определенного порога. (Первоначально у меня были строки, хранящиеся в дереве, но это, очевидно, мне не поможет!)
Хотя для небольших списков это не такая уж плохая идея, было бы проблематично для списков с разрешением 100 000 имен, и пользователь выполнил много запросов.
Еще один алгоритм, на который я смотрел, - это метод проверки орфографии, где вы просто выполняете поиск всех возможных орфографических ошибок. Однако это также очень неэффективно, так как для слова длиной 7 и количества ошибок всего 2 требуется более 75 000 слов.
Что мне нужно?
Может кто-нибудь, пожалуйста, предложите мне хороший эффективный алгоритм нечеткого поиска. с:
- Название алгоритма
- Как это работает или ссылка на то, как это работает.
- Pro и минусы и когда он лучше всего используется (необязательно)
Я понимаю, что все алгоритмы будут иметь свои плюсы и минусы, и нет лучшего алгоритма.
Ответы
Ответ 1
Учитывая, что вы пытаетесь выполнить нечеткий поиск в списке школьных имен, я не думаю, что вы хотите пойти на традиционное сходство строк, такое как расстояние Левенштейна. Мое предположение заключается в том, что вы принимаете пользовательский ввод (ввод на клавиатуре или разговор по телефону), и вы хотите быстро найти подходящую школу.
Показатели расстояния указывают, как похожие две строки основаны на подстановках, удалениях и вставках. Но эти алгоритмы на самом деле ничего не говорят о том, как строки похожи на слова в человеческом языке.
Рассмотрим, например, слова "кузнец", "smythe" и "smote". Я могу перейти от "smythe" к "кузнецу" в два этапа:
smythe -> smithe -> smith
И от "ударить" до "кузнеца" в два этапа:
smote -> smite -> smith
Таким образом, они имеют то же расстояние, что и строки, но, как слова, они существенно отличаются друг от друга. Если кто-то сказал вам (разговорный язык), что он ищет "Колледж Симте", вы почти наверняка скажете: "О, я думаю, вы имеете в виду Смита". Но если кто-то сказал "Колледж Смотта", вы бы не представляли, о чем он говорит.
Вам нужен фонетический алгоритм, например Soundex или Metaphone. В принципе, эти алгоритмы разбивают слово на фонемы и создают представление о том, как слово произносится на разговорном языке. Затем вы можете сравнить результат с известным списком слов, чтобы найти совпадение.
Такая система будет намного быстрее, чем использование метрики расстояния. Учтите, что с метрикой расстояния вам нужно сравнить пользовательский ввод с каждым словом в вашем списке, чтобы получить расстояние. Это вычислительно дорого, и результаты, которые я продемонстрировал с помощью "кузнец" и "удар", могут быть смехотворно плохими.
Используя фонетический алгоритм, вы создаете представление фонемы каждого из ваших известных слов и помещаете его в словарь (хеш-карту или, возможно, trie). Это одноразовая стоимость запуска. Затем, всякий раз, когда пользователь вводит поисковый запрос, вы создаете представление фонемы своего ввода и просматриваете его в своем словаре. Это намного быстрее и дает гораздо лучшие результаты.
Считайте также, что, когда люди ошибочно набирают имена, они почти всегда получают первую букву вправо, и чаще, чем не произносящие орфографические звуки, похожее на фактическое слово, которое они пытались записать. Если это так, то фонетические алгоритмы, безусловно, способ пойти.
Ответ 2
Вы вводите в заблуждение алгоритмы нечеткого поиска с реализацией: нечеткий поиск слова может возвращать 400 результатов всех слов, которые имеют расстояние Левенштейна, скажем, 2. Но для пользователя вы должны отображать только верхние 5 -10.
Реализация, вы предварительно обработаете все слова в словаре и сохраните результаты в БД. Популярные слова (и их нечеткие) будут сохранены в кэш-слое - поэтому вам не нужно ударять DB для каждого запроса.
Вы можете добавить слой AI, который добавит наиболее распространенные орфографические ошибки и добавит их в БД. И т.д.
Ответ 3
Я написал статью о том, как я реализовал нечеткий поиск:
https://medium.com/@Srekel/implementing-a-fuzzy-search-algorithm-for-the-debuginator-cacc349e6c55
Реализация в Github и в свободном доступе, так что не стесняйтесь взглянуть.
https://github.com/Srekel/the-debuginator/blob/master/the_debuginator.h#L1856
Основы этого: Разделите все строки, которые вы будете искать, на части. Так что если у вас есть пути, то "C:\documents\lol.txt" может быть "C", "Documents", "LOL", "TXT".
Убедитесь, что вы строчные эти строки, чтобы убедиться, что вы не чувствительны к регистру. (Может быть, только если это строка поиска в нижнем регистре).
Затем сопоставьте строку поиска с этим. В моем случае я хочу сопоставить его независимо от порядка, поэтому "loldoc" все равно будет соответствовать указанному выше пути, даже если "lol" следует после "doc".
Соответствие должно иметь некоторую оценку, чтобы быть хорошим. Самая важная часть, которую я считаю, - это последовательное сопоставление, поэтому чем больше совпадают символы, расположенные непосредственно друг за другом, тем лучше. Так что "док" лучше, чем "дсм".
Тогда вы, вероятно, захотите дать дополнительный счет за матч, который начинается в начале части. Таким образом, вы получаете больше очков за "док", чем "Оку".
В моем случае я также даю больше очков для соответствия конца части.
И, наконец, вы можете рассмотреть вопрос о предоставлении дополнительных очков для соответствия последней части (ей). Это делает так, чтобы совпадение с именем файла/конечной оценкой было выше, чем у папок, ведущих к нему.
Ответ 4
Простой алгоритм "нечеткого поиска"
Честно говоря, в некоторых случаях нечеткий поиск по большей части бесполезен, и я думаю, что более простой алгоритм может улучшить результаты поиска, создавая ощущение, что мы все еще выполняем нечеткий поиск.
Вот мой пример использования: фильтрация списка стран с помощью "Нечеткого поиска".
В списке, с которым я работал, были две страны, начинающиеся с Z: Замбия и Зимбабве.
Я использовал Fusejs.
В этом случае при вводе стрелки "zam" в наборе результатов было 19 совпадений, причем наиболее релевантное для любого человека (Замбия) внизу списка. И у большинства других стран в результате даже не было буквы z в их названии.
Это было для мобильного приложения, где вы можете выбрать страну из списка. Это должно было быть очень похоже на то, когда нужно выбрать контакт из контактов телефона. Вы можете отфильтровать список контактов, введя какой-либо термин в поле поиска.
ИМХО, такой ограниченный контент для поиска не должен восприниматься так, чтобы люди спрашивали: "Что за черт?!?".
Можно было бы предложить отсортировать по наиболее подходящему совпадению. Но об этом не может быть и речи в этом случае, потому что тогда пользователю всегда придется визуально находить "Предмет интереса" в сокращенном списке. Имейте в виду, что это должен быть инструмент фильтрации, а не поисковая система "а-ля Google". Таким образом, результат должен быть отсортирован предсказуемым образом. А до фильтрации сортировка была по алфавиту. Таким образом, отфильтрованный список должен быть просто отсортированным по алфавиту подмножеством исходного списка.
Итак, я придумал следующий алгоритм...
- Хватай иглу... в этом случае: ZAM
- Вставьте шаблон
.*
В начале и конце иглы - Вставьте шаблон
.*
Между каждой буквой иглы - Выполните поиск регулярных выражений в стоге сена, используя новую иглу, которая теперь
.*z.*a.*m.*
В этом случае пользователь получит очень ожидаемый результат, найдя все, что каким-то образом имеет буквы z, a и m, появляющиеся в этом порядке. Все буквы в иглах будут присутствовать в спичках в одинаковом порядке.
Это также будет соответствовать названиям стран, таким как Mo**zam**bique
... что идеально.
Я просто думаю, что иногда мы не должны пытаться убить муху с помощью базуки.