← все задачи

Задача 7 из 10

Поиск по каталогу

Спроектируйте поиск по каталогу товаров: пользователь вводит запрос, подсказки появляются на лету, а по Enter открывается релевантная выдача с фильтрами.

Уровень: Средний На собеседовании: 45–60 минут поисковый индексCDC и outboxотставание данных

Функциональные требования

  • Поиск по названию и описанию, устойчивый к опечаткам
  • Подсказки по мере ввода
  • Фильтры (категория, цена, наличие) и сортировка
  • Новый или изменённый товар быстро появляется в поиске

Нефункциональные требования

  • 5 млн товаров, 3000 поисков/с в пик
  • Подсказка отвечает за 50 мс, выдача — за 200 мс
  • Изменение товара доезжает до поиска в течение минуты
  • Индекс может отставать от БД, но не имеет права терять товары

Нарисуйте архитектуру

Не гонитесь за красотой: на собеседовании от схемы нужно, чтобы по ней было видно путь запроса и где лежат данные. Сначала нарисуйте сами — эталон и разбор ниже.

Блок из палитры — добавить. Тащите мышкой или пальцем. Двойной клик по названию — переименовать. «Связь» — щёлкнуть по одному блоку, потом по другому: получится стрелка.

Схема сохраняется в этом браузере — вкладку можно закрыть и вернуться позже.

1 С чего начать, если ступор
  • Объясните, почему LIKE «%запрос%» по основной БД не работает на 5 млн товаров.
  • Поисковый индекс — отдельное хранилище, значит появляется задача его наполнять.
  • Синхронизация: писать в индекс из приложения или ловить изменения из БД (CDC / outbox)?
  • Подсказки и полнотекстовый поиск — разные задачи с разными требованиями по латентности.
  • Продумайте переиндексацию: что происходит, когда индекс нужно построить заново.
2 Эталонная схема

Поиск живёт в отдельном индексе, а не в основной БД. Изменения товаров доезжают до индекса через очередь, поэтому индекс всегда чуть отстаёт — по требованиям это допустимо. Карточку товара при этом отдаёт каталог из основной БД, где данные точные.

Это один из рабочих вариантов, а не единственно верный. Если у вас иначе, но вы можете объяснить почему — на собеседовании это ровно то, что нужно.

3 Разбор: что должно прозвучать

Почему не искать в основной БД

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

Наполнение индекса

  • Двойная запись из приложения (в БД и в индекс) рассинхронизируется при любом сбое между ними
  • Outbox: событие пишется в одной транзакции с товаром, отправляет его отдельный процесс
  • CDC из журнала БД — вариант без изменения кода приложения

Отставание индекса

  • Требование «в течение минуты» разрешает асинхронность — на это стоит опереться явно
  • Сразу после сохранения товар может не находиться: продавцу это надо объяснить в интерфейсе
  • Карточку товара читаем из БД, а не из индекса: там цена и наличие должны быть точными

Подсказки

  • Отдельный лёгкий индекс под префиксы, а не полнотекстовый поиск
  • Требование 50 мс жёстче, чем у выдачи, — здесь агрессивный кэш популярных префиксов
  • Подсказки можно строить по логу запросов, а не только по названиям товаров

Фильтры и пагинация

  • Фильтры и сортировка считаются в индексе — иначе придётся вытаскивать всё в приложение
  • Глубокая пагинация в поисковых движках дорогая: обычно ограничивают глубину
  • Наличие и цена меняются часто — иногда их держат отдельно и подмешивают при выдаче

Куда копать дальше, если спросят

  • Переиндексация без даунтайма через алиасы: строим новый индекс, переключаем указатель
  • Оценка релевантности и A/B-эксперименты над ранжированием
  • Что делать, если индекс потерян целиком — сколько занимает полная переиндексация
  • Персонализация и региональность выдачи

Следующая задача: Оплата заказа

Деньги нельзя ни потерять, ни списать дважды. Распределённой транзакции с банком не существует — отсюда идемпотентность, outbox и сага.