Умный поиск

Поиск подстроки подходит для простых запросов, но не находит значение, в котором части многословного запроса разделены другими символами. Например, по запросу 10.125 all он не находит 10.125.123.0/24 - all, хотя оба фрагмента есть в значении.

Умный поиск разбивает многословный запрос на токены и ищет каждый токен отдельно. Поэтому он находит значения, соответствующие запросу.

Функции normalizeSearchValue, tokenizeSearchQuery и createSearchPredicate из @koobiq/components/core реализуют эти принципы. Реализация подключается по желанию и не меняет поведение компонентов по умолчанию. Ее можно добавить в собственную логику фильтрации.

Поиск с учетом регистра считает строки разными из-за различий в регистре, хотя они совпадают по смыслу. При сравнении WORLD, world и World приводятся к одному значению.

Алгоритм удаляет пробелы в начале и конце введенной строки. Внутренние пробелы сохраняются: их удаление или схлопывание может изменить смысл фразы.

Многословный запрос разбивается на независимые токены. Значение считается совпадением, только если в нем найдены все токены.

Порядок токенов не важен. Например, запросы 10.125 all и all 10.125 находят значение 10.125.123.0/24 - all.

Текст в двойных кавычках считается одним токеном. Пробелы внутри него участвуют в сравнении, поэтому запрос в кавычках требует точного совпадения фразы.

Минимальная длина токена не задана. Например, токен a находит all.

Диакритические знаки — это пометки над, под или внутри букв. К ним относятся, например, знаки в é, ü и ç.

Умный поиск отделяет диакритические знаки от базовых букв и сравнивает результат без них. Поэтому значение Café Wi-Fi находится по запросам cafe и café, независимо от того, какой вариант введен.

Пунктуация не удаляется. Символы /, - и . сохраняются, поэтому IP-диапазоны и похожие значения не изменяются.

Подсветка совпадений также должна учитывать свертку диакритических знаков. У функций kbqHighlightBackground и mcHighlight есть аргумент foldDiacritics. Передайте ему значение true, если ключевые слова сопоставлялись со сверткой, например через createSearchPredicate. Тогда запрос cafe подсветит Café.

Какие поля участвуют в поиске, определяет вызывающий код. Это зависит от структуры данных.

Токен считается найденным, если он совпал хотя бы с одним полем. Все токены должны найтись хотя бы в одном из полей:

const matches = createSearchPredicate('10.125 guest');

matches(['10.125.11.0/24', 'guest network']); // true — «10.125» найден в первом поле, «guest» — во втором
matches(['10.125.11.0/24', 'production']); // false — «guest» не найден ни в одном поле

Логика сопоставления определяет, соответствует ли значение запросу, но не ранжирует результаты.

Если результаты нужно упорядочить по релевантности, добавьте отдельный алгоритм ранжирования:

const tokens = tokenizeSearchQuery(query);
options.filter(createSearchPredicate(query)).sort(rankByRelevance(tokens));

Умный поиск не исправляет опечатки. Например, запрос developr не находит developer.

Поиск по расстоянию редактирования — отдельная задача. Для нее лучше использовать специализированную библиотеку нечеткого поиска, чем расширять собственную логику сопоставления.

На страницах компонентов показано, как подключить умный поиск: Autocomplete, Dropdown, Filter bar, Select, Tag autocomplete, Timezone, Tree select.

Предложения по улучшению
Если вы нашли ошибку или хотите доработать статью, создайте запрос на GitHub.