intermediate
Full-text search
Используйте tsvector, dictionaries, ranking и GIN indexes, когда PostgreSQL search достаточен до search cluster.
Полнотекстовый поиск PostgreSQL токенизирует текст в `tsvector`, сопоставляет через `tsquery`, ранжирует через `ts_rank`. Подходит для product search умеренного масштаба, пока не оправдан Elasticsearch.
ALTER TABLE articles ADD COLUMN search_vector tsvector
GENERATED ALWAYS AS (
setweight(to_tsvector('english', coalesce(title, '')), 'A') ||
setweight(to_tsvector('english', coalesce(body, '')), 'B')
) STORED;
CREATE INDEX idx_articles_fts ON articles USING GIN (search_vector);
SELECT id, title, ts_rank(search_vector, query) AS rank
FROM articles, plainto_tsquery('english', 'postgres indexing') AS query
WHERE search_vector @@ query
ORDER BY rank DESC
LIMIT 20;
Словари задают стемминг и стоп-слова. Префикс — `:*` в tsquery или trigram (`pg_trgm`) для fuzzy. Подсветка — `ts_headline`.
На интервью: pipeline tsvector + GIN; когда FTS достаточно vs отдельный search cluster; как веса влияют на релевантность.
Типовые ошибки: поиск по сырому тексту без индекса; неверный language config; ожидание typo tolerance уровня Google от базового FTS; вектор не обновляется при записи (generated columns или triggers).
Компромисс — простота эксплуатации в PostgreSQL против продвинутой релевантности, анализаторов и горизонтального масштаба search engine.
Чеклист:
- Храните или генерируйте tsvector при записи.
- Индекс GIN (или GiST с другим trade-off).
- Словарь/язык под тип контента.
- Запасной план, если recall или масштаб не хватает.