Векторный поиск

Материал из llmdocs — справочник разработчика
Векторный поиск
Задачанайти k векторов, ближайших к вектору запроса
Точный поискполный перебор (kNN)
Приближённый поискANN — HNSW, IVF, DiskANN, ScaNN
Сжатиепродуктовая (PQ), скалярная и бинарная квантизация
Метрики качестваrecall@k, задержка, память
БиблиотекиFAISS, hnswlib, ScaNN
Хранилищаpgvector, Qdrant, Milvus, Weaviate, Elasticsearch, OpenSearch

Векторный поиск — поиск объектов по близости их векторных представлений. Тексты, изображения или товары заранее превращаются в эмбеддинги — векторы, в которых похожие по смыслу объекты расположены рядом. Запрос тоже превращается в вектор, и система находит k ближайших к нему векторов в коллекции. В отличие от поиска по ключевым словам, векторный поиск находит «машину» по запросу «автомобиль» и правильный раздел документации по вопросу, сформулированному своими словами.

Векторный поиск — центральная часть RAG, рекомендательных систем, поиска по изображениям и обнаружения дубликатов.

Точный и приближённый поиск

Точный поиск (kNN) сравнивает запрос со всеми векторами коллекции. Он прост и гарантирует правильный результат, но время растёт линейно: миллион векторов размерности 1024 — это миллиард умножений на каждый запрос. Для тысяч и десятков тысяч векторов этого достаточно, особенно на GPU.

Приближённый поиск ближайших соседей (ANN) использует индексы, которые проверяют лишь малую часть коллекции. Он находит почти всех настоящих соседей — доля найденных называется полнотой (recall@k) — но работает в сотни и тысячи раз быстрее. На практике полнота 95–99% при задержке в миллисекунды — обычный компромисс.

Основные алгоритмы

Метод Идея Сильные стороны Слабые стороны
HNSW многоуровневый граф «тесного мира»: поиск спускается от дальних связей к ближним[1] высокая полнота и скорость, добавление на лету много памяти, долгое построение
IVF векторы разбиты на кластеры, поиск только в ближайших быстро строится, экономнее по памяти полнота зависит от числа просматриваемых кластеров
PQ (продуктовая квантизация) вектор делится на части, каждая кодируется номером ближайшего центроида[3] сжатие в десятки раз потеря точности, нужен пересчёт лучших кандидатов
DiskANN граф, хранимый на SSD миллиарды векторов на одном сервере сложнее в эксплуатации
ScaNN анизотропная квантизация от Google[4] высокая скорость на CPU меньше интеграций

Библиотека FAISS от Meta реализует большинство этих методов и их комбинации, например IVF+PQ, на CPU и GPU.[2] Сравнивать алгоритмы на одинаковых данных позволяет открытый набор тестов ANN-Benchmarks.[6]

Пример

import faiss
import numpy as np

d = 768                                   # размерность эмбеддингов
xb = np.random.rand(100_000, d).astype("float32")
faiss.normalize_L2(xb)                    # для косинусного сходства

index = faiss.IndexHNSWFlat(d, 32, faiss.METRIC_INNER_PRODUCT)  # 32 связи на узел
index.hnsw.efConstruction = 200
index.add(xb)

q = np.random.rand(1, d).astype("float32")
faiss.normalize_L2(q)
index.hnsw.efSearch = 64                  # больше — точнее, но медленнее
scores, ids = index.search(q, 5)          # 5 ближайших соседей

В продакшене индекс обычно живёт не в памяти скрипта, а в хранилище: в PostgreSQL через расширение pgvector или в специализированной векторной базе.

Фильтрация

Реальные запросы почти всегда сочетают смысловую близость с условиями: «документы этого клиента», «товары в наличии дешевле 5000 рублей», «статьи после 2024 года». Есть два наивных подхода — отфильтровать после поиска (рискуя получить пустой результат) или до поиска (теряя преимущества индекса). Современные системы поддерживают фильтрацию прямо во время обхода индекса; при выборе хранилища стоит проверять именно поиск с фильтрами на своих данных.

Гибридный поиск и переранжирование

Эмбеддинги хорошо передают общий смысл, но слабо работают с точными совпадениями: номерами ошибок, артикулами, именами функций, редкими терминами. Поэтому распространён гибридный поиск: параллельно выполняются векторный и полнотекстовый поиск (BM25), а списки объединяются, например методом обратного рангового слияния (RRF), где документ получает сумму величин 1 / (60 + ранг) из каждого списка.[5]

Затем лучшие 50–100 кандидатов можно переранжировать более точной, но медленной моделью (cross-encoder, reranker), которая читает запрос и документ вместе. Эта двухэтапная схема — быстрый отбор и точная сортировка — стандарт качественного поиска.

Практические советы

  • Используйте одну и ту же модель эмбеддингов для документов и запросов; при смене модели переиндексируйте всё.
  • Качество поиска чаще определяется подготовкой данных — нарезкой на фрагменты (Чанкинг документов), очисткой и метаданными, — чем выбором алгоритма индекса.
  • Меряйте полноту на своём наборе запросов с известными правильными ответами, а не только скорость.
  • Начинайте с простого: точный поиск или pgvector; специализированная инфраструктура нужна на десятках миллионов векторов.

См. также

Источники

  1. Yu. Malkov, D. Yashunin — Efficient and robust approximate nearest neighbor search using HNSW graphs (2016)
  2. J. Johnson, M. Douze, H. Jégou — Billion-scale similarity search with GPUs (FAISS, 2017)
  3. H. Jégou, M. Douze, C. Schmid — Product Quantization for Nearest Neighbor Search (IEEE TPAMI, 2011)
  4. R. Guo et al. — Accelerating Large-Scale Inference with Anisotropic Vector Quantization (ScaNN, 2019)
  5. G. Cormack et al. — Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods (SIGIR 2009)
  6. ANN-Benchmarks