Vector нагрузка

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

Нагрузка позволяет загружать векторы из реального датасета (например, Wikipedia embeddings) или генерировать случайные синтетические векторы. После загрузки данных можно построить векторный индекс, запустить поисковые запросы для измерения полноты и производительности и очистить таблицы нагрузки.

Структура команды

ydb [global options...] workload vector [options...] <subcommand>

Подкоманды:

vector                YDB vector workload.
├─ init                 Инициализация таблиц для нагрузки
├─ import               Загрузка данных в таблицы нагрузки
│   ├─ files              Импорт векторов из файлов
│   └─ generator          Генерация случайных векторов
├─ build-index          Создание и инициализация векторного индекса
├─ drop-index           Удаление векторного индекса
├─ run                  Запуск нагрузки
│   ├─ select            Поиск векторов и измерение производительности/полноты
│   └─ upsert            Вставка или обновление строк с векторами
└─ clean                Удаление таблиц, созданных для нагрузочного тестирования

Инициализация нагрузки

Создайте таблицу для нагрузочного тестирования:

ydb workload vector init

Доступные параметры

Имя Описание Значение по умолчанию
--table <имя> Имя основной таблицы для хранения векторов. vector_index_workload
--min-partitions <значение> Минимальное количество партиций таблицы. 40
--partition-size <значение> Целевой размер партиции, в МБ. 2000
--auto-partition <значение> Включить автопартицирование по нагрузке (1 — включено, 0 — выключено). 1
--prefixed Добавить столбец prefix в таблицу для использования с фильтрующим (prefixed) векторным индексом.
--clear Удалить и пересоздать таблицу, если она уже существует.
--dry-run Только вывести DDL-запрос, не выполняя его.

Создаваемая таблица имеет следующую схему:

  • id Uint64 NOT NULL — первичный ключ;
  • embedding String — сериализованный вектор-эмбеддинг;
  • prefix Uint64 NOT NULL (только при указании --prefixed) — столбец фильтра для prefixed-индексов.

Загрузка данных

После инициализации загрузите данные в таблицу. Доступны две подкоманды: files — для импорта векторов из готового датасета, и generator — для генерации синтетических случайных векторов.

После завершения импорта автоматически строится векторный индекс с именем index по столбцу embedding (если не указано --index-type None).

Импорт из файлов

Импорт векторов из файлов (CSV, TSV или Parquet, возможно в сжатом формате gzip). Датасет должен содержать столбцы id и embedding. Дополнительные столбцы игнорируются.

В файлах CSV/TSV эмбеддинги должны быть представлены в виде списка чисел с плавающей точкой, например "[ 1.0, 2.0, 3.0 ]". В файлах Parquet эмбеддинги могут быть как списком float32, так и уже сериализованными бинарными эмбеддингами YDB.

Пример запуска:

ydb workload vector import files

Доступные параметры

Имя Описание Значение по умолчанию
--input <путь> или -i <путь> Путь к файлу или директории с датасетом. Поддерживаемые форматы: CSV/TSV (с опциональным gzip-сжатием), Parquet. Импортируются только столбцы id и embedding. Обязательный
--format <формат> Формат файлов. Один из csv, tsv, parquet. Если указан, из директории импортируются только файлы соответствующего формата. Если не указан — формат определяется по расширению файла.
--embedding-column-name <имя> Альтернативное имя исходного столбца с эмбеддингами. embedding
--table <имя> Имя таблицы для загрузки данных. vector_index_workload
--index <имя> Имя векторного индекса, который будет построен после импорта. index
--index-type <тип> Тип индекса, строимого после импорта. Возможные значения: None, KmeansTree. Указание None отключает построение индекса. KmeansTree
--vector-type <тип> Тип векторов. Один из float, int8, uint8, bit. float
--vector-dimension <значение> Размерность векторов. 1024
--distance <значение> Функция расстояния или сходства. Один из inner_product, cosine, euclidean, manhattan. inner_product
--kmeans-tree-levels <значение> Количество уровней в дереве k-means. Если не задано, определяется сервером автоматически. См. тип kmeans-tree. Автоопределение
--kmeans-tree-clusters <значение> Количество кластеров k-means. Если не задано, определяется сервером автоматически. См. тип kmeans-tree. Автоопределение
--kmeans-tree-covering <значение> Создавать покрывающий индекс (1 — да, 0 — нет). 0
--kmeans-tree-prefixed <значение> Создавать prefixed (фильтрующий) индекс (1 — да, 0 — нет). Таблица должна быть создана с параметром --prefixed. 0

