Qdrant - Vector Database

HNSW: Как работает индекс

Поиск по 1 млн векторов за 1-5ms - это не магия. Это HNSW: граф, по которому можно добраться до любого вектора за O(log N) шагов. Понять его параметры - значит уметь настраивать recall и скорость под конкретную задачу.

  • **RAG с высоким recall:** ef_construct=200, hnsw_ef=128 - не пропустим релевантный контекст для LLM
  • **Рекомендации в реальном времени:** m=16, hnsw_ef=32 - 1-2ms на запрос, recall 94% достаточно
  • **Медицинские данные:** m=32, exact: true для финальной верификации - точность важнее скорости

Предварительные знания

  • First Search: Search API

HNSW: Navigable Small World

**HNSW (Hierarchical Navigable Small World)** - алгоритм приближённого поиска ближайших соседей (ANN). Это многослойный граф: верхние слои - «скоростные шоссе» с малым числом узлов и длинными связями, нижний слой - полный граф со всеми векторами и короткими связями.

**«Маленький мир»** - концепция из социологии: любые два человека связаны через ~6 рукопожатий. HNSW использует тот же принцип - из любой точки можно быстро достичь любой другой, двигаясь по «длинным» связям верхних слоёв и уточняя через «короткие» связи нижних.

**HNSW - это ANN, не точный поиск.** Он находит приближённых ближайших соседей, а не гарантированно точных. Recall (доля правильных результатов) обычно 95-99%, что достаточно для большинства задач. Для 100% recall - `exact: true`, но это brute-force.

Поиск с HNSW даёт 9 из 10 правильных результатов (recall = 90%). Коллега предлагает использовать `exact: true` для 100% recall в production. Что правильнее?

Параметры m, ef_construct, ef

**Три ключевых параметра HNSW** определяют качество и скорость работы индекса. Важно понимать каждый из них.

ПараметрГде задаётсяDefaultЧто контролирует
mhnsw_config при создании коллекции16Количество связей каждого узла в графе. Больше = лучше recall, больше памяти
ef_constructhnsw_config при создании коллекции100Размер очереди при построении индекса. Больше = лучше граф, дольше индексирование
ef (hnsw_ef)params при поискезависит от ef_constructРазмер очереди при поиске. Больше = лучше recall, медленнее запрос

**ef_construct изменить нельзя после создания коллекции** - нужно пересоздавать. Параметр `m` тоже фиксирован. **hnsw_ef при поиске** - можно менять для каждого запроса. Именно поэтому начинайте с умеренных m/ef_construct, а тюнинг качества делайте через hnsw_ef.

Коллекция создана с m=16, ef_construct=100. Recall при поиске - 94%, цель - 98%. Какой параметр менять?

Тюнинг: память, скорость, качество

**Главный trade-off HNSW:** качество recall ↔ скорость поиска ↔ потребление памяти. Три вершины треугольника - улучшение одного обычно ухудшает другое.

Сценарийmef_constructhnsw_efХарактеристики
Быстрый поиск (latency-first)85032Минимальная память, максимальная скорость, recall ~90%
Баланс (default)1610064Хороший recall ~97%, умеренная скорость и память
Высокий recall32200128Recall ~99%, +2x память, умеренно медленнее
Максимальное качество64400256Recall ~99.9%, дорого по памяти и скорости

**Практический совет:** начните с дефолтных m=16, ef_construct=100. Измерьте recall на реальных данных через сравнение с `exact: true`. Если recall < 95% - сначала увеличьте hnsw_ef при поиске. Если даже hnsw_ef=512 не помогает - пересоздайте с m=32, ef_construct=200.

Установить максимальные m=64, ef_construct=400 «на всякий случай»

Начинать с дефолтных значений (m=16, ef_construct=100) и увеличивать только если измеренный recall недостаточен

m=64 vs m=16: память под граф растёт в 4 раза. ef_construct=400 vs 100: индексирование замедляется в ~4 раза. При этом recall на типичных задачах с дефолтами уже 95-97%. Избыточные параметры - пустая трата ресурсов

Коллекция из 5 млн векторов (1536-dim). Измеренный recall@10 = 96% при hnsw_ef=64. Продукт требует 99%+. Что оптимально?

Ключевые идеи

  • **HNSW** - многослойный граф, поиск за O(log N). Верхние слои - быстрое приближение, нижний - точное уточнение
  • **m** (default: 16) - связность узлов в графе. Больше = лучше recall, больше памяти. Фиксируется при создании
  • **ef_construct** (default: 100) - качество построения графа. Больше = лучше граф, дольше индексирование. Фиксируется при создании
  • **hnsw_ef** при поиске - можно менять для каждого запроса. Это главный рычаг тюнинга recall без пересоздания коллекции
  • **Тюнинг:** сначала hnsw_ef ↑, потом m и ef_construct ↑. Измеряйте recall через сравнение с exact: true

Что дальше

HNSW управляет поиском по векторам. Но часто нужно ещё и фильтровать по полям данных - категории, дате, геолокации.

  • Payload индексы — Ускорение фильтрации по payload-полям - работает вместе с HNSW
  • Квантизация векторов — Сжатие памяти в 4-32x при минимальной потере recall
  • Метрики расстояния — Как выбрать правильную метрику для своей задачи

Вопросы для размышления

  • При каких задачах recall 95% достаточен, а при каких нужен 99%+? Приведите примеры из реальных систем.
  • Почему ef_construct нельзя изменить после создания коллекции? Как это связано с принципом работы HNSW?
  • При ограниченной RAM - какой параметр уменьшить первым: m или ef_construct?

Связанные уроки

  • alg-12-bfs
HNSW: Как работает индекс

0

1

Войти