Векторные базы данных: зачем они нужны и когда не нужны

Что такое векторные базы данных, как работают эмбеддинги, какие задачи действительно требуют специализированного хранилища и когда достаточно pgvector или встроенного поиска

Векторные базы данных — один из самых горячих классов инструментов последних лет. Интерес к ним вырос вместе с LLM и RAG-паттерном, но сами по себе векторные индексы и поиск по сходству (similarity search) существуют куда дольше нынешнего хайпа. Поэтому правильный вопрос — не «нужна ли мне векторная БД», а какую именно задачу она решает и где более простые альтернативы справляются не хуже.

Эта статья — не каталог движков и не бенчмарк с цифрами. Она про то, как подходить к выбору инженерно: понимать, что стоит за словом «эмбеддинг», почему приблизительный поиск — это осознанный компромисс, а не недостаток, и по какой лестнице вопросов двигаться прежде чем тянуть в стек отдельное хранилище. Это вход в серию: каждый слой — эмбеддинги, ANN-индексы, конкретные движки — планируется разобрать отдельно и вглубь в следующих статьях.

Маскот-библиотекарь в стиле «Полдень. XXI век» стоит в уютном зале-гибриде библиотеки и дата-центра с раскрытой светящейся книгой в руках. Вокруг парят светящиеся книги, сгруппированные по цвету — розовые к розовым, синие к синим, зелёные к зелёным: похожее по смыслу оказывается рядом. Слева тёплый деревянный книжный шкаф, справа за порогом — холодный высокотехнологичный сейф со светящимися ячейками: два варианта, куда положить данные

В статье

Что такое эмбеддинг и семантический поиск

В основе всего лежит одна идея: модель превращает текст, картинку или аудио в вектор — точку в пространстве из нескольких сотен или тысяч измерений. Это и есть эмбеддинг. Ключевое свойство, ради которого всё затевается: смысловая близость превращается в геометрическую. «Кот» и «кошка» окажутся точками рядом друг с другом, а «кот» и «квартальный отчёт» — далеко. Найти похожее по смыслу теперь означает найти ближайшие точки в этом пространстве — это и называют семантическим поиском, в отличие от поиска по точному совпадению слов.

Размерность вектора — 384, 768, 1536 и другие похожие числа, которые встречаются в описаниях моделей, — это просто количество чисел, которыми описана точка. Большая размерность даёт модели больше ёмкости под оттенки смысла, но сама по себе качества не гарантирует: насколько хорошо ловится смысл, зависит от модели, её обучения, домена, языка и метрики близости, и проверяется только на конкретной задаче. При этом каждое лишнее измерение — это дополнительная память и вычисления на каждый вектор, так что «больше» не значит «лучше по умолчанию». Как именно эти числа получаются внутри модели и почему близость измеряют косинусом или евклидовым расстоянием — детали, которые для выбора инструмента не обязательны; здесь достаточно интуиции «данные стали точками, похожее — рядом».

Эмбеддинги для русскоязычной аудитории. Основной путь — открытые мультиязычные модели с Hugging Face, которые поднимаются у себя: например, multilingual-e5 или BGE-M3. Запускают их обычно через Sentence Transformers или родные библиотеки вроде FlagEmbedding. Они работают с русским языком и не привязывают проект к конкретному облаку; за сам доступ к модели платить не нужно, но инференс на своих GPU или CPU — это уже своя эксплуатационная стоимость, которую стоит закладывать. Удобная альтернатива — российские облачные API, например GigaChat Embeddings или YandexGPT Embeddings: не нужно поднимать инфраструктуру, но появляется зависимость от внешнего сервиса и плата за запросы. Как ещё один вариант — зарубежные API вроде OpenAI или Cohere. Какой из вариантов точнее именно на ваших текстах — вопрос, который решается замером на своём датасете, а не общими рекомендациями: у моделей разные сильные стороны по языкам и доменам. Выбор конкретной модели, её обновление и то, как со временем «плывут» уже посчитанные эмбеддинги, — тема отдельного разговора: эмбеддинги в проде: выбор модели, дрейфСкоро.

Приблизительный поиск — это компромисс

Раз данные стали точками, найти похожее можно в лоб: сравнить запрос с каждой точкой в базе и взять ближайшие. Это точный поиск (exact kNN), и с ним есть одна проблема — сравнение со всеми линейно дорожает по мере роста числа векторов. На практике вместо этого почти всегда используют приблизительный поиск (ANN, approximate nearest neighbors): он находит почти всех нужных соседей на порядки быстрее точного перебора, но время от времени кого-то из по-настоящему ближайших пропускает.

