Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 14.05 · 35 мин
Продвинутый
HNSWvector similaritycosineDistanceQBitANNGAADD INDEXMATERIALIZE INDEX

HNSW Vector Similarity и QBit

Векторный поиск — растущий use case для RAG-систем, рекомендаций и семантического поиска. ClickHouse не является vector-native базой данных, но предоставляет ANN-индексы (Approximate Nearest Neighbor) для случаев, когда данные уже хранятся в ClickHouse и нет необходимости в отдельном векторном хранилище.


HNSW Vector Similarity Index (GA с 25.8)

HNSW vector_similarity index стал GA-фичей в ClickHouse 25.8 (vectorSimilarityIndex stable) и доступен в 26.3 LTS как production-ready возможность. Иерархические навигационные малые миры (Hierarchical Navigable Small World) — граф-структура для приближённого поиска ближайших соседей. Предыдущие экспериментальные индексы Annoy и usearch удалены в 25.6 — если у вас были такие индексы на старых версиях, их необходимо DROP INDEX перед апгрейдом.

INFO

Начиная с 25.8 настройка allow_experimental_vector_similarity_index больше не требуется (индекс GA). 25.8 также добавил index-only reading, fetch multiplier и binary quantization (b1). Quantization-режимы: bf16 (по умолчанию), i8 (int8), b1 (бинарная).

Создание таблицы с HNSW-индексом:

CREATE TABLE embeddings (
    id      UInt32,
    title   String,
    vector  Array(Float32),
    CONSTRAINT dim CHECK length(vector) = 384
) ENGINE = MergeTree()
ORDER BY id;

Добавление индекса через ALTER TABLE:

-- Синтаксис: vector_similarity(algorithm, distance, dim, quantization, M, ef_construction)
ALTER TABLE embeddings
ADD INDEX vec_idx vector
TYPE vector_similarity('hnsw', 'cosineDistance', 384, 'bf16', 64, 512);

Параметры индекса:

ПараметрЗначениеОписание
algorithm'hnsw'Алгоритм построения графа
distance_function'cosineDistance'Функция расстояния
dim384Размерность векторов (должна совпадать для всех строк)
quantization'bf16'Квантизация (bf16 = bfloat16, экономия памяти)
M64Число рёбер в HNSW-графе (больше = точнее, больше памяти)
ef_construction512Размер очереди при построении (больше = точнее, медленнее build)

ADD INDEX vs MATERIALIZE INDEX

WARNING

ADD INDEX только объявляет определение индекса. Для существующих данных необходимо выполнить ALTER TABLE embeddings MATERIALIZE INDEX vec_idx SETTINGS mutations_sync = 2. Новые INSERT индексируются автоматически.

-- Шаг 1: объявить определение индекса
ALTER TABLE embeddings
ADD INDEX vec_idx vector
TYPE vector_similarity('hnsw', 'cosineDistance', 384, 'bf16', 64, 512);

-- Шаг 2: материализовать для существующих данных
ALTER TABLE embeddings
MATERIALIZE INDEX vec_idx
SETTINGS mutations_sync = 2;
-- mutations_sync=2 -- ждать завершения мутации на всех репликах

Поиск ближайших соседей

ClickHouse автоматически использует HNSW при запросе с ORDER BY distance_function(...) LIMIT K:

-- Найти 10 наиболее похожих документов
SELECT id, title
FROM embeddings
ORDER BY cosineDistance(vector, [0.1, 0.2, 0.3, 0.4])
LIMIT 10;

Доступные функции расстояния:

ФункцияОписаниеИспользование
cosineDistance1 - cos(angle)Текстовые эмбеддинги, семантическое сходство
L2DistanceЕвклидово расстояниеИзображения, audio-эмбеддинги
L2SquaredDistanceL2^2 без sqrtОптимизация вычислений (монотонно эквивалентно L2)

HNSW + FINAL: несовместимость

WARNING

HNSW indexes несовместимы с FINAL qualifier и ReplacingMergeTree. При использовании SELECT ... FINAL ClickHouse вернёт результат, но HNSW-индекс будет проигнорирован — будет выполнен полный сканирующий поиск. Для vector storage используйте обычный MergeTree без FINAL.

-- Неправильно: HNSW индекс не используется при FINAL
SELECT id, title
FROM dedup_embeddings FINAL
ORDER BY cosineDistance(vector, query_vec)
LIMIT 10;

-- Правильно: MergeTree без FINAL, ручная дедупликация при необходимости
SELECT id, title
FROM plain_embeddings
ORDER BY cosineDistance(vector, query_vec)
LIMIT 10;

QBit Binary Quantization

QBit — тип данных для бит-срезового хранения векторов с tunable precision. Введён в 25.10, переведён в beta в 26.1, объявлен production-ready в 26.2 и стандартно доступен в 26.3 LTS.

INFO

Ключевая идея QBit — decomposed bit-sliced storage. Каждое число (BFloat16, Float32 или Float64) разбивается на отдельные бит-плоскости (bit planes), и при запросе пользователь указывает, сколько старших бит брать. Без QBit квантизация фиксируется во время INSERT; с QBit — выбирается на лету в момент SELECT. Re-ingest при смене precision не требуется.

