Команда разработчиков объединила OpenSearch с SQLite FTS5 и сократила количество поисковых запросов по видео с нулевым результатом с 11,4% до 2,1%, сохранив при этом задержку менее 20 мс. Теперь пользователи, вводя «blackpink jenny solo stag», видят правильный результат «BLACKPINK Jennie SOLO stage» вместо пустого списка.

Почему это изменение было необходимо

Логи поиска видеохостинга выявили повторяющуюся проблему: одна опечатка в названии на латинице могла привести к отсутствию всех совпадений. Расширение SQLite FTS5, ценное своей способностью сопоставлять подстроки в текстах на китайском, японском и корейском (CJK) языках, не поддерживает нечеткий поиск (fuzzy matching). Одна неверно написанная буква в имени или названии песни полностью ломает запрос.

Существующий конвейер рассматривал SQLite как единственный индекс. Он хорошо справлялся с CJK-запросами, но не обеспечивал защиты от опечаток в латинице. Поэтому команда начала искать дополнительный поисковый движок, который мог бы обеспечить устойчивость к опечаткам, не отказываясь от проверенного слоя FTS5.

Как был добавлен OpenSearch

OpenSearch работает как основной поисковый сервис, в то время как SQLite остается первоисточником данных (source of truth). Обе системы работают параллельно: сначала OpenSearch получает пользовательский запрос, и если он отвечает достаточно быстро, отображаются его результаты. Если OpenSearch не успевает ответить или выдает ошибку, запрос перенаправляется на индекс SQLite FTS5. Такая отказоустойчивая (fail-safe) архитектура гарантирует, что сетевой сбой не оставит строку поиска пустой.

Мультиполевой маппинг

Каждое название видео индексируется в OpenSearch тремя способами:

  • title.std – обрабатывается стандартным анализатором с ASCII folding. Это нормализует символы с диакритическими знаками и обрабатывает большинство опечаток в латинице.
  • title.cjk – обрабатывается CJK-анализатором, который создает биграммы (токены из двух символов). Это сохраняет преимущество сопоставления подстрок, которое FTS5 обеспечивает для азиатских языков.
  • title.keyword – хранится без изменений для поиска по точному совпадению и сортировки.

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

Уровни бустинга

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

  1. Точные совпадения фраз в title.keyword получают самый высокий бустинг, гарантируя, что идеальные совпадения будут доминировать в списке.
  2. Совпадения CJK-биграмм в title.cjk получают средний бустинг, сохраняя качество поиска на азиатских языках.
  3. Нечеткие совпадения на латинице в title.std получают более низкий бустинг, что позволяет результатам с опечатками появляться в списке, не вытесняя точные совпадения.

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

Умная нечеткость (Smart fuzziness)

Нечеткость (fuzziness) — возможность допуска ограниченного количества правок символов — применяется только к латинскому полю. Команда отключила fuzziness для title.cjk, так как изменение всего одного символа в CJK часто полностью меняет смысл. Для латинского текста запрос использует настройку AUTO fuzziness в OpenSearch, которая масштабирует допустимое расстояние редактирования в зависимости от длины слова, соблюдая баланс между устойчивостью к ошибкам и релевантностью.

Производительность и логика отката

Процедура поиска оборачивает вызов OpenSearch в блок try-catch:

  • Если OpenSearch возвращает ответ в течение 400 мс, отображаются его результаты.
  • Если вызов вызывает исключение или превышает время ожидания, система немедленно выполняет повторный запрос к SQLite FTS5.

Это гарантирует, что сетевые задержки или сбои сервиса не ухудшат пользовательский опыт. Задержка поиска осталась ниже 20 мс.

Измеримый эффект

  • Доля запросов с нулевым результатом для латиницы упала с 11,4% до 2,1%.
  • Качество поиска для CJK-запросов осталось неизменным, что подтверждает: новый CJK-анализатор сохранил преимущества оригинального индекса FTS5.
  • Сквозная задержка (end-to-end latency) уверенно удерживалась ниже целевого показателя в 20 мс, а значит, добавленный слой не замедлил работу интерфейса.

Уроки и компромиссы

  • Разделение фолдинга и нечеткого поиска – фолдинг (нормализация символов) и fuzziness (обработка опечаток) решают разные задачи. Использование разных полей для них позволяет избежать непредвиденных взаимодействий.
  • Не рассматривайте поисковый индекс как первоисточник – SQLite остается каноническим хранилищем, а OpenSearch — производным, обновляемым представлением. Это предотвращает рассинхронизацию индексов и упрощает восстановление после сбоев.
  • Уровни бустинга упрощают настройку – группировка связанных совпадений под одним коэффициентом бустинга уменьшает количество параметров, требующих корректировки.

Что изучить дальше

Эксперимент доказывает, что даже небольшой слой OpenSearch может значительно повысить устойчивость к опечаткам в многоязычных названиях видео, не жертвуя при этом проверенными возможностями SQLite FTS5 для языков CJK. Для платформ, где релевантность поиска напрямую влияет на время просмотра, такое улучшение становится ощутимым преимуществом для пользовательского опыта.