Приходилось ли работать с полнотекстовым поиском
Что проверяют
Знаете ли вы, что в Go поиск обычно не пишут, а подключают, и понимаете ли последствия выбора. Главная развилка простая: индекс живёт внутри процесса или в отдельном сервисе, и что с этим станет при второй реплике приложения.
Как отвечать
Начните с вводных: объём корпуса, язык документов, требования к свежести индекса и к отказоустойчивости. Дальше варианты:
- данные уже в PostgreSQL и объём умеренный:
tsvectorс индексом GIN, поднимать новое хранилище не нужно; - нужен полноценный движок: Elasticsearch или OpenSearch через официальный клиент, из более простых Meilisearch и Typesense;
- Bleve, если индекс живёт в одном процессе: это встраиваемая библиотека без кластера, хороша для единственного узла или локального индекса справочника.
Со стороны Go расскажите инженерную часть, её и спрашивают: индексация пачками через bulk-запросы с ограничением размера пачки, пул воркеров с errgroup и лимитом параллелизма, context с таймаутом на каждый запрос к движку, повторы с отступом на временных ошибках, отдельная метрика отставания индекса от базы.
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()Синхронизацию опишите через очередь или таблицу исходящих сообщений: запись в базу и в индекс подряд в одном обработчике расходится при первом же сбое.
Где спотыкаются
Берут встраиваемый индекс, а сервис потом раскатывают в несколько реплик. У каждой свой файл индекса, выдача зависит от того, на какой экземпляр попал запрос, а переиндексацию надо делать везде одновременно.
Второе: индексируют по одному документу на каждое изменение. Накладные расходы на запрос убивают пропускную способность, тогда как пачка из нескольких сотен документов проходит на порядок быстрее.
Третье: ходят в движок без таймаута и без ограничения размера выдачи. Один тяжёлый поиск держит горутину и соединение, под нагрузкой это выливается в исчерпание пула и каскад ошибок во всём сервисе.