Indexium/docs/adr/003-search-engine.md

3.1 KiB
Raw Blame History

ADR-003: Использование PostgreSQL FTS и pg_trgm вместо Meilisearch/Elasticsearch

Дата: 2026-09-06
Статус: Принято

Контекст

Для поиска модов по названию, описанию и авторам требуется полнотекстовый поиск и устойчивость к опечаткам (fuzzy search). Введение отдельного движка поиска (Meilisearch, OpenSearch, Elasticsearch) усложняет инфраструктуру и увеличивает потребление RAM (ещё один сервис в docker-compose, отдельный индекс, синхронизация).

На MVP ожидается <50k модов, поисковый трафик <100 RPS, VPS за $5–10.

Решение

Использовать возможности PostgreSQL 16:

  • tsvector + GIN-индексы для ранжированного полнотекстового поиска (to_tsvector, ts_rank, plainto_tsquery).
  • Расширение pg_trgm для поиска с опечатками (Trigram Similarity, оператор %, similarity()).
  • Материализованный search_vector с триггером на INSERT/UPDATE (см. docs/database-schema.md).

Запрос: search_vector @@ plainto_tsquery + фильтр по mod_versions (GIN (game_versions, loaders)) + ORDER BY ts_rank DESC + fallback similarity() при 0 результатах.

Последствия

  • Плюсы: Нет дополнительных сервисов в docker-compose, экономия памяти (~0 доп. RAM vs +500MB–1GB у Meilisearch), атомарные транзакции при обновлении индекса (нет лагосинка), проще бэкапы.
  • Минусы: При объёме >500k записей или >500 RPS скорость FTS в Postgres начинает уступать специализированным движкам (latency >100ms, нет typo-tolerance из коробки как в Meilisearch).
  • План миграции: Если p95 latency поиска превысит 100ms (метрика в tracing + Grafana), вынести индекс в Meilisearch: добавить воркер-синк mods → Meilisearch, переключить GET /mods на Meilisearch с fallback на Postgres. Схема БД не меняется.

Альтернативы (отклонены на MVP)

  • Meilisearch — отличный typo-tolerance, но +1 сервис, нужен отдельный деплой и синк.
  • Elasticsearch / OpenSearch — оверхед по RAM/диску, нужен кластер даже для малого объёма.
  • SQLite FTS — не подходит, уже Postgres как основной.

Ссылки

  • docs/database-schema.md — секция 2 (триггер mods_search_vector_update), секция 3 (примеры FTS + fuzzy).
  • docs/architecture.md — секция 4 (Поиск без Elasticsearch).