-- В 26.3 LTS флаг включения по умолчанию активен; на более ранних версиях:
SET allow_experimental_qbit_type = 1;

CREATE TABLE items (
    id        UInt32,
    embedding QBit(Float32, 128)
) ENGINE = MergeTree()
ORDER BY id;

Tunable precision: B бит на размерность

Параметр B (bits per dimension) выбирается в момент запроса, а не при создании таблицы. Чем меньше B — тем меньше I/O и быстрее вычисление расстояния, но тем ниже recall.

-- Поиск с B=2 бита на размерность (агрессивная квантизация, ~16x экономия памяти)
SELECT id, L2DistanceTransposed(embedding, [0.1, 0.2, ...], 2) AS dist
FROM items
ORDER BY dist
LIMIT 10;

-- Тот же запрос с B=8 (выше recall, больше I/O)
SELECT id, L2DistanceTransposed(embedding, [0.1, 0.2, ...], 8) AS dist
FROM items
ORDER BY dist
LIMIT 10;

-- B=32 для Float32 -- эквивалент полной точности
SELECT id, L2DistanceTransposed(embedding, [0.1, 0.2, ...], 32) AS dist
FROM items
ORDER BY dist
LIMIT 10;

Memory и recall trade-off

Для Float32 (32 бита на dimension) использование B=2 эффективно сокращает читаемый объём примерно в 16 раз — читаются только 2 старших бит-плоскости из 32. На практике это означает:

B (бит/dim)Чтение vs Float32Recall@10 (типично)Use case
1~32x меньше0.6-0.75Грубое candidate generation
2~16x меньше0.75-0.85Recall-rough screening
4~8x меньше0.90-0.95Production query (баланс)
8~4x меньше0.97-0.99Высокое качество
321x (full)1.0 (точное)Reranking topK после QBit-screening

Hybrid pattern: QBit screening + точный rerank

Типичный production-паттерн — двухэтапный поиск: QBit с малым B для быстрого получения top-K кандидатов, затем точное расстояние для финального ранжирования:

WITH candidates AS (
    -- Шаг 1: дешёвое candidate generation через QBit B=2
    SELECT id, embedding
    FROM items
    ORDER BY L2DistanceTransposed(embedding, {query:Array(Float32)}, 2)
    LIMIT 200
)
-- Шаг 2: точное ранжирование на 200 кандидатах
SELECT id
FROM candidates
ORDER BY L2DistanceTransposed(embedding, {query:Array(Float32)}, 32)
LIMIT 10;

QBit поддерживает BFloat16, Float32 и Float64 как базовые типы. Для embedded-моделей, которые традиционно используют Float32, QBit(Float32, 768) — стандартный выбор для 768-мерных векторов BERT/E5.


Сравнение подходов

ПодходТочностьСкорость поискаДоп. памятьСтатус
Полный скан + cosineDistanceТочнаяМедленная (O(N))НетGA
HNSW index (vector_similarity)ПриближённаяБыстрая (O(log N))ЗначительнаяGA (с 25.8)
QBit (QBit(Float32, N), B=2-8)Tunable (B на запрос)БыстраяМинимальная (~16x при B=2)GA (с 26.2)
Annoy / usearchУдалён в 25.6 (заменён на vector_similarity)

Production альтернативы

ClickHouse HNSW (GA с 25.8) подходит для production-сценариев, когда данные уже хранятся в ClickHouse и нет потребности в отдельном инфраструктурном компоненте. Если требуется специализированная vector DB (например, для очень больших корпусов или сложных hybrid-search паттернов), рассмотрите:

  • Milvus — открытая vector DB, Kubernetes-native
  • Qdrant — высокопроизводительная vector DB на Rust
  • pgvector — расширение PostgreSQL для векторного поиска

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

  1. HNSW vector_similarity index — GA с ClickHouse 25.8 (доступен в 26.3 LTS). Настройка allow_experimental_vector_similarity_index больше не требуется.
  2. ADD INDEX только регистрирует определение. Для индексации существующих строк необходим MATERIALIZE INDEX ... SETTINGS mutations_sync = 2.
  3. Доступные distance functions: cosineDistance (текст), L2Distance (изображения), L2SquaredDistance (оптимизация).
  4. HNSW несовместим с FINAL и ReplacingMergeTree — при SELECT ... FINAL индекс игнорируется.
  5. QBit — production-ready тип данных (GA в 26.2, доступен в 26.3 LTS) с tunable precision: параметр B (bits per dimension) выбирается в момент запроса, а не при INSERT. B=2 даёт ~16x экономию I/O при recall ~0.75-0.85; B=4 — production-баланс. Hybrid-паттерн: QBit-screening для top-K кандидатов + точное ранжирование (B=32) для финального LIMIT.
  6. Annoy и usearch индексы удалены в 25.6 — мигрировать на vector_similarity через DROP INDEX + ADD INDEX ... TYPE vector_similarity(...) перед апгрейдом.
Dictionary encoding и quantization: сжатие high-dimensional данных Embeddings и векторные данные: генерация, хранение и поиск

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 8