Перейти к основному содержимому
Версия: 2.0.x

Vector индекс

Эта тема представляет функцию vector индекса Selena и как выполнять приблизительный поиск ближайших соседей (ANNS) с её помощью.

Функция vector индекса поддерживается только в shared-nothing кластерах версии v1.5.2 или более поздней.

Обзор

В настоящее время Selena поддерживает векторную индексацию на уровне файлов Segment. Индекс отображает каждый элемент поиска на его ID строки в файлах Segment, позволяя быстро извлекать данные путём прямого определения соответствующих строк данных без вычислений векторных расстояний методом грубой силы. Система теперь предоставляет два типа векторной индексации: Inverted File with Product Quantization (IVFPQ) и Hierarchical Navigable Small World (HNSW), каждый со своей организационной структурой.

Inverted File with Product Quantization (IVFPQ)

Inverted File with Product Quantization (IVFPQ) — это метод приблизительного поиска ближайших соседей в крупномасштабных многомерных векторах, обычно используемый в задачах векторного поиска в глубоком обучении и машинном обучении. IVFPQ состоит из двух основных компонентов: inverted file и product quantization.

  • Inverted File: Этот компонент является методом индексации. Он разделяет набор данных на несколько кластеров (или ячеек Вороного), каждый с центроидом (начальной точкой), и назначает каждую точку данных (вектор) её ближайшему центру кластера. Для векторного поиска IVFPQ нужно только искать в ближайшем кластере, значительно уменьшая область и сложность поиска.
  • Product Quantization: Этот компонент является методом сжатия данных. Он разбивает многомерные векторы на подвекторы и квантует каждый подвектор для отображения его на ближайшую точку в предопределённом наборе, уменьшая затраты на хранение и вычисления при сохранении высокой точности.

Комбинируя inverted files и product quantization, IVFPQ обеспечивает эффективный приблизительный поиск ближайших соседей в больших многомерных наборах данных.

Hierarchical Navigable Small World (HNSW)

Hierarchical Navigable Small World (HNSW) — это алгоритм на основе графов для поиска ближайших соседей в многомерных пространствах, также широко используемый в задачах векторного поиска.

HNSW строит иерархическую структуру графов, в которой каждый уровень представляет собой navigable small world (NSW) граф. В графе каждая вершина представляет точку данных, а рёбра указывают на сходство между вершинами. Верхние уровни графа содержат меньше вершин с более разреженными соединениями для быстрого глобального поиска, в то время как нижние уровни включают все вершины с более плотными соединениями для точного локального поиска.

Для векторного поиска HNSW сначала выполняет поиск на верхнем уровне, быстро определяя приблизительную область ближайших соседей, затем перемещается вниз по уровням, чтобы найти точного ближайшего соседа на нижнем уровне.

HNSW предлагает как эффективность, так и точность, делая его адаптируемым к различным данным и распределениям запросов.

Сравнение IVFPQ и HNSW

  • Коэффициент сжатия данных: IVFPQ имеет более высокий коэффициент сжатия (около 1:0.15). Расчёт индексации обеспечивает только предварительные результаты сортировки после грубой ранжировки, потому что PQ сжимает векторы. Требуется дополнительная тонкая ранжировка для окончательных результатов сортировки, что приводит к более высоким вычислениям и задержке. HNSW имеет более низкий коэффициент сжатия (около 1:0.8) и обеспечивает точную ранжировку без дополнительной обработки, что приводит к более низким вычислительным затратам и задержке и более высоким затратам на хранение.
  • Настройка Recall: Оба индекса поддерживают настройку уровня recall через регулировку параметров, но IVFPQ влечёт более высокие вычислительные затраты при аналогичных уровнях recall.
  • Стратегия кэширования: IVFPQ позволяет балансировать затраты на память и задержку вычислений путём регулировки пропорции кэша блоков индекса, в то время как HNSW в настоящее время поддерживает только полное кэширование файла.

