---
metadata:
  - name: generator
    content: Diplodoc Platform v5.57.3
alternate:
  - https://ydb.tech/docs/en/dev/vector-indexes.md?version=main
  - https://ydb.tech/docs/ru/dev/vector-indexes.md?version=main
  - href: https://ydb.tech/docs/ru/dev/vector-indexes.md?version=main
    type: text/markdown
    title: Markdown version
  - href: https://ydb.tech/docs/ru/llms.txt
    type: text/markdown
    title: llms.txt
sourcePath: ru/core/dev/vector-indexes.md
---
> **Documentation Index:** Fetch the complete configuration index at https://ydb.tech/docs/ru/llms.txt

# Векторные индексы

[Векторные индексы](https://ydb.tech/docs/ru/concepts/glossary.md?version=main#vector-index) — это специализированный тип [вторичного индекса](https://ydb.tech/docs/ru/concepts/glossary.md?version=main#secondary-index), который позволяет эффективно выполнять [векторный поиск](https://ydb.tech/docs/ru/concepts/query_execution/vector_search.md?version=main) в многомерных пространствах. В отличие от традиционных вторичных индексов, оптимизированных для поиска по равенству или диапазону, векторные индексы позволяют выполнять приближенный поиск на основе [функций схожести или расстояния](https://ydb.tech/docs/ru/yql/reference/udf/list/knn.md?version=main#functions).

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

## Виды векторных индексов {#types}

Векторный индекс может быть [глобальным](#global) либо [глобальным с фильтрацией](#filtered). Также любой из этих видов индекса может быть [покрывающим](#covering) и включать копию данных дополнительных колонок из основной таблицы.

### Глобальный векторный индекс {#global}

Глобальный векторный индекс по колонке `embedding` позволяет быстро искать приближённых ближайших соседей по всей таблице:

```yql
ALTER TABLE my_table
  ADD INDEX my_index
  GLOBAL USING vector_kmeans_tree
  ON (embedding)
  COVER (embedding, data)
  WITH (distance=cosine, vector_type="float", vector_dimension=512, overlap_clusters=3);
```

Пример запроса поиска к такому индексу:

```yql
PRAGMA ydb.KMeansTreeSearchTopSize = "10";

DECLARE $query_vector AS string;

$query_vector = Knn::ToBinaryStringFloat([1.0, 1.2, 0, ...]);

SELECT user, data
FROM my_table VIEW my_index
ORDER BY Knn::CosineSimilarity(embedding, $query_vector) DESC
LIMIT 10;
```

Обратите внимание, что:

- Как векторная колонка `embedding`, так и параметр `$query_vector` должны иметь строковый тип и содержать массив чисел в простом [бинарном формате](https://ydb.tech/docs/ru/yql/reference/udf/list/knn.md?version=main#functions-convert-format).
- Передавать параметр из SDK эффективнее в виде строки, сериализуя числа на стороне приложения ([примеры](https://ydb.tech/docs/ru/recipes/ydb-sdk/vector-search.md?version=main#search-by-vector)). Альтернативно значение можно передавать из SDK как вектор чисел и конвертировать из списка функциями `Knn::ToBinaryString*`, но это медленнее.
- Конструкция `COVER (embedding, data)` необязательна и предназначена для создания [покрывающего индекса](#covering). Это помогает дополнительно ускорить поиск.
- Поиск по векторному индексу всегда приближённый - его результаты отличаются от поиска полным перебором.
- Увеличение параметра [`PRAGMA KMeansTreeSearchTopSize`](https://ydb.tech/docs/ru/yql/reference/syntax/select/vector_index.md?version=main#kmeanstreesearchtopsize) повышает качество (полноту) поиска, но снижает его скорость. Параметр задаёт число ближайших к запросу сканируемых кластеров индекса. Значение по умолчанию - 1 (минимальное качество, максимальная скорость).
- Параметр `overlap_clusters=3` сильно повышает качество будущего поиска при индексации, задавая число кластеров, в которые добавляется каждый вектор, но увеличивает размер индекса.
- Параметры `vector_type` и `vector_dimension` можно не указывать, если таблица не пуста — они будут автоматически определены из содержимого строк.

### Векторный индекс с фильтрацией {#filtered}

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

Чтобы создать такой индекс, укажите несколько индексных колонок. Последняя колонка должна быть векторной, остальные (колонки категорий) - любыми:

```yql
ALTER TABLE my_table
  ADD INDEX my_index
  GLOBAL USING vector_kmeans_tree
  ON (user, embedding)
  COVER (embedding, data)
  WITH (distance=cosine);
```

Запросы поиска к такому индексу с фильтрацией должны включать условия по колонке `user`:

```yql
PRAGMA ydb.KMeansTreeSearchTopSize = "10";

DECLARE $query_vector AS string;

$query_vector = Knn::ToBinaryStringFloat([1.0, 1.2, 0, ...]);

SELECT user, data
FROM my_table VIEW my_index
WHERE user = 'john'
ORDER BY Knn::CosineSimilarity(embedding, $query_vector) DESC
LIMIT 10;
```

Параметры индексации и поиска здесь работают аналогично глобальному индексу. Поскольку разные значения фильтруемых колонок часто содержат очень разное количество векторов, индекс с фильтрацией может дополнительно использовать [адаптивное количество кластеров](https://ydb.tech/docs/ru/dev/vector-indexes-kmeans-tree-type.md?version=main#adaptive-clusters), чтобы выбирать количество кластеров для каждого значения автоматически.

### Покрывающий векторный индекс {#covering}

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

Обратите внимание, что по умолчанию индекс не содержит копию векторной колонки (в примере - embedding), поэтому если её не добавить в список покрытых колонок явно, то избежать чтения из основной таблицы не удастся, так как вектора всегда используются для точной сортировки результатов на последнем этапе поиска.

```yql
ALTER TABLE my_table
  ADD INDEX my_index
  GLOBAL USING vector_kmeans_tree
  ON (embedding)
  COVER (embedding, data)
  WITH (distance=cosine);
```

## Функции расстояния {#distance}

Поддерживаются следующие [функции схожести или расстояния](https://ydb.tech/docs/ru/yql/reference/udf/list/knn.md?version=main#functions-distance):

* `distance=cosine` или `similarity=cosine` - косинусное расстояние, соответствует сортировке `ORDER BY Knn::CosineDistance(...) ASC` либо `ORDER BY Knn::CosineSimilarity(...) DESC`.
* `distance=manhattan` - Манхэттенское расстояние (L1-метрика), соответствует `ORDER BY Knn::ManhattanDistance(...) ASC`.
* `distance=euclidean` - Евклидово расстояние (L2-метрика), соответствует `ORDER BY Knn::EuclideanDistance(...) ASC`.
* `similarity=inner_product` - скалярное произведение, соответствует `ORDER BY Knn::InnerProductSimilarity(...) DESC`.

## Полный синтаксис векторных индексов {#syntax}

Создание векторного индекса:

* При создании таблицы: [CREATE TABLE](https://ydb.tech/docs/ru/yql/reference/syntax/create_table/vector_index.md?version=main).
* Добавление к существующей таблице: [ALTER TABLE](https://ydb.tech/docs/ru/yql/reference/syntax/alter_table/indexes.md?version=main).

Полный синтаксис запроса к векторному индексу:

* [VIEW VECTOR INDEX](https://ydb.tech/docs/ru/yql/reference/syntax/select/vector_index.md?version=main).

## Алгоритм поиска

В текущей реализации доступен один тип индекса: `vector_kmeans_tree`.

### Векторный индекс типа `vector_kmeans_tree` {#kmeans-tree-type}

Индекс `vector_kmeans_tree` реализует иерархическую кластеризацию данных. Структура индекса включает:

1. Иерархическая кластеризация:

    * индекс строит несколько уровней k-means кластеров;
    * на каждом уровне векторы распределяются по заданному количеству кластеров в степени уровня;
    * первый уровень кластеризует весь набор данных;
    * последующие уровни рекурсивно кластеризуют содержимое каждого родительского кластера.

2. Процесс поиска:

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

3. Параметры:

    * `levels`: число уровней в дереве, задает глубину поиска (рекомендуется 1-3);
    * `clusters`: количество кластеров в k-means, определяющее ширину поиска (рекомендуется 64-512).
    * `overlap_clusters`: количество кластеров нижнего уровня, в которые добавляется каждый вектор (рекомендуется 3).

Внутри векторный индекс состоит из скрытых индексных таблиц вида `indexImpl*Table`. В [запросах на выборку](https://ydb.tech/docs/ru/yql/reference/syntax/select/vector_index.md?version=main) с использованием векторного индекса эти таблицы отображаются в [статистике запросов](https://ydb.tech/docs/ru/dev/query-execution-optimization/query-plans-optimization.md?version=main). Подробнее об устройстве векторного индекса см. в отдельной статье [Векторный индекс вида vector_kmeans_tree](https://ydb.tech/docs/ru/dev/vector-indexes-kmeans-tree-type.md?version=main).

### Перекрытие кластеров {#overlap-clusters}

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

```yql
ALTER TABLE my_table
  ADD INDEX my_index
  GLOBAL USING vector_kmeans_tree
  ON (embedding)
  WITH (distance=cosine, overlap_clusters=3);
```

В данном примере каждый вектор будет добавлен в 3 ближайших кластера вместо 1.

Параметр overlap_clusters рекомендуется использовать практически всегда, особенно, для векторных индексов с `levels > 1`, так как он позволяет значительно улучшить полноту поиска даже с небольшими значениями PRAGMA [KMeansTreeSearchTopSize](https://ydb.tech/docs/ru/yql/reference/syntax/select/vector_index.md?version=main#kmeanstreesearchtopsize) (например, 3).

Таким образом, можно снизить параметр PRAGMA и значительно ускорить поиск при сохранении той же полноты.

## Партиционирование индексных таблиц {#partitioning}

Основная нагруженная таблица векторного индекса - `indexImplLevelTable`, таблица структуры кластеров. Любой запрос поиска по индексу читает эту таблицу, поэтому нагрузка на её партиции может ограничивать производительность выборок.

Чтобы улучшить производительность, можно включить для неё автопартиционирование по нагрузке:

```yql
ALTER TABLE `my_table/my_index/indexImplLevelTable`
SET AUTO_PARTITIONING_BY_LOAD ENABLED;
```

Или по размеру:

```yql
ALTER TABLE `my_table/my_index/indexImplLevelTable`
SET AUTO_PARTITIONING_PARTITION_SIZE_MB 100;
```

Аналогичную настройку можно применять и к другим индексным таблицам (`indexImplPostingTable` и `indexImplPrefixTable`), но таблица Level - самая нагруженная и при этом небольшая по размеру, поэтому для неё настройки автопартиционирования наиболее актуальны.

## Использование реплик индексных таблиц {#replicas}

Ещё один способ ускорения поиска - использовать реплики таблиц. Для этого нужно:

1. Создать [покрывающий индекс](#covering), чтобы в запросе поиска участвовали только индексные таблицы.
2. Включить реплики на всех индексных таблицах:

   ```yql
   ALTER TABLE `my_table/my_index/indexImplLevelTable` SET READ_REPLICAS_SETTINGS 'PER_AZ:3';
   ALTER TABLE `my_table/my_index/indexImplPostingTable` SET READ_REPLICAS_SETTINGS 'PER_AZ:3';
   ```

   И, для индекса с фильтрацией, также:

   ```yql
   ALTER TABLE `my_table/my_index/indexImplPrefixTable` SET READ_REPLICAS_SETTINGS 'PER_AZ:3';
   ```

3. Использовать режим запроса [Stale Read-Only](https://ydb.tech/docs/ru/recipes/ydb-sdk/tx-control.md?version=main#stale-read-only).

## Обновление векторных индексов {#update}

Обновление векторных индексов имеет следующие особенности:

### Кластеры не пересчитываются при обновлении

При обновлении таблицы с векторным индексом его внутренняя структура — дерево кластеров (групп схожих векторов) — не перестраивается. Новые или изменённые записи лишь распределяются по уже существующим кластерам.

Со временем это может приводить к деградации индекса, которая проявляется двумя способами:

* Снижение полноты — индекс может возвращать меньше релевантных результатов, так как кластеры перестают отражать истинную структуру данных;
* Снижение производительности — если кластеры становятся несбалансированными (например, один кластер содержит слишком много записей), поиск замедляется.

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

* Если индекс был построен на репрезентативной выборке (например, случайные 50 % данных), а затем добавлены оставшиеся записи, структура остаётся актуальной, и деградация минимальна;
* Если же изначально отсутствовали целые группы схожих векторов, кластеры могут разделять пространство некорректно, и качество поиска может существенно упасть.

Крайним случаем является индекс, созданный на пустой таблице: в этом случае он содержит только один кластер, и все новые записи попадают в него. Поиск по такому индексу эквивалентен полному сканированию всей таблицы.

Чтобы избежать деградации:

* Не создавайте векторный индекс на пустой таблице;
* Если в таблице накопилось много новых данных, [постройте новый индекс](https://ydb.tech/docs/ru/yql/reference/syntax/alter_table/indexes.md?version=main) и [атомарно замените](https://ydb.tech/docs/ru/reference/ydb-cli/commands/secondary_index.md?version=main#rename) старый индекс на вновь построенный.

### Неконсистентность при обновлении во время построения

Векторные индексы не поддерживают консистентные обновления во время построения. То есть, векторный индекс не обновляется, если данные в основной таблице меняются до завершения построения индекса.

Это означает, что если вы хотите, чтобы векторный индекс оставался на 100% консистентным, вы должны приостановить обновления данных в таблице во время его построения.

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

## Рецепты работы с векторным индексом {#vector-index-recipes}

Для начала работы с векторным индексом можно воспользоваться следующими рецептами:

* [YDB CLI & YQL](https://ydb.tech/docs/ru/recipes/vector-search/index.md?version=main)
* [YDB SDK: Python, C++](https://ydb.tech/docs/ru/recipes/ydb-sdk/vector-search.md?version=main)
