Векторный индекс — быстрый старт
Эта статья поможет быстро начать работу с векторными индексами в 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_kmeans_tree. В этом модельном примере указан параметр distance=cosine, задающий функцию расстояния — косинусное. Это важный параметр: используемая в индексе функция расстояния должна совпадать с той, на которой обучалась модель эмбеддингов. Параметры clusters, levels, overlap_clusters в этом примере не указаны — они определяются автоматически. Если данных много и есть необходимость тонко настроить индекс, см. подробное описание параметров в Векторный индекс.
Подробную информацию о векторных индексах и их параметрах смотрите в разделе Векторные индексы.
Шаг 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, нужно выполнить запрос:
PRAGMA ydb.KMeansTreeSearchTopSize="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
Благодаря использованию индекса поиск ближайших векторов происходит значительно быстрее на больших выборках.
Заключение
Данная статья приводит простой пример работы с векторным индексом: создание таблицы с векторами, заполнение таблицы векторами, построение векторного индекса для такой таблицы и поиск вектора в таблице с использованием векторного индекса или без него.
В случае маленькой таблицы, как в этом модельном примере, невозможно увидеть разницу в производительности запросов. Эти примеры призваны проиллюстрировать синтаксис при работе с векторными индексами. Более реалистичный пример с бо́льшим объёмом данных см. здесь.
Более подробную информацию о векторных индексах см. здесь.