Использование

Каждая таблица поддерживает только один vector индекс.

Предварительные условия

Перед созданием vector индексов необходимо включить его, установив параметр конфигурации FE enable_experimental_vector в true.

Выполните следующий оператор для динамического включения:

ADMIN SET FRONTEND CONFIG ("enable_experimental_vector" = "true");

Чтобы включить его постоянно, необходимо добавить enable_experimental_vector = true в файл конфигурации FE fe.conf и перезапустить FE.

Создание vector индекса

Это руководство создаёт vector индексы при создании таблиц. Вы также можете добавить vector индексы к существующей таблице. См. Добавление vector индекса для подробных инструкций.

  • Следующий пример создаёт HNSW vector индекс hnsw_vector на столбце vector в таблице hnsw.

    CREATE TABLE hnsw (
    id BIGINT(20) NOT NULL COMMENT "",
    vector ARRAY<FLOAT> NOT NULL COMMENT "",
    INDEX hnsw_vector (vector) USING VECTOR (
    "index_type" = "hnsw",
    "dim"="5",
    "metric_type" = "l2_distance",
    "is_vector_normed" = "false",
    "M" = "16",
    "efconstruction" = "40"
    )
    ) ENGINE=OLAP
    DUPLICATE KEY(id)
    DISTRIBUTED BY HASH(id) BUCKETS 1;
  • Следующий пример создаёт IVFPQ vector индекс ivfpq_vector на столбце vector в таблице ivfpq.

    CREATE TABLE ivfpq (
    id BIGINT(20) NOT NULL COMMENT "",
    vector ARRAY<FLOAT> NOT NULL COMMENT "",
    INDEX ivfpq_vector (vector) USING VECTOR (
    "index_type" = "ivfpq",
    "dim"="5",
    "metric_type" = "l2_distance",
    "is_vector_normed" = "false",
    "nbits" = "16",
    "nlist" = "40"
    )
    ) ENGINE=OLAP
    DUPLICATE KEY(id)
    DISTRIBUTED BY HASH(id) BUCKETS 1;

Параметры построения индекса

USING VECTOR
  • По умолчанию: N/A
  • Обязательно: Да
  • Описание: Создаёт vector индекс.
index_type
  • По умолчанию: N/A
  • Обязательно: Да
  • Описание: Тип vector индекса. Допустимые значения: hnsw и ivfpq.
dim
  • По умолчанию: N/A
  • Обязательно: Да
  • Описание: Размерность индекса. После построения индекса векторы, не соответствующие требованиям размерности, будут отклонены при загрузке в базовый столбец. Должно быть целым числом больше или равным 1.
metric_type
  • По умолчанию: N/A
  • Обязательно: Да
  • Описание: Тип метрики (функция измерения) vector индекса. Допустимые значения:
    • l2_distance: Евклидово расстояние. Чем меньше значение, тем выше сходство.
    • cosine_similarity: Косинусное сходство. Чем больше значение, тем выше сходство.
is_vector_normed
  • По умолчанию: false
  • Обязательно: Нет
  • Описание: Нормализованы ли векторы. Допустимые значения true и false. Действует только когда metric_type равен cosine_similarity. Если векторы нормализованы, значение вычисленных расстояний будет в пределах [-1, 1]. Векторы должны удовлетворять условию, что сумма квадратов равна 1, иначе возвращается ошибка.
M
  • По умолчанию: 16
  • Обязательно: Нет
  • Описание: Специфический параметр HNSW. Количество двунаправленных соединений, создаваемых для каждого нового элемента во время построения графа. Должно быть целым числом больше или равным 2. Значение M напрямую влияет на эффективность и точность построения и поиска графа. Во время построения графа каждая вершина попытается установить соединения с её ближайшими M вершинами. Если вершина уже имеет M соединений, но находит более близкую вершину, самое дальнее соединение будет удалено, и новое соединение будет установлено с более близкой вершиной. Векторный поиск начнётся с точки входа и найдёт ближайшего соседа вдоль вершин, соединённых с ней. Следовательно, чем больше значение M, тем больше область поиска для каждой вершины, тем выше эффективность поиска, но тем выше стоимость построения и хранения графа.