Примечание

Подробнее о параметрах построения индекса --kmeans-tree-* смотрите в разделе Тип kmeans-tree.

Общие параметры команды import

Имя Описание Значение по умолчанию
--upload-threads <значение> или -t <значение> Количество потоков исполнения для подготовки данных. Рассчитывается автоматически и равно числу доступных ядер на клиентской машине.
--bulk-size <значение> Размер порции для отправки данных в строках. 10000
--max-in-flight <значение> Максимальное количество порций данных, одновременно находящихся в обработке. 128
--file-output-path <значение> или -f <путь> Если эта опция установлена, данные не будут загружены в базу данных, а будут сохранены в каталоге <путь>.

Генерация синтетических данных

Генерация случайных векторов и загрузка их в таблицу. Компоненты векторов выбираются из равномерного распределения и сериализуются в бинарный формат эмбеддингов YDB.

ydb workload vector import generator

Доступные параметры

Имя Описание Значение по умолчанию
--rows <значение> Количество строк для генерации. 10000
--prefix-count <значение> Количество различных значений префикса для prefixed-индекса. 100
--seed <значение> Зерно для генератора случайных чисел. 42
--table <имя> Имя таблицы для загрузки данных. vector_index_workload
--index <имя> Имя векторного индекса, который будет построен после импорта. index
--index-type <тип> Тип индекса. Возможные значения: None, KmeansTree. KmeansTree
--vector-type <тип> Тип векторов. Один из float, int8, uint8, bit. float
--vector-dimension <значение> Размерность векторов. 1024
--distance <значение> Функция расстояния или сходства. inner_product
--kmeans-tree-levels <значение> Количество уровней в дереве k-means. Если не задано, определяется сервером автоматически. Автоопределение
--kmeans-tree-clusters <значение> Количество кластеров k-means. Если не задано, определяется сервером автоматически. Автоопределение
--kmeans-tree-covering <значение> Создавать покрывающий индекс. 0
--kmeans-tree-prefixed <значение> Создавать prefixed-индекс. 0

Примечание

Подробнее о параметрах построения индекса --kmeans-tree-* смотрите в разделе Тип kmeans-tree.

Общие параметры команды import

Имя Описание Значение по умолчанию
--upload-threads <значение> или -t <значение> Количество потоков исполнения для подготовки данных. Рассчитывается автоматически и равно числу доступных ядер на клиентской машине.
--bulk-size <значение> Размер порции для отправки данных в строках. 10000
--max-in-flight <значение> Максимальное количество порций данных, одновременно находящихся в обработке. 128
--file-output-path <значение> или -f <путь> Если эта опция установлена, данные не будут загружены в базу данных, а будут сохранены в каталоге <путь>.

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

Если данные загружались с параметром --index-type None, или если нужно построить дополнительный индекс с другими параметрами, векторный индекс можно построить на существующей таблице командой build-index.

ydb workload vector build-index --distance cosine

Доступные параметры

Имя Описание Значение по умолчанию
--table <имя> Имя таблицы, на которой строится индекс. vector_index_workload
--index <имя> Имя создаваемого индекса. index
--vector-type <тип> Тип векторов. Один из float, int8, uint8, bit. float
--vector-dimension <значение> Размерность векторов. 1024
--distance <значение> Функция расстояния или сходства. inner_product
--kmeans-tree-levels <значение> Количество уровней в дереве k-means. Если не задано, определяется сервером автоматически. Автоопределение
--kmeans-tree-clusters <значение> Количество кластеров k-means. Если не задано, определяется сервером автоматически. Автоопределение
--dry-run Только вывести DDL-запрос, не выполняя его.

Примечание

Подробнее о параметрах построения индекса --kmeans-tree-* смотрите в разделе Тип kmeans-tree.

Удаление векторного индекса

Удаление ранее созданного векторного индекса.

ydb workload vector drop-index

Доступные параметры

