pgvector в туториалах (и часто в моих постах тоже) выглядит идеально: добавил расширение, создал индекс, поиск работает – считай вот и внедрили AI на бэкенд 🥂
В большом проде всё иначе. Я смело использую pgvector когда знаю – тут есть, был и будет постгресс, датасет до ~100-200K векторов, и тут не будет резких пивотов и приростов трафика.
Потому что за этими границами резко начинается веселье.
Проблема №1: Бесконечный ад тюнинга индексов
IVFFlat деградирует со временем - у него падает точность поиска, и периодически надо пересобирать. HNSW на огромных датасетах может жрать 10+ гигов оперативки на билд. Для 1M векторов размерности 384 это дело займет минуты, а вот для 10M+ векторов, например, размерности 1536 – часы. При этом ваша база должна продолжать обслуживать запросы.
Решать это можно по всякому, например писать в отдельную таблицу, строить индекс "офлайн", делать свопы. Ну или держать два инекса одновременно ¯\_(ツ)_/¯
pgvector 0.7.0+ улучшил параллельную пересборку для HNSW, но проблема масштаба все равно остается. Настраивать
ef_construction (грубо говоря, это параметр который регулирует "качество" грава HNSW индекса) приходится методом тыка – чем выше значение тем, очевидно - дольше билд.Проблема №2: Планировщик запросов не понимает векторы
Хорошо оптимизированный запрос: ~50ms. Плохо оптимизированный: ~5 секунд. Пу-пу-пу. Разница в 100 раз на одних и тех же данных, потому что планировщик постгресса вообще не понимает кост модели для векторных операций.
Фильтруете после поиска – получаете неполные результаты. Фильтруете до поиска – перебираете миллионы векторов. Золотой середины нет, приходится тюнить каждый запрос руками со всеми вытекающими из остальных пунктов.
Проблема №3: Добавление данных в реальном времени
IVFFlat: быстрые вставки, но без пересборки новые вектора попадают в неоптимальные кластеры – точность поиска деградирует. HNSW: каждая вставка обновляет граф, вызывает блокировки, всплеск записей в базе и снова выжирает память. Ни один из индексов не любит высокую нагрузку на запись, векторные не исключение.
Что в итоге:
Либо раздувается буфер базы в разы (настраивать
maintenance_work_mem и VACUUM помогает, но не сильно), либо принимаете "eventual consistency" (документы не ищутся N минут после добавления), либо строите сложную инфраструктуру с репликами и staging-таблицами/базами (удачи с поиском хорошего dba.)Нужен комбинированный поиск (векторный + полнотекстовый)? Придётся реализовывать самим – взвешивать оценки от разных алгоритмов, нормализовать их, комбинировать результаты (RRF – Reciprocal Rank Fusion один из подходов, но это всё равно код, который надо писать и поддерживать).
Про альтернативы
Специализированные векторные БД (Qdrant, Weaviate, Milvus, Chroma и тд) решают часть проблем, но естественным образом добавляют свой оверхед на поддержку – ещё одна БД в стеке, синхронизация данных, мониторинг и пр. Поэтому я считаю что для небольших проектов с постгрессом в стеке pgvector всё таки разумный выбор.
Я уже писал про Knowledge Graph RAG как альтернативу чёрному ящику векторного поиска. Напомню – близость в векторном пространстве ≠ смысловая связь. А ещё векторный поиск очень сложно дебажить в production. А еще... вы точно уверены что индекс все таки не вырастет x200 раз в течении пары-тройки лет?
Мораль:
pgvector работает. Но его операционная поддержка и особенности (впрочем как и любой другой зависимости в стеке) часто недооценивается на этапе выбора инструментов. Если у вас <100-200K векторов, постоянная инфраструктура и нет хайлоада на запись – смело берите. Дальше считайте TCO с учётом инженерного времени.
Со всем этим планированием и оценкой я помогаю на консультациях, пишите в личку @m0n0x41d