efconstruction
  • По умолчанию: 40
  • Обязательно: Нет
  • Описание: Специфический параметр HNSW. Размер списка кандидатов, содержащего ближайших соседей. Должно быть целым числом больше или равным 1. Используется для контроля глубины поиска во время процесса построения графа. В частности, efconstruction определяет размер списка поиска (также известного как список кандидатов) для каждой вершины во время процесса построения графа. Этот список кандидатов используется для хранения кандидатов соседей текущей вершины, а размер списка равен efconstruction. Чем больше значение efconstruction, тем больше кандидатов рассматривается как соседи вершины во время процесса построения графа, и, как результат, лучше качество (например, лучшая связность) графа, но также выше потребление времени и вычислительная сложность построения графа.
nbits
  • По умолчанию: 16
  • Обязательно: Нет
  • Описание: Специфический параметр IVFPQ. Точность Product Quantization (PQ). Должно быть кратным 8. С IVFPQ каждый вектор разделяется на несколько подвекторов, и затем каждый подвектор квантуется. Nbits определяет точность квантования, то есть на сколько двоичных цифр квантуется каждый подвектор. Чем больше значение nbits, тем выше точность квантования, но тем выше затраты на хранение и вычисления.
nlist
  • По умолчанию: 16
  • Обязательно: Нет
  • Описание: Специфический параметр IVFPQ. Количество кластеров или inverted списков. Должно быть целым числом больше или равным 1. С IVFPQ набор данных разделяется на кластеры, и центроид каждого кластера соответствует inverted списку. Векторный поиск сначала найдёт центроид кластера, ближайший к точке данных, и затем извлечёт ближайших соседей в соответствующем inverted списке. Следовательно, значение nlist будет влиять на точность и эффективность поиска. Чем больше значение nlist, тем мельче гранулярность кластеризации, таким образом, выше точность поиска, но также выше сложность поиска.
M_IVFPQ
  • Обязательно: Да
  • Описание: Специфический параметр IVFPQ. Количество подвекторов, на которые будет разделён исходный вектор. IVFPQ индекс разделит вектор размерности dim на M_IVFPQ подвекторов равной длины. Следовательно, должно быть делителем значения dim.

Добавление vector индекса

Вы также можете добавить vector индексы к существующей таблице, используя CREATE INDEX или ALTER TABLE ADD INDEX.

Пример:

CREATE INDEX ivfpq_vector
ON ivfpq (vector)
USING VECTOR (
"index_type" = "ivfpq",
"metric_type" = "l2_distance",
"is_vector_normed" = "false",
"dim"="5",
"nlist" = "256",
"nbits"="10"
);

ALTER TABLE ivfpq
ADD INDEX ivfpq_vector (vector)
USING VECTOR (
"index_type" = "ivfpq",
"metric_type" = "l2_distance",
"is_vector_normed" = "false",
"dim"="5",
"nlist" = "256",
"nbits"="10"
);

Управление vector индексами

Просмотр vector индекса

Вы можете просмотреть определение vector индекса с помощью оператора SHOW CREATE TABLE:

Пример:

mysql> SHOW CREATE TABLE hnsw \G
*************************** 1. row ***************************
Table: hnsw
Create Table: CREATE TABLE hnsw (
id bigint(20) NOT NULL COMMENT "",
vector array<float> NOT NULL COMMENT "",
INDEX index_vector (vector) USING VECTOR("dim" = "5", "efconstruction" = "40", "index_type" = "hnsw", "is_vector_normed" = "false", "M" = "512", "metric_type" = "l2_distance") COMMENT ''
) ENGINE=OLAP
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES (
"compression" = "LZ4",
"fast_schema_evolution" = "true",
"replicated_storage" = "false",
"replication_num" = "3"
);
1 row in set (0.00 sec)

