Векторный индекс — быстрый старт

Эта статья поможет быстро начать работу с векторными индексами в YDB на простейшем модельном примере.

В статье будут рассмотрены следующие шаги работы с векторным индексом:

Шаг 1. Создание таблицы с векторами

Сначала нужно создать таблицу в YDB, в которой будут храниться векторы. Это можно сделать с помощью SQL-запроса:

CREATE TABLE Vectors (
  id Uint64,
  embedding String,
  PRIMARY KEY (id)
);

Эта таблица Vectors имеет два столбца:

  • id — уникальный идентификатор каждого вектора;
  • embedding — вектор вещественных чисел, упакованный в строку.

Шаг 2. Заполнение таблицы данными

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

UPSERT INTO Vectors(id, embedding)
VALUES 
    (1, Untag(Knn::ToBinaryStringFloat([1.f, 1.f, 1.f, 1.f, 1.f]), "FloatVector")),
    (2, Untag(Knn::ToBinaryStringFloat([1.f, 1.f, 1.f, 1.f, 1.25f]), "FloatVector")),
    (3, Untag(Knn::ToBinaryStringFloat([1.f, 1.f, 1.f, 1.f, 1.5f]), "FloatVector")),
    (4, Untag(Knn::ToBinaryStringFloat([-1.f, -1.f, -1.f, -1.f, -1.f]), "FloatVector")),
    (5, Untag(Knn::ToBinaryStringFloat([-2.f, -2.f, -2.f, -2.f, -4.f]), "FloatVector")),
    (6, Untag(Knn::ToBinaryStringFloat([-3.f, -3.f, -3.f, -3.f, -6.f]), "FloatVector"));

Описание функции Knn::ToBinaryStringFloat см. здесь.

Шаг 3. Построение векторного индекса

Для создания векторного индекса EmbeddingIndex на таблице Vectors нужно использовать команду:

ALTER TABLE Vectors
ADD INDEX EmbeddingIndex
GLOBAL USING vector_kmeans_tree 
ON (embedding)
WITH (
  distance=cosine, 
  vector_type="float", 
  vector_dimension=5, 
  levels=1, 
  clusters=2)

Данная команда создаёт индекс типа vector_kmeans_tree. Подробнее об индексах такого типа вы можете прочитать здесь. В данном модельном примере указан параметр clusters=2 (разбиение множества векторов при построении индекса на два кластера на каждом уровне); для реальных данных рекомендованы значения в диапазоне от 64 до 512.

Общую информацию о векторных индексах, параметрах их создания и текущих ограничениях см. в разделе Векторные индексы.

Шаг 4. Поиск в таблице без использования векторного индекса

На данном шаге выполняется точный поиск 3-х ближайших соседей для заданного вектора [1.f, 1.f, 1.f, 1.f, 4.f] без использования индекса.

Сначала целевой вектор кодируется в бинарное представление с помощью Knn::ToBinaryStringFloat.

Затем вычисляется косинусное расстояние от embedding каждой строки до целевого вектора.

Записи сортируются по возрастанию расстояния, и выбираются три ($K) первых записей, которые являются ближайшими.

$K = 3;
$TargetEmbedding = Knn::ToBinaryStringFloat([1.f, 1.f, 1.f, 1.f, 4.f]);

SELECT id, Knn::CosineDistance(embedding, $TargetEmbedding) As CosineDistance
FROM Vectors
ORDER BY Knn::CosineDistance(embedding, $TargetEmbedding)
LIMIT $K;

Результат выполнения запроса:

id CosineDistance
3  0.1055728197
2  0.1467181444
1  0.1999999881

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

Шаг 5. Поиск в таблице с использованием векторного индекса

Для поиска 3-х ближайших соседей вектора [1.f, 1.f, 1.f, 1.f, 4.f] с использованием индекса EmbeddingIndex, который был создан на шаге 3, нужно выполнить запрос:

$K = 3;
$TargetEmbedding = Knn::ToBinaryStringFloat([1.f, 1.f, 1.f, 1.f, 4.f]);

SELECT id, Knn::CosineDistance(embedding, $TargetEmbedding) As CosineDistance
FROM Vectors VIEW EmbeddingIndex
ORDER BY Knn::CosineDistance(embedding, $TargetEmbedding)
LIMIT $K;

Обратите внимание, что в данном запросе после названия таблицы указано, что отбор записей в ней следует производить с помощью векторного индекса: FROM Vectors VIEW EmbeddingIndex.

Результат выполнения запроса:

id CosineDistance
3  0.1055728197
2  0.1467181444
1  0.1999999881

Благодаря использованию индекса поиск ближайших векторов происходит значительно быстрее на больших выборках.

Заключение

Данная статья приводит простой пример работы с векторным индексом: создание таблицы с векторами, заполнение таблицы векторами, построение векторного индекса для такой таблицы и поиск вектора в таблице с использованием векторного индекса или без него.

В случае маленькой таблицы, как в этом модельном примере, невозможно увидеть разницу в производительности запросов. Эти примеры призваны проиллюстрировать синтаксис при работе с векторными индексами. Более реалистичный пример с бо́льшим объёмом данных см. здесь.

Более подробную информацию о векторных индексах см. здесь.