Именно этот размен — точность против скорости и памяти — и есть центральная тема всей области векторного поиска. Крутить его ручки в ту или иную сторону приходится в любом проекте, который выбирает векторную БД или индекс: чуть точнее — чуть медленнее и прожорливее по памяти, и наоборот. Как именно устроены индексы вроде HNSW и IVF и что делает с векторами квантизация — отдельный и более глубокий разговор: ANN вглубь: HNSW, IVF, PQСкоро.

Нужна ли вообще: лестница выбора

Правильный порядок вопросов — не «какую векторную БД взять», а «нужен ли тут вообще поиск по смыслу, а если да — хватит ли того, что уже стоит в стеке». Это лестница из трёх ступеней, и подниматься по ней стоит снизу вверх.

flowchart TD A["Нужен поиск по смыслу,
а не по совпадению слов?"] -->|"Нет"| B["Полнотекстовый поиск,
теги, фильтры"] A -->|"Да"| C{"Объём и требования"} C -->|"Порядка миллиона векторов,
низкий/средний QPS, простые фильтры,
PG или OpenSearch уже есть"| D["Встроенное:
pgvector / k-NN / Redis"] C -->|"Миллионы+, гибрид,
фильтрация, SLA"| E["Выделенная:
Qdrant / Milvus / Weaviate"]

flowchart TD
    A["Нужен поиск по смыслу,
а не по совпадению слов?"] -->|"Нет"| B["Полнотекстовый поиск,
теги, фильтры"] A -->|"Да"| C{"Объём и требования"} C -->|"Порядка миллиона векторов,
низкий/средний QPS, простые фильтры,
PG или OpenSearch уже есть"| D["Встроенное:
pgvector / k-NN / Redis"] C -->|"Миллионы+, гибрид,
фильтрация, SLA"| E["Выделенная:
Qdrant / Milvus / Weaviate"]
Лестница выбора: сначала — нужен ли поиск по смыслу вообще, затем — хватит ли встроенного в текущий стек, и только потом — выделенная база

Часто не нужна вовсе

Если задачу решают полнотекстовый поиск, теги и атрибутивные фильтры, векторы только добавят сложности. Векторный поиск оправдан там, где важен смысл, а не совпадение слов: «похожие товары», «найди по описанию своими словами», семантический FAQ. Если такой задачи нет — нет и повода тянуть в стек векторную БД.

Встроенного часто хватает

Если PostgreSQL уже стоит в проекте, pgvector добавляет векторный поиск той же командой SQL, в той же транзакции, с тем же бэкапом — без нового stateful-компонента в инфраструктуре. На практике это выглядит буквально как ещё одна колонка и ORDER BY по расстоянию:

CREATE EXTENSION IF NOT EXISTS vector;

-- вектор живёт обычной колонкой рядом с остальными полями таблицы
CREATE TABLE documents (
    id        bigserial PRIMARY KEY,
    title     text,
    lang      text,
    embedding vector(768)   -- 768 — размерность выбранной модели эмбеддингов
);

-- эмбеддинг кладётся тем же INSERT/UPDATE, что и любое другое поле
UPDATE documents SET embedding = :embedding WHERE id = :id;

-- поиск похожих: ORDER BY по расстоянию, <=> — косинусное расстояние.
-- Обычные WHERE-фильтры и JOIN работают ровно как всегда.
-- Без индекса это точный перебор (exact scan); индексы HNSW/IVFFlat — дальше в серии.
SELECT id, title
FROM documents
WHERE lang = 'ru'
ORDER BY embedding <=> :query_embedding
LIMIT 10;

Никакого отдельного клиента, протокола или сервиса — тот же коннект к Postgres, что и для всего остального. То же касается k-NN в OpenSearch или векторного поиска в Redis, если один из них уже есть в стеке. Практический порог здесь — это порядок величины, а не точное число: где-то около миллиона векторов, но конкретная граница гуляет в зависимости от размерности эмбеддингов, требуемого QPS, доступной RAM, сложности фильтров и целевого recall. Ниже этого масштаба встроенного обычно хватает; выше — стоит смотреть предметно, по своей нагрузке. Что происходит с pgvector на больших объёмах и как выжать из него больше: pgvector вглубьСкоро.

Когда нужна выделенная

Набор условий, при котором стоит смотреть в сторону выделенной базы, обычно такой: миллионы и больше векторов; гибридный поиск (смысл вперемешку с ключевыми словами); сложная фильтрация без заметного недобора (recall); требования к throughput и SLA. В этих сценариях выделенные движки вроде Qdrant, Milvus или Weaviate дают более специализированные механики эксплуатации, фильтрации, гибридного поиска и масштабирования.

Важно, что дело не в «умеет / не умеет»: встроенные решения тоже делают векторный поиск — pgvector поддерживает и точный, и приблизительный поиск, косинусное расстояние <=>, JOIN и всё остальное из Postgres; Redis и OpenSearch — тоже. Разница в том, насколько глубоко эти механики проработаны под нагрузку. И компромиссы никуда не деваются — фильтрация в ANN всё равно имеет свою цену, — просто в выделенном движке она управляется аккуратнее.

Разбор самих движков: Qdrant, Milvus, WeaviateСкоро. А выбор «pgvector или выделенная база» как отдельное инженерное решение, со своими критериями: pgvector или выделенная базаСкоро.

Ступени этой лестницы проходят снизу вверх, а не наоборот: начинать с выделенной базы ради десяти тысяч документов значит платить за проблему, которой нет.

Типичные ошибки — они же «когда не нужны»

За разбором лестницы выбора стоит несколько ошибок, которые на практике встречаются чаще прочих.

Выбор базы раньше, чем понятны объём данных и паттерн запросов. Правильный порядок — сначала посчитать, сколько объектов предстоит хранить, как часто и какими запросами их ищут, и только потом выбирать инструмент под эту нагрузку. Выбор в обратном порядке — сначала модная база, потом попытка подогнать под неё задачу — почти всегда добавляет сложности без пользы.

Игнор качества эмбеддингов. Если модель подобрана небрежно или векторы посчитаны не для того языка и домена, никакой индекс — ни HNSW, ни IVF, ни самый точный ANN-алгоритм — не вытащит смысл, которого в векторах нет. Мусор на входе даёт мусор на выходе, и для векторного поиска это особенно верно: качество поиска ограничено сверху качеством эмбеддингов, а не настройками индекса.

Отсутствие метрик качества поиска. «Вроде находит нужное» — это впечатление, а не метрика. Векторный поиск — это поиск с ранжированием, и меряют его соответствующими метриками: Recall@K и Precision@K (сколько релевантного попало в топ-K результатов), а если важен порядок выдачи — ещё MRR или nDCG. Без них нельзя сравнить два индекса, две модели эмбеддингов или два порога приближённости между собой, и тем более — заметить, что качество поиска потихоньку деградирует. Как устроить измерение и мониторинг этих метрик на практике: карта выбора и мониторинг recallСкоро.

Переусложнение. Поднять отдельный кластер Milvus ради десяти тысяч документов — значит добавить в инфраструктуру новый stateful-компонент, новый цикл эксплуатации и новую точку отказа там, где pgvector в уже существующем PostgreSQL закрыл бы задачу без единой новой сущности в стеке.

Отдельно от этих ошибок стоят два вопроса, которые здесь сознательно не разбираются, а вынесены в отдельные статьи серии: как совмещать векторный поиск с поиском по ключевым словам — гибридный поиск и rerankingСкоро — и как фильтровать по атрибутам, не теряя точность ANN-поиска — фильтрация и консистентность в ANNСкоро.

Куда дальше

В retrieval-augmented generation (RAG) модель отвечает не по памяти, а по фрагментам текста, которые ей подложили в контекст, — и находит эти фрагменты именно векторный поиск. Насколько точно он находит нужное, настолько же точным будет и итоговый ответ: качество поиска — это потолок качества всей цепочки RAG. Если нужный факт не попал в найденный контекст, ни промпт, ни более крупная модель не смогут надёжно подставить его как обоснованный (grounded) ответ — в лучшем случае угадают, в худшем придумают. Как устроена эта цепочка целиком: RAG end-to-end: от эмбеддингов до ответаСкоро.

Дальше в серии каждый слой из этой статьи планируется разобрать отдельно и вглубь — статьи готовятся следом за этой вводной:

  • ANN вглубь: HNSW, IVF, PQСкоро — как устроены индексы приблизительного поиска;
  • pgvector вглубьСкоро — что делать, когда pgvector нужно выжать по максимуму;
  • Qdrant, Milvus, WeaviateСкоро — разбор выделенных движков;
  • гибридный поиск и rerankingСкоро — совмещение смысла и ключевых слов;
  • фильтрация и консистентность в ANNСкоро — атрибутивные фильтры и их цена для recall;
  • pgvector или выделенная базаСкоро — карта выбора и эксплуатация в проде.

Когда серия выйдет, для тех, кому решение нужно здесь и сейчас, а не после чтения всего, удобной точкой входа будет последняя статья — карта выбора: там лестница из этой вводной собрана в практический вид. Пока продолжения готовятся, ссылки выше помечены как ожидаемые.

Документация и первоисточники

  • pgvector — векторный поиск внутри PostgreSQL
  • Qdrant — документация выделенного движка
  • Milvus — документация выделенного движка
  • Weaviate: поиск — векторный и гибридный поиск в Weaviate
  • OpenSearch k-NN — векторный поиск в поисковом движке
  • Redis Vector Search — векторные запросы в Redis
  • HNSW — оригинальная статья — алгоритм приблизительного поиска, лежащий в основе большинства индексов

Обсуждение в Telegram

Присоединиться →

Комментарии