Удаление vector индекса

Вы можете удалить vector индексы, используя DROP INDEX или ALTER TABLE DROP INDEX.

DROP INDEX ivfpq_vector ON ivfpq;
ALTER TABLE ivfpq DROP INDEX ivfpq_vector;

Выполнение ANNS с vector индексами

Перед запуском векторного поиска убедитесь, что параметр конфигурации FE enable_experimental_vector установлен в true.

Требования для запросов на основе vector индекса

SELECT *, <vector_index_distance_func>(v1, [1,2,3]) as dis
FROM table_name
WHERE <vector_index_distance_func>(v1, [1,2,3]) <= 10
ORDER BY <vector_index_distance_func>(v1, [1,2,3])
LIMIT 10

Чтобы использовать vector индекс в запросах, все следующие требования должны быть выполнены:

  • Требования ORDER BY:
    • Формат предложения ORDER BY: Предложение ORDER BY должно следовать формату ORDER BY <vector_index_distance_func>(vector_column, constant_array) без включения дополнительных столбцов ORDER BY.
      • Требования к имени функции для <vector_index_distance_func>:
        • Если metric_type равен l2_distance, имя функции должно быть approx_l2_distance.
        • Если metric_type равен cosine_similarity, имя функции должно быть approx_cosine_similarity.
      • Требования к параметрам для <vector_index_distance_func>:
        • Один из столбцов constant_array должен быть константным ARRAY<FLOAT> с размерностью, соответствующей dim vector индекса.
        • Другой столбец vector_column должен быть столбцом, соответствующим vector индексу.
    • Требования к направлению ORDER:
      • Если metric_type равен l2_distance, порядок должен быть ASC.
      • Если metric_type равен cosine_similarity, порядок должен быть DESC.
    • Требуется предложение LIMIT N.
  • Требования к предикатам:
    • Все предикаты должны быть выражениями <vector_index_distance_func>, объединёнными с использованием AND и операторов сравнения (> или <). Направление оператора сравнения должно совпадать с порядком ASC/DESC. В частности:
    • Требование 1:
      • Если metric_type равен l2_distance: col_ref <= constant.
      • Если metric_type равен cosine_similarity: col_ref >= constant.
      • Здесь col_ref относится к результату <vector_index_distance_func>(vector_column, constant_array) и может быть приведён к типам FLOAT или DOUBLE, например:
        • approx_l2_distance(v1, [1,2,3])
        • CAST(approx_l2_distance(v1, [1,2,3]) AS FLOAT)
        • CAST(approx_l2_distance(v1, [1,2,3]) AS DOUBLE)
    • Требование 2:
      • Предикат должен использовать AND, где каждый дочерний предикат соответствует Требованию 1.

Подготовка

Создайте таблицы с vector индексами и вставьте векторные данные в них:

CREATE TABLE test_hnsw (
id BIGINT(20) NOT NULL COMMENT "",
vector ARRAY<FLOAT> NOT NULL COMMENT "",
INDEX index_vector (vector) USING VECTOR (
"index_type" = "hnsw",
"metric_type" = "l2_distance",
"is_vector_normed" = "false",
"M" = "512",
"dim"="5")
) ENGINE=OLAP
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1;

INSERT INTO test_hnsw VALUES
(1, [1,2,3,4,5]),
(2, [4,5,6,7,8]);

CREATE TABLE test_ivfpq (
id BIGINT(20) NOT NULL COMMENT "",
vector ARRAY<FLOAT> NOT NULL COMMENT "",
INDEX index_vector (vector) USING VECTOR (
"index_type" = "ivfpq",
"metric_type" = "l2_distance",
"is_vector_normed" = "false",
"nlist" = "256",
"nbits"="8",
"dim"="5",
"M_IVFPQ"="1")
) ENGINE=OLAP
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1;

