Встроенный поисковый движок

Встроенный поисковый механизм Tom Select представляет собой комбинацию индексирования данных, текстовой нормализации и скоринговой модели, позволяющей ранжировать варианты без необходимости подключения внешних библиотек полнотекстового поиска. Он рассчитан на работу как с небольшими списками, так и с динамически загружаемыми наборами данных, сохраняя предсказуемое поведение при масштабировании.


Архитектура поиска и базовый поток обработки

Поисковый процесс внутри Tom Select строится вокруг последовательности операций:

  1. Нормализация входной строки запроса
  2. Разбиение текста на токены
  3. Сопоставление токенов с индексируемыми полями объектов
  4. Вычисление веса совпадений
  5. Сортировка по релевантности
  6. Фильтрация результата по порогу значимости

Каждый элемент списка опций рассматривается как объект с набором полей, указанных в searchField. Поиск выполняется не по всему объекту целиком, а по заранее определённым ключам.

new TomSelect("#select", {
  valueField: "id",
  labelField: "title",
  searchField: ["title", "description"]
});

Индексируемые поля и стратегия поиска

Параметр searchField определяет, какие свойства объекта участвуют в поиске. Tom Select не строит полноценный инвертированный индекс, но выполняет предобработку данных для ускорения сравнения.

Особенности:

  • поддерживается несколько полей одновременно
  • поля обрабатываются независимо
  • итоговый скор формируется как сумма вкладов
  • порядок полей влияет на приоритет совпадений

При наличии нескольких полей совпадение в первом поле имеет больший вес, чем во втором, даже при одинаковом тексте.


Нормализация текста и устойчивость к различиям

Перед сравнением строки проходят нормализацию:

  • приведение к нижнему регистру
  • удаление диакритических знаков (при включённой настройке ignoreDiacritics)
  • очистка от лишних символов
  • унификация пробелов

Это обеспечивает устойчивость к различным формам ввода:

  • «München» и «Munchen» рассматриваются как эквивалентные
  • «Москва» и «МОСКВА» имеют одинаковый вес
  • лишние пробелы не влияют на результат

Токенизация и разбиение запроса

Запрос пользователя разбивается на токены по пробелам и знакам пунктуации. Каждый токен рассматривается независимо и сравнивается с индексируемыми строками.

Пример:

"new york city"
→ ["new", "york", "city"]

Поведение зависит от настройки searchConjunction:

  • and — требуется совпадение всех токенов
  • or — достаточно совпадения одного токена

По умолчанию используется режим and, что повышает точность поиска.


Алгоритм скоринга совпадений

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

Основные факторы:

  • позиция совпадения в строке
  • длина совпавшего фрагмента
  • количество совпавших токенов
  • приоритет поля (searchField)
  • точность совпадения (полное или частичное)

Упрощённо скоринг можно представить так:

score = fieldWeight × matchQuality × tokenCoverage

Полное совпадение строки всегда получает максимальный приоритет над частичным.


Сортировка результатов

После вычисления веса все элементы сортируются по убыванию релевантности. Поведение сортировки контролируется параметром sortField.

Пример настройки:

new TomSelect("#select", {
  searchField: ["title"],
  sortField: [
    { field: "title", direction: "asc" }
  ]
});

Если sortField не задан, используется внутренний алгоритм ранжирования, основанный на скоринге поиска.


Фильтрация и пороговые значения

После сортировки применяется фильтрация:

  • удаляются элементы с нулевым скором
  • могут отбрасываться слабые совпадения
  • учитывается минимальная релевантность

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


Поведение при частичном совпадении

Tom Select поддерживает частичные совпадения подстрок. Например:

  • запрос app может совпасть с Apple
  • запрос mic может совпасть с Microsoft

При этом частичные совпадения имеют меньший вес, чем точные или префиксные.

Особое значение имеют:

  • префиксные совпадения (начало строки)
  • полные совпадения токенов
  • совпадения по границам слов

Настройка поиска через custom filter

Поведение поиска может быть полностью переопределено через score и filter.

new TomSelect("#select", {
  score: function(search) {
    return function(item) {
      if (item.disabled) return 0;
      return item.title.includes(search) ? 1 : 0;
    };
  }
});

В этом случае стандартный алгоритм игнорируется, и используется пользовательская логика оценки.


Интеграция с динамической загрузкой данных

При использовании load поиск может выполняться как локально, так и на сервере.

new TomSelect("#select", {
  load: function(query, callback) {
    fetch(`/api/search?q=${encodeURIComponent(query)}`)
      .then(res => res.json())
      .then(data => callback(data));
  }
});

В таком режиме встроенный поисковый движок может использоваться:

  • до запроса на сервер (предфильтрация)
  • после получения данных (локальная сортировка)
  • как fallback при пустом ответе API

Обработка больших наборов данных

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

  • минимизация повторной нормализации строк
  • кеширование промежуточных результатов
  • ранний выход при отсутствии совпадений
  • сокращение числа сравнений через токенизацию

Несмотря на отсутствие полноценного индекса, структура позволяет сохранять приемлемую производительность при среднем объёме данных.


Кэширование результатов поиска

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

Пример поведения:

  • ввод: m
  • затем: ma
  • затем: man

Результаты предыдущих шагов частично переиспользуются, снижая нагрузку на пересчёт скоринга.


Влияние настроек на поисковый движок

На поведение поиска влияют следующие параметры:

  • searchField — область поиска
  • searchConjunction — логика объединения токенов
  • ignoreDiacritics — нормализация символов
  • sortField — сортировка результатов
  • maxOptions — ограничение числа результатов
  • score — кастомная функция оценки

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


Особенности поведения при одинаковых значениях

Если несколько элементов имеют одинаковый скор, применяется дополнительная стабилизирующая сортировка:

  • порядок добавления в список
  • значение sortField при равенстве скоров
  • внутренний индекс элемента

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


Работа с многоязычными данными

Поисковый движок не зависит от языка, но его эффективность определяется качеством нормализации:

  • латиница и кириллица обрабатываются одинаково
  • диакритика удаляется при включённой настройке
  • смешанные строки сравниваются по унифицированному виду

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