Векторные базы данных: полное руководство
Векторные базы данных — это не просто еще один хранилище данных. Это специализированные движки для семантического поиска, где каждый выбор индекса, квантования или архитектуры напрямую влияет на latency, стоимость и способность вашей RAG-системы работать с миллионами векторов в реальном времени. Забудьте про “универсальные решения”: здесь каждая технология делает ставки на конкретные сценарии, а их trade-offs определяют, выдержит ли ваша архитектура нагрузку.
Технический вызов: ANN-поиск при миллионах векторов и динамических обновлениях
Когда вы сталкиваетесь с поиском ближайших соседей (ANN) в высокомерном пространстве, сталкиваетесь с фундаментальным конфликтом: как сохранить приемлемую latency при постоянных upsert/delete-операциях? Классические индексы (KD-Tree, VP-Tree) ломаются на >10K векторов. HNSW (Hierarchical Navigable Small World) решает это, но его эффективность зависит от баланса между связностью (m), глубиной поиска (ef) и стратегией квантования. Проблема усугубляется, если вам нужно фильтровать по метаданным — каждый дополнительный слой логики увеличивает latency. Решение: архитектура, которая интегрирует фильтрацию в обход графа, или компромисс через гибридный поиск.
Pinecone (managed SaaS)
Pinecone берет на себя всю DevOps-болезнь, но платит за это ценой контроля. Его ядро — кастомный HNSW, где ef динамически подстраивается под качество early-results. Это умно, но черный ящик: вы не можете тонко настроить поведение. Ключевая оптимизация — Product Quantization (PQ): векторы сжимаются в 8-битные кодбуки, уменьшая индекс в 4-8×. Но это требует оффлайн-тренировки на репрезентативной данных, а обновления проходят через WAL с фоновым мерджем. При массовых записях возможны пики latency из-за фрагментации графа.
Trade-offs: Vendor lock-in, линейный рост стоимости при >100M векторов, ограниченные метрики (нет Manhattan distance). Идеально для стартапов, где скорость важнее контроля, но осторожно с масштабом — стоимость RU/WU может сорвать бюджет.
Weaviate (open-source + облачный)
Weaviate разделяет векторы и метаданные (LSM-дерево + файлы), упрощая работу с payload. Гибридный поиск (HNSW + inverted index) позволяет совмещать векторные запросы с BM25, но inverted index обновляется пост-фактум. Добавляет 10-30% latency и гонки при фильтрации сразу после upsert. Мета-модель (GraphQL) позволяет добавлять кастомные vectorizers, но каждый вызов — дополнительная CPU-нагрузка на ноде. Холодный старт 2-5 минут при большом числе модулей.
Trade-offs: Гибкость за счет latency, ручное шардирование, задержки обновления индекса. Выбирайте, если критичен гибридный поиск векторов и текста, но будьте готовы к компромиссам в производительности.
Qdrant (open-source, Rust)
Rust дает предсказуемую производительность без UB, но главное отличие — фильтрация, встроенная в обход HNSW. При traversal графа проверяются условия фильтра (hash/tree индексы) до вычисления расстояния. Это экономит 50% CPU при жестких фильтрах. On-disk quantization mmap’ит сегменты графа, позволяя работать с датасетом, превышающим RAM (деквантование добавляет 5-10% CPU). Архитектура single-binary с RAFT-репликацией: лидер обрабатывает writes, followers — reads. Простой в развертывании, но лидер становится bottleneck при high upsert-rate.
Trade-offs: Линейный рост RAM от индексов (уникальные значения полей), нет GPU-ускорения. Оптимален для сценариев с жесткими фильтрами (персонализация, временные окна).
Milvus (корпоративная / облачная)
Распределенная платформа: etcd (метаданные), MinIO (сжатые векторы), Pulsar (лог), query/data nodes. Индекс-билдер поддерживает IVF-PQ, HNSW, DiskANN. IVF-PQ делит пространство на ячейки (Voronoi), каждая квантуется независимо — эффективно при >100M векторов, но чувствителен к сдвигу данных. Data nodes хранят векторы в MinIO, query nodes — в RAM. Вводит сетевую латентность 1-5 мс между нодами.
Trade-offs: Избыточный оверхед для <10M векторов, сложная отладка, необходимость K8s-инженера. Для корпоративных нагрузок >10K QPS.
Пример кода: Qdrant
# Клиент с пулом и таймаутом — must-have под нагрузкой
from qdrant_client import QdrantClient
from qdrant_client.http.models import VectorParams, Distance, OptimizersConfigDiff, HnswConfigDiff
client = QdrantClient(
host="localhost",
port=6333,
timeout=10, # Защита от зависаний
prefer_grpc=True, # gRPC быстрее при большом трафике
)
# Баланс качества и RAM: m=16 (средняя связность), ef_construct=200 (качество построения)
COLL = "rag_docs"
if not client.collection_exists(COLL):
client.recreate_collection(
collection_name=COLL,
vectors_config=VectorParams(size=768, distance=Distance.COSINE),
hnsw_config=HnswConfigDiff(m=16, ef_construct=200),
on_disk_payload=True, # Индексы payload на диске → экономия RAM
optimizers_config=OptimizersConfigDiff(max_segment_size=50_000),
)
# Формируем точки: вектор + легкий payload. Текст хранится отдельно (S3/MinIO)
points = [
{
"id": i,
"vector": emb.tolist(),
"payload": {
"doc_id": f"doc_{i}",
"source": "wiki",
"category": "science", # Индексируем только низкокардинальные поля
},
}
for i, emb in enumerate(embeddings)
]
# Пакетный upsert: размер подбираем под MTU, избегая TCP-фрагментации
BATCH = 256
for i in range(0, len(points), BATCH):
client.upsert(
collection_name=COLL,
points=points[i:i+BATCH],
wait=True, # Гарантирует репликацию перед возвратом
)
# Фильтрация во время обхода графа — экономия CPU
res = client.search(
collection_name=COLL,
query_vector=query_emb.tolist(),
limit=10,
with_payload=True,
query_filter={"must": [{"key": "category", "match": {"value": "science"}}]},
params={"ef": 120}, # Эмпирический recall~0.92 для наших данных
)
Неочевидные детали:
m * N * 8 байт— RAM под граф HNSW (при 10M векторов и m=16 ~1.3 GB).on_disk_payload=Trueвыносит индексы payload на диск, но граф остается в RAM.- Фильтр проверяется во время traversal — пост-фильтрация в Python избыточна.
wait=Trueупрощает синхронные пайплайны; для async — отслеживайте_recovery.
Узкие места в продакшене
- Pinecone: Нелинейный рост стоимости при >100M векторов. Архивация в S3 снижает расходы, но усложняет операции и риски staleness.
- Weaviate: Холодный старт 2-5 минут. Inverted index обновляется с задержкой → гонки при фильтрации сразу после upsert.
- Qdrant: Линейный рост RAM от индексов (поле
user_idс 1M уникальных значений съест >10 GB). - Milvus: Сетевые хопы между query/data nodes добавляют 1-5 мс latency. Отладка требует агрегации логов из 4+ сервисов.
Вывод: когда что использовать
- Pinecone: MVP и стартапы с ограниченным бюджетом ($0.20-$0.50 за 1M векторов/мес). Zero-Ops, но осторожно с масштабом >1B векторов.
- Weaviate: Гибридный поиск (вектор + BM25) + встроенные vectorizers. Готовьтесь к 20-30% latency и ручному шардированию.
- Qdrant: Жесткие фильтры, персонализация, экономия RAM. Один бинарник, но контролируйте индексы полей.
- Milvus: Корпоративные нагрузки >10K QPS. Только если есть SRE для K8s. Для <10M векторов используйте Milvus Lite.
Бонус: Замеряйте recall@k на реальном трафике, а не на бенчмарках. Оптимальное ef или nprobe — это recall~0.9, а не 0.99: последнее экспоненциально увеличивает latency. Помните, что ANN — это всегда компромисс между памятью, скоростью и точностью.