INSERT INTO test_ivfpq VALUES
(1, [1,2,3,4,5]),
(2, [4,5,6,7,8]);

Выполнение векторного поиска

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

Приблизительные поиски будут использовать vector индекс и тем самым ускорят процесс поиска.

Следующий пример ищет топ-1 приблизительного ближайшего соседа вектора [1,1,1,1,1].

SELECT id, approx_l2_distance([1,1,1,1,1], vector)
FROM test_hnsw
ORDER BY approx_l2_distance([1,1,1,1,1], vector)
LIMIT 1;
Совместный скалярно-векторный поиск

Вы можете комбинировать скалярный поиск с векторным поиском.

SELECT id, approx_l2_distance([1,1,1,1,1], vector)
FROM test_hnsw
WHERE id = 1
ORDER BY approx_l2_distance([1,1,1,1,1], vector)
LIMIT 1;
Поиск по диапазону

Вы можете выполнять поиск по диапазону векторных данных.

Следующий пример отправляет условие score < 40 вниз к индексу и фильтрует векторы по диапазону score.

SELECT * FROM (
SELECT id, approx_l2_distance([1,1,1,1,1], vector) score
FROM test_hnsw
) a
WHERE score < 40
ORDER BY score
LIMIT 1;
Точный расчёт

Точные расчёты проигнорируют vector индекс и будут напрямую вычислять расстояния между векторами для точных результатов.

SELECT id, l2_distance([1,1,1,1,1], vector)
FROM test_hnsw WHERE id = 1
ORDER BY l2_distance([1,1,1,1,1], vector)
LIMIT 1;

ПРИМЕЧАНИЕ

Различные функции метрик расстояния определяют "сходство" по-разному. Для l2_distance меньшие значения указывают на более высокое сходство; для cosine_similarity большие значения указывают на более высокое сходство. Следовательно, при вычислении topN направление сортировки (ORDER BY) должно соответствовать направлению сходства метрики. Используйте ORDER BY ASC LIMIT x для l2_distance и ORDER BY DESC LIMIT x для cosine_similarity.

Тонкая настройка параметров индекса для поиска

Настройка параметров важна в векторном поиске, поскольку влияет как на производительность, так и на точность. Рекомендуется настраивать параметры поиска на небольшом наборе данных и переходить к большим наборам данных только когда достигнуты ожидаемые recall и задержка.

Параметры поиска передаются через подсказки в операторах SQL.

Для HNSW индекса

Перед продолжением убедитесь, что столбец вектора построен с HNSW индексом.

SELECT
/*+ SET_VAR (ann_params='{efsearch=256}') */
id, approx_l2_distance([1,1,1,1,1], vector)
FROM test_hnsw
WHERE id = 1
ORDER BY approx_l2_distance([1,1,1,1,1], vector)
LIMIT 1;

Параметр:

efsearch
  • По умолчанию: 16
  • Обязательно: Нет
  • Описание: Параметр, контролирующий компромисс точности и скорости. Во время поиска иерархической структуры графа этот параметр контролирует размер списка кандидатов во время поиска. Чем больше значение efsearch, тем выше точность, но тем ниже скорость.
Для IVFPQ индекса

Перед продолжением убедитесь, что столбец вектора построен с IVFPQ индексом.

SELECT
/*+ SET_VAR (ann_params='{nprobe=256,max_codes=0,scan_table_threshold=0,polysemous_ht=0,range_search_confidence=0.1}') */
id, approx_l2_distance([1,1,1,1,1], vector)
FROM test_ivfpq
ORDER BY approx_l2_distance([1,1,1,1,1], vector)
LIMIT 1;

Параметр:

nprobe
  • По умолчанию: 1
  • Обязательно: Нет
  • Описание: Количество inverted списков, проверяемых во время поиска. Чем больше значение nprobe, тем выше точность, но тем ниже скорость.
