Содержание

Для поиска на сайте с каталогом до сотен тысяч записей обычно хватает встроенного полнотекстового поиска PostgreSQL. Отдельный движок — Meilisearch или Elasticsearch — нужен, когда важны мгновенный поиск по мере ввода, устойчивость к опечаткам, сложные фильтры с подсчётом и релевантность, которую настраивают без программиста.

Разберём, чем плох поиск через LIKE, что умеет база данных, когда переходить на отдельный движок и как сделать поиск удобным.

Почему LIKE — это не поиск?

Запрос с LIKE '%слово%' ищет точное совпадение подстроки: он не понимает формы слов, не прощает опечаток, не сортирует по релевантности и на больших таблицах не использует обычные индексы. Пользователь ищет «красные кроссовки», а в базе «кроссовок красного цвета» — и получает пустую страницу.

Нормальный поиск должен уметь:

  • находить разные формы слова: «кроссовки», «кроссовок», «кроссовкам»;
  • прощать опечатки и неправильную раскладку;
  • сортировать результаты по релевантности, а не по дате;
  • учитывать синонимы и сокращения;
  • совмещать текстовый запрос с фильтрами по цене, категории и наличию.

Что умеет полнотекстовый поиск PostgreSQL?

PostgreSQL умеет искать по словам с учётом морфологии, ранжировать результаты и использовать для этого индекс. Для нечёткого поиска по опечаткам подключают расширение триграмм. Плюс подхода — не нужна отдельная система: данные и поиск в одном месте, синхронизировать ничего не надо.

ALTER TABLE products ADD COLUMN search tsvector
  GENERATED ALWAYS AS (
    setweight(to_tsvector('russian', coalesce(title, '')), 'A') ||
    setweight(to_tsvector('russian', coalesce(description, '')), 'B')
  ) STORED;

CREATE INDEX products_search_idx ON products USING GIN (search);

SELECT id, title, ts_rank(search, query) AS rank
FROM products, websearch_to_tsquery('russian', 'красные кроссовки') query
WHERE search @@ query
ORDER BY rank DESC
LIMIT 20;

Подробнее про индексы — в статье индексы в PostgreSQL, а про выбор СУБД — в материале PostgreSQL или MySQL.

Книжные полки в круглой библиотеке Фото: Unsplash

Когда нужен отдельный поисковый движок?

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

Критерий PostgreSQL Meilisearch Elasticsearch / OpenSearch
Отдельная инфраструктура Не нужна Один сервис Кластер
Опечатки Через расширение Из коробки Настраивается
Поиск по мере ввода Возможен, но сложнее Из коробки Настраивается
Фасеты и подсчёт по фильтрам Вручную Из коробки Из коробки
Объём данных До миллионов строк Миллионы документов Очень большие объёмы, логи
Сложность поддержки Низкая Низкая Высокая

Meilisearch и похожие движки хороши для каталогов и сайтов: их быстро подключить, а качество из коробки высокое. Elasticsearch и OpenSearch выбирают, когда данных очень много, нужна сложная аналитика или поиск по логам.

Как синхронизировать данные с поисковым индексом?

Данные синхронизируют через события: при создании, изменении или удалении записи в базе фоновая задача обновляет документ в индексе. Источником правды остаётся база данных, а индекс в любой момент можно перестроить с нуля.

Правила синхронизации:

  1. Обновляйте индекс через очередь, а не прямо в запросе пользователя.
  2. Держите команду полной переиндексации — она понадобится при изменении настроек.
  3. Индексируйте только поля, по которым ищут и фильтруют, а не всю запись.
  4. Следите за отставанием индекса от базы и ошибками задач.

Как сделать поиск удобным для пользователя?

Поиск удобен, когда он отвечает быстро, понимает человеческие формулировки и не оставляет пустую страницу. Даже идеальная технология не спасёт, если в данных нет нужных слов, а результаты нельзя отфильтровать.

Что помогает:

  • подсказки по мере ввода и исправление раскладки;
  • синонимы: «ноутбук» и «лэптоп», «телефон» и «смартфон»;
  • фильтры с количеством результатов рядом с каждым значением;
  • вместо пустой страницы — похожие товары или популярные категории;
  • аналитика запросов без результатов, чтобы дополнять данные и синонимы.

Как собирать такие данные, мы разбирали в статье продуктовые метрики после запуска.

Коротко

  • LIKE не понимает формы слов, опечатки и релевантность — это не поиск.
  • Для большинства сайтов хватает полнотекстового поиска PostgreSQL.
  • Отдельный движок нужен, когда поиск — ключевая функция: мгновенные подсказки, опечатки, фасеты.
  • Индекс обновляют через очередь, а база остаётся источником правды.
  • Качество поиска улучшают синонимы, фильтры и анализ запросов без результатов.

Частые вопросы

  • Поддерживает ли поиск PostgreSQL русский язык?

    Да, в PostgreSQL есть словари для русского языка: поиск учитывает разные формы слов. Опечатки из коробки он не исправляет, для этого подключают расширение для нечёткого поиска по триграммам.

  • Сколько стоит отдельный поисковый движок?

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

  • Как понять, что поиск работает плохо?

    Смотрите на запросы без результатов и на долю поисков, после которых пользователь ничего не открыл. Эти два отчёта быстро показывают, каких синонимов и данных не хватает.