Векторное хранилище для корпоративного RAG: pgvector против Qdrant на 500K документов
Выбираем между pgvector в существующем PostgreSQL и отдельным Qdrant для RAG-пайплайна над корпоративной базой знаний - смотрим на производительность, операционку и компромиссы.
Появление production-готовых векторных СУБД (Qdrant, Weaviate, pgvector) для RAG-пайплайнов, осень 2023
В октябре мы строили RAG поверх внутренней документации клиента на примерно 300 markdown-файлах и взяли ChromaDB - встраиваемая, без операционной нагрузки, для такого объёма достаточно. Но у другого клиента задача на порядок крупнее: корпоративная база знаний, накопленная за несколько лет, - порядка полумиллиона фрагментов после чанкования. Тут ChromaDB уже не вариант, и вопрос «что взять» встал по-настоящему.
Откуда документы и что от системы хотят
Клиент - средний производственный холдинг. Документация разнородная: технические регламенты, инструкции по оборудованию, внутренние стандарты, итоги совещаний в PDF, переписка по согласованиям, эксплуатационные журналы. Всё это скапливалось в разных системах - часть в Confluence, часть в файловой шаре, часть в самописном DMS.
После индексации и чанкования на 512-токенные фрагменты с перекрытием 64 токена получилось около 500-520 тысяч векторов размерностью 768 (эмбеддинг-модель - multilingual-e5-large, нормально работает с русским). Требование к поиску: топ-10 по косинусному сходству за разумное время, под нагрузкой несколько десятков одновременных запросов.
Инфраструктурно у клиента уже есть PostgreSQL 15 - это важно. Видеть вторую БД в продакшне никто не хочет, если можно без неё обойтись.
Кандидаты
Смотрели на три варианта:
- pgvector в существующем PostgreSQL. Расширение, добавляет тип vector и индексы HNSW/IVFFlat. Плюс очевиден: нет нового сервиса, транзакции, знакомые инструменты, PgBouncer уже настроен.
- Qdrant - специализированная векторная СУБД, написанная на Rust, с REST и gRPC API. Позиционирует себя как production-ready, активно развивается весь 2023 год, у версии 1.x достаточно стабильный API.
- Weaviate смотрели мельком - архитектура интересная, но Go-стек и более тяжёлая операционка под нашу ситуацию не подошли. Убрали из сравнения.
Тестовый стенд
Одна физическая машина: 32 ядра, 128 GB RAM, NVMe. PostgreSQL 15 + pgvector 0.5.1. Qdrant 1.6.1 в Docker, дал ему 40 GB RAM через --memory. Векторов - 500K, размерность 768.
Для pgvector построили индекс HNSW с параметрами m=16, ef_construction=64. Для Qdrant - HNSW с теми же m=16, ef=64. Сравнивали в одинаковых условиях.
Что увидели по производительности
Честно говоря, pgvector приятно удивил. На одиночных запросах (топ-10, косинусное расстояние) задержка вполне конкурентоспособная - у обеих систем цифры в одном диапазоне при холодном кеше. Qdrant быстрее именно при параллельной нагрузке: при нескольких десятках одновременных запросов latency у pgvector начинает расти сильнее - PostgreSQL всё-таки строчно-ориентированная СУБД, и векторный поиск конкурирует с обычными OLTP-транзакциями за пул соединений.
Конкретные числа приводить не будем - у другого клиента на другом железе они будут другие, и это плохая привычка. Но соотношение такое: одиночные запросы - близко, параллельная нагрузка - Qdrant держит форму лучше.
Потребление памяти под нагрузкой у Qdrant заметно выше: HNSW-граф хранится в RAM, и для 500K векторов размерностью 768 это несколько гигабайт только под индекс. pgvector работает в рамках shared_buffers и ОС-кеша, что при правильной настройке PostgreSQL даёт предсказуемое поведение.
Где pgvector проигрывает не по скорости
Фильтрация по метаданным - вот где разрыв принципиальный. В реальном RAG-пайплайне редко ищут «по всему корпусу»: нужно «найди похожее, но только в документах отдела X за последний год» или «только по категории Регламенты».
В pgvector фильтрация реализована через WHERE на обычные столбцы. Проблема в том, что HNSW-индекс не умеет pre-filter - сначала векторный поиск, потом фильтрация результатов. Если фильтр убивает большую часть корпуса, эффективность падает, и планировщик PostgreSQL может принять плохое решение по порядку операций.
Qdrant изначально проектировался с filtered search: фильтры применяются во время обхода графа, что при избирательных фильтрах даёт качественно другой результат. Для нашего случая с разнородной документацией разных отделов это важно.
Операционная сторона
Аргумент «pgvector не требует нового сервиса» реальный, но не абсолютный.
Плюсы pgvector: всё знакомо. Мониторинг уже есть, бэкапы настроены, команда умеет, pg_dump работает. Добавление векторного поиска - это одна строчка в миграции и одно расширение.
Плюсы Qdrant: изоляция нагрузки. Тяжёлый векторный поиск не конкурирует с операционными транзакциями. Отдельное масштабирование. Snapshots встроены в API. Плюс у Qdrant есть понятие collection, которое хорошо ложится на логическое разделение корпусов по отделам - проще управлять правами доступа на уровне коллекций.
Минусы Qdrant: ещё один сервис со своим жизненным циклом, бэкап отдельно от PostgreSQL, мониторинг надо настраивать с нуля. Для небольшой команды ops это реальная нагрузка.
Что решили
Взяли Qdrant. Решающими оказались два аргумента: фильтрация по метаданным важна для этого клиента (документы разных отделов с разными правами доступа), и объём достаточно большой, чтобы изоляция нагрузки имела смысл.
Если бы корпус был 50-100K фрагментов и весь однородный - pgvector был бы очевидным выбором. Его возможностей для многих реальных задач хватает, а операционная простота - не мнимое преимущество.
Qdrant запущен как отдельный контейнер на том же хосте, что и PostgreSQL, с отдельным томом. Для аналитической инфраструктуры такого масштаба это рабочий компромисс - не разносить по разным машинам без явной необходимости, но и не смешивать нагрузку в одном процессе.
Текущий статус
RAG-пайплайн в активной разработке. Векторная часть работает, индексация документов запущена. Следующий вопрос - качество поиска: какая модель эмбеддинга лучше работает на технических текстах вперемешку с бюрократическими PDF, и как чанкование влияет на recall. Это отдельная тема, туда и пойдём.