max_codes
  • По умолчанию: 0
  • Обязательно: Нет
  • Описание: Максимальное количество кодов, проверяемых на inverted список. Этот параметр также будет влиять на точность и скорость.
scan_table_threshold
  • По умолчанию: 0
  • Обязательно: Нет
  • Описание: Параметр, контролирующий polysemous hashing. Когда расстояние Хэмминга между хешем элемента и хешем вектора для поиска ниже этого порога, элемент добавляется в список кандидатов.
polysemous_ht
  • По умолчанию: 0
  • Обязательно: Нет
  • Описание: Параметр, контролирующий polysemous hashing. Когда расстояние Хэмминга между хешем элемента и хешем вектора для поиска ниже этого порога, элемент напрямую добавляется в результаты.
range_search_confidence
  • По умолчанию: 0.1
  • Обязательно: Нет
  • Описание: Уверенность приблизительных поисков по диапазону. Диапазон значений: [0, 1]. Установка в 1 даёт наиболее точные результаты.

Расчёт приблизительного recall

Вы можете рассчитать приблизительный recall, пересекая элементы topK из поиска методом грубой силы с элементами из приблизительного поиска: Recall = TP / (TP + FN).

-- Приблизительный поиск
SELECT id
FROM test_hnsw
ORDER BY approx_l2_distance([1,1,1,1,1], vector)
LIMIT 5;
8
9
7
5
1

-- Поиск методом грубой силы
SELECT id
FROM test_hnsw
ORDER BY l2_distance([1,1,1,1,1], vector)
LIMIT 5;
8
9
5
7
10

В предыдущем примере приблизительный поиск возвращает 8, 9, 7 и 5. Однако правильный результат — 8, 9, 5, 7 и 10. В этом случае recall составляет 4/5=80%.

Проверка, работают ли vector индексы

Выполните EXPLAIN для оператора запроса. Если свойства OlapScanNode показывают VECTORINDEX: ON, это указывает, что vector индекс был применён к приблизительным векторным поискам.

Пример:

> EXPLAIN SELECT id FROM t_test_vector_table ORDER BY approx_l2_distance([1,1,1,1,1], vector) LIMIT 5;

+-----------------------------------------------------------------------------------------------------------------------------------------------------+
| Explain String |
+-----------------------------------------------------------------------------------------------------------------------------------------------------+
| PLAN FRAGMENT 0 |
| OUTPUT EXPRS:1: id |
| PARTITION: UNPARTITIONED |
| |
| RESULT SINK |
| |
| 4:Project |
| | <slot 1> : 1: id |
| | limit: 5 |
| | |
| 3:MERGING-EXCHANGE |
| limit: 5 |
| |
| PLAN FRAGMENT 1 |
| OUTPUT EXPRS: |
| PARTITION: RANDOM |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 03 |
| UNPARTITIONED |
| |
| 2:TOP-N |
| | order by: <slot 3> 3: approx_l2_distance ASC |
| | offset: 0 |
| | limit: 5 |
| | |
| 1:Project |
| | <slot 1> : 1: id |
| | <slot 3> : 4: __vector_approx_l2_distance |
| | |
| 0:OlapScanNode |
| TABLE: t_test_vector_table |
| VECTORINDEX: ON |
| IVFPQ: OFF, Distance Column: <4:__vector_approx_l2_distance>, LimitK: 5, Order: ASC, Query Vector: [1, 1, 1, 1, 1], Predicate Range: -1.0 |
| PREAGGREGATION: ON |
| partitions=1/1 |
| rollup: t_test_vector_table |
| tabletRatio=1/1 |
| tabletList=11302 |
| cardinality=2 |
| avgRowSize=4.0 |
+-----------------------------------------------------------------------------------------------------------------------------------------------------+

Ограничения

  • Каждая таблица поддерживает только один vector индекс.