Имя Описание Значение по умолчанию
--table <имя> Имя таблицы, в которой находится индекс. vector_index_workload
--index <имя> Имя удаляемого индекса. index
--dry-run Только вывести DDL-запрос, не выполняя его.

Запуск нагрузки

Запустите нагрузочное тестирование в одном из двух режимов: select (векторный поиск) или upsert (вставка новых векторов).

Нагрузочное тестирование поисковых запросов

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

ydb workload vector run select --recall

Доступные параметры

Имя Описание Значение по умолчанию
--table <имя> Имя основной таблицы с векторами. vector_index_workload
--index <имя> Имя векторного индекса. index
--query-table <имя> Имя таблицы с тестовой выборкой векторов. Если не задано, используются случайные строки из основной таблицы.
--targets <значение> Размер тестовой выборки. 100
--limit <значение> Максимальное число записей в результатах одного запроса. 5
--kmeans-tree-clusters <значение> Максимальное число кластеров, проверяемых во время поиска (KMeansTreeSearchTopSize). 1
--recall Включить замер полноты приближённого поиска относительно точного.
--recall-threads <значение> Число параллельных запросов при оценке полноты. 10
--non-indexed Использовать настройки поиска из индекса, но искать без индекса, полным перебором.
--stale-ro Чтение в режиме StaleRO.

Важно

Обратите внимание на параметр --kmeans-tree-clusters — его увеличение значительно повышает полноту поиска ценой его замедления. Попробуйте значения в пределах от 1 до числа кластеров, указанного при создании индекса.

Общие параметры для всех видов нагрузки

Имя Описание Значение по умолчанию
--dry-run Не выполнять инициализационные запросы, а только вывести их текст.
--check-canonical или -c Использовать специальную версию запросов (они имеют детерминированные ответы) и сверять результаты с каноническими.
--output <значение> Имя файла, в котором будут сохранены результаты выполнения запросов. results.out
--iterations <значение> Количество выполнений каждого из запросов нагрузки. 1
--json <имя> Имя файла, в котором будет сохранена статистика выполнения запросов в формате json. Файл не сохраняется
--ministat <имя> Имя файла, в котором будет сохранена статистика выполнения запросов в формате ministat. Файл не сохраняется
--csv <имя> Имя файла для сохранения CSV-версии таблицы с результатами. Файл не сохраняется
--plan <имя> Имя файла для сохранения плана запроса. Если задано, то сохраняются файлы <имя>.<номер запроса>.explain и <имя>.<номер запроса>.<номер итерации> с планами в нескольких форматах: ast, json, svg и table. Планы не сохраняются.
--query-prefix <префикс> Префикс запроса. Каждый префикс будет добавлен отдельной строкой в начало каждого запроса. Если нужно указать несколько префиксов, используйте параметр несколько раз. По умолчанию не задан
--retries Количество повторных попыток выполнения каждого запроса 0
--include Имена, номера или диапазоны номеров запросов, которые нужно выполнить в рамках нагрузки. Указываются через запятую, например: 1,2,4-6. Все запросы
--exclude Имена, номера или диапазоны номеров запросов, которые нужно исключить из нагрузки. Указываются через запятую, например: 1,2,4-6.
--verbose или -v Выводить больше информации на экран в процессе выполнения запросов.
--global-timeout <значение> Общий таймаут на выполнение всех запросов. Задаётся в текстовом формате, например: 0.5s, 1m, 100us и т.д. Отсутствует. Время не ограничено.
--request-timeout <значение> Таймаут на выполнение каждой итерации каждого запроса. Задаётся в текстовом формате, например: 0.5s, 1m, 100us и т.д. Отсутствует. Время не ограничено.
--threads <значение> или -t <значение> Количество потоков, генерирующих нагрузку. Ноль означает, что запросы будут выполняться в основном потоке; при ином значении запросы будут перемешаны. 0
--stats <значение> Режим сбора расширенной статистики выполнения. Возможные значения: full, profile. full

Нагрузочное тестирование на запись

Непрерывно вставляет новые строки с векторами в таблицу, генерируя случайные эмбеддинги «на лету».

ydb workload vector run upsert

Доступные параметры

Имя Описание Значение по умолчанию
--table <имя> Имя таблицы для вставки. vector_index_workload
--index <имя> Имя векторного индекса. index
--bulk-size <значение> Количество строк в одном пакете upsert. 100
--prefixed Генерировать вставки со столбцом prefix (для prefixed-индексов).
--prefix-count <значение> Количество различных значений префикса. Используется только при указании --prefixed. 1000

Общие параметры для всех видов нагрузки

Имя Описание Значение по умолчанию
--dry-run Не выполнять инициализационные запросы, а только вывести их текст.
--check-canonical или -c Использовать специальную версию запросов (они имеют детерминированные ответы) и сверять результаты с каноническими.
--output <значение> Имя файла, в котором будут сохранены результаты выполнения запросов. results.out
--iterations <значение> Количество выполнений каждого из запросов нагрузки. 1
--json <имя> Имя файла, в котором будет сохранена статистика выполнения запросов в формате json. Файл не сохраняется
--ministat <имя> Имя файла, в котором будет сохранена статистика выполнения запросов в формате ministat. Файл не сохраняется
--csv <имя> Имя файла для сохранения CSV-версии таблицы с результатами. Файл не сохраняется
--plan <имя> Имя файла для сохранения плана запроса. Если задано, то сохраняются файлы <имя>.<номер запроса>.explain и <имя>.<номер запроса>.<номер итерации> с планами в нескольких форматах: ast, json, svg и table. Планы не сохраняются.
--query-prefix <префикс> Префикс запроса. Каждый префикс будет добавлен отдельной строкой в начало каждого запроса. Если нужно указать несколько префиксов, используйте параметр несколько раз. По умолчанию не задан
--retries Количество повторных попыток выполнения каждого запроса 0
--include Имена, номера или диапазоны номеров запросов, которые нужно выполнить в рамках нагрузки. Указываются через запятую, например: 1,2,4-6. Все запросы
--exclude Имена, номера или диапазоны номеров запросов, которые нужно исключить из нагрузки. Указываются через запятую, например: 1,2,4-6.
--verbose или -v Выводить больше информации на экран в процессе выполнения запросов.
--global-timeout <значение> Общий таймаут на выполнение всех запросов. Задаётся в текстовом формате, например: 0.5s, 1m, 100us и т.д. Отсутствует. Время не ограничено.
--request-timeout <значение> Таймаут на выполнение каждой итерации каждого запроса. Задаётся в текстовом формате, например: 0.5s, 1m, 100us и т.д. Отсутствует. Время не ограничено.
--threads <значение> или -t <значение> Количество потоков, генерирующих нагрузку. Ноль означает, что запросы будут выполняться в основном потоке; при ином значении запросы будут перемешаны. 0
--stats <значение> Режим сбора расширенной статистики выполнения. Возможные значения: full, profile. full

Очистка данных

Удаление таблиц, созданных для нагрузочного тестирования:

ydb workload vector clean

Алгоритм тестирования

Режим run select выполняет следующие шаги:

  1. Формируется тестовая выборка:
    • Если задана таблица с тестовой выборкой (--query-table), из неё выбираются первые --targets записей по порядку первичного ключа.
    • В противном случае выбираются случайные --targets записей из основной таблицы.
  2. Производится оценка полноты (если указан --recall):
    • Для каждого элемента тестовой выборки запускается по два запроса.
    • Первый запрос — точный векторный поиск (полный перебор) по близости к векторной колонке, формируя эталонное множество результатов R_exact.
    • Второй запрос — приближённый векторный поиск на основе векторного индекса, получая множество результатов R_approx.
    • Если выбран индекс с фильтрацией, то оба поиска проводятся только среди записей с соответствующими значениями колонок фильтров.
    • Вычисляется полнота приближённого поиска по формуле RapproxRexactRexact\frac{|R_{approx} \bigcap R_{exact}|}{|R_{exact}|} (здесь |A| — число элементов в множестве A, а A ∩ B — пересечение множеств A и B).
  3. Производится оценка скорости:
    • В течение заданного времени и в заданное число параллельных потоков запускаются запросы поиска по индексу.
    • Каждый запрос запускается для случайного элемента тестовой выборки.
    • Вычисляется средняя производительность (RPS) и время ответа на разных квантилях.

Примеры использования

Пример с генерируемыми данными

  1. Инициализируйте таблицу для нагрузочного тестирования:

    ydb workload vector init
    
  2. Сгенерируйте и загрузите синтетические векторы:

    ydb workload vector import generator --rows 100000 --distance cosine
    
  3. Запустите нагрузку на поиск:

    ydb workload vector run select --recall
    

    Пример вывода:

    Recall: 0.8950
    Window      Txs Txs/Sec Retries Errors  p50(ms) p95(ms) p99(ms) pMax(ms)
    1            100 100     0       0       5       8       12      15
    2             98 98      0       0       5       9       13      16
    ...
    
    Total       Txs Txs/Sec Retries Errors  p50(ms) p95(ms) p99(ms) pMax(ms)
    10          980 98.0    0       0       5       9       14      18
    

    Описание колонок:

    • Window — Порядковый номер временного окна (например, каждая секунда или фиксированный интервал).
    • Txs — Количество успешно выполненных транзакций в данном окне (или общее количество по всем окнам в итоговой строке).
    • Txs/Sec — Количество транзакций в секунду для данного окна (или среднее значение для итоговой строки).
    • Retries — Количество автоматических повторных попыток из-за временных ошибок (например, конфликтов или троттлинга).
    • Errors — Количество неисправимых ошибок.
    • p50(ms) — Медианная (50-й перцентиль) задержка выполнения транзакции в миллисекундах.
    • p95(ms) — Задержка на уровне 95-го перцентиля (миллисекунды).
    • p99(ms) — Задержка на уровне 99-го перцентиля (миллисекунды).
    • pMax(ms) — Максимальная наблюдаемая задержка в пределах окна (или глобальный максимум для итоговой строки).
  4. Запустите нагрузку на запись:

    ydb workload vector run upsert
    
  5. Удаление таблиц, созданных для нагрузочного тестирования:

    ydb workload vector clean
    

Пример с внешним датасетом

  1. Подготовьте таблицы и загрузите данные. Пример создания таблицы и загрузки данных приведён в рецепте Векторный индекс с загрузкой внешнего набора данных.

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

  2. Запустите нагрузку на поиск:

    ydb -e grpc://hostname:2135 -d /Root/testdb workload vector run select \
        --table wikipedia --index idx_vector \
        --query-table wikipedia_sample --recall
    

    Пример вывода:

    Recall: 0.8950
    Window      Txs Txs/Sec Retries Errors  p50(ms) p95(ms) p99(ms) pMax(ms)
    1            100 100     0       0       5       8       12      15
    2             98 98      0       0       5       9       13      16
    ...
    
    Total       Txs Txs/Sec Retries Errors  p50(ms) p95(ms) p99(ms) pMax(ms)
    10          980 98.0    0       0       5       9       14      18
    

Примечания

  • Поисковая нагрузка генерирует SQL-запросы выборки ближайших строк по векторному расстоянию из таблицы --table по индексу --index.
  • Указывать названия колонок (векторной, фильтра, первичного ключа) и функцию расстояния не нужно — они извлекаются автоматически из определения индекса.
  • Случайный выбор тестовых векторов из таблицы --table работает только в том случае, если первичный ключ таблицы — целочисленный.
  • Если используется --query-table, в обеих таблицах имена векторной колонки и колонки фильтра должны совпадать.
  • Оценка полноты поиска (--recall) проводится отдельным этапом перед тестированием производительности и показывает среднюю долю совпадения результатов поиска по индексу и полным перебором (от 0 до 1).

Подготовка тестовой выборки из большой таблицы

Важно

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

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

CREATE TABLE vector_index_sample (
    id Uint64 NOT NULL,
    prefix Uint64 NOT NULL,
    embedding String NOT NULL,
    PRIMARY KEY (id)
);

Наполнение таблицы случайной выборкой приблизительно 1000 строк из большой таблицы:

INSERT INTO vector_index_sample
SELECT id, prefix, embedding FROM large_table
WHERE RandomNumber(id) < 0xFFFFFFFFFFFFFFFF / <число_строк_в_таблице> * 1000;

Совет

Приблизительное число строк в таблице можно посмотреть в статистике таблицы, не выполняя SELECT COUNT(*).