Включение и использование расширения DiskANN на гибком сервере База данных Azure для PostgreSQL

DiskANN — это масштабируемый приблизительный алгоритм поиска ближайших соседей для эффективного векторного поиска в любом масштабе. Он предлагает высокий уровень отзыва, высокий уровень запросов в секунду и низкую задержку запросов, даже для наборов данных в миллиардных точках. Эти характеристики делают его мощным инструментом для обработки больших объемов данных.

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

Расширение pg_diskann добавляет поддержку использования DiskANN для эффективного индексирования и поиска векторов.

Включить pg_diskann

Чтобы использовать pg_diskann расширение на База данных Azure для PostgreSQL гибком сервере, необходимо разрешить расширение на уровне сервера. Затем необходимо создать расширение для каждой базы данных, в которой требуется использовать функциональные возможности, предоставляемые расширением.

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

CREATE EXTENSION IF NOT EXISTS pg_diskann;

Кроме того, можно пропустить этап явного разрешения и создания vector расширения, а затем выполнить предыдущую команду, добавив CASCADE условие. Этот пункт позволяет PostgreSQL неявно выполнять CREATE EXTENSION для расширения, от которого он зависит. Для этого выполните следующую команду:

CREATE EXTENSION IF NOT EXISTS pg_diskann CASCADE;

Чтобы удалить расширение из базы данных, к которой вы подключены в данный момент, выполните следующую команду:

DROP EXTENSION IF EXISTS pg_diskann;

Использование метода доступа к индексу diskann

После установки расширения можно создать diskann индекс в столбце таблицы, который содержит векторные данные. Например, чтобы создать индекс в embedding столбце demo таблицы, используйте следующую команду:

CREATE TABLE demo (
 id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
 embedding public.vector(3)
 -- other columns
);

-- insert dummy data
INSERT INTO demo (embedding) VALUES
('[1.0, 2.0, 3.0]'),
('[4.0, 5.0, 6.0]'),
('[7.0, 8.0, 9.0]');

-- create a diskann index by using Cosine distance operator
CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)

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

Следующий запрос находит пять ближайших соседей в векторе [2.0, 3.0, 4.0]:

SELECT id, embedding
FROM demo
ORDER BY embedding <=> '[2.0, 3.0, 4.0]'
LIMIT 5;

Postgres автоматически решает, когда следует использовать индекс DiskANN. Если индекс не используется в ситуации, когда требуется его использование, выполните следующую команду:

-- Explicit Transcation block to force use for DiskANN index.

BEGIN;
SET LOCAL enable_seqscan TO OFF;
-- Similarity search queries
COMMIT;

Это важно

Установка значения enable_seqscan в off заставляет планировщик избегать использования плана последовательного сканирования, если доступны другие методы. Так как он отключен с помощью SET LOCAL команды, параметр вступает в силу только для текущей транзакции. После COMMIT или ROLLBACK параметр уровня сеанса вновь вступает в силу. Если запрос включает в себя другие таблицы, параметр также не рекомендует использовать последовательные проверки во всех из них.

Эффективное масштабирование с помощью Quantization (предварительная версия)

DiskANN использует квантизацию продуктов (PQ) для резкого уменьшения объема памяти векторов. В отличие от других методов квантизации, алгоритм PQ может более эффективно сжимать векторы, значительно повышая производительность.  Используя PQ, DiskANN может хранить больше данных в памяти, уменьшать необходимость доступа к более медленному хранилищу и использовать меньше вычислений при сравнении сжатых векторов. Это приводит к повышению производительности и значительной экономии затрат при работе с большими объемами данных (> 1 млн строк).

Это важно

Поддержка квантизации продуктов в DiskANN доступна начиная с pg_diskann версии 0.6 и выше.

Чтобы уменьшить размер индекса и поместить больше данных в память, используйте PQ:

CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann(embedding vector_cosine_ops) 
WITH(
    product_quantized=true
    );    

Повысить точность при использовании PQ с повторным векторным ранжированием

Повторное ранжирование с использованием полных векторов — это метод, применяемый в системах поиска приблизительных ближайших соседей (ANN), таких как DiskANN с квантизацией произведения (Product Quantization, PQ), для повышения точности результатов путём повторного упорядочивания N лучших найденных кандидатов с использованием исходных несжатых полноточных векторов. Этот метод повторного ранжирования основан исключительно на точных метриках векторного сходства (например, косинусном сходстве или евклидовом расстоянии). Этот метод отличается отповторного использования модели ранжирования.

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

  1. Первоначальный приблизительный поиск: внутренний запрос использует DiskANN для получения первых 50 приблизительных ближайших соседей на основе косинусного расстояния между хранимыми векторами представлений и вектором запроса. Этот шаг является быстрым и эффективным, используя возможности индексирования DiskANN.

  2. Точное переназначение: внешний запрос переупорядочивает эти 50 результатов по фактически вычисленному расстоянию и возвращает первые 10 наиболее релевантных результатов.

Вот пример переранжирования с использованием этого двухэтапного подхода:

SELECT id
FROM (
    SELECT id, embedding <=> %s::vector AS distance
    FROM demo
    ORDER BY embedding <=> %s::vector asc
    LIMIT 50
) AS t
ORDER BY t.distance
LIMIT 10;

Замечание

Замените %s вектором запроса. Вы можете использовать azure_ai для создания вектора запросов непосредственно в Postgres.

Этот подход балансирует скорость (с помощью приблизительного поиска) и точность (с помощью полного векторного повторения), обеспечивая высококачественные результаты без сканирования всего набора данных.

Поддержка встраиваний высоких измерений

Передовые приложения генеративного ИИ часто используют высокоразмерные модели встраивания, такие как text-embedding-3-large, чтобы обеспечить высокую точность. Однако традиционные методы индексирования, такие как HNSW в pgvector , ограничены векторами до 2000 измерений, что ограничивает использование этих мощных моделей.

Начиная с версии pg_diskann v0.6 и выше, DiskANN поддерживает индексирование векторов размерностью до 16 000, что значительно расширяет возможности для рабочих нагрузок ИИ с высокой точностью.

Это важно

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

Рекомендуемые параметры:

  • product_quantized: задано значение true
  • pq_param_num_chunks: Установите значение на одну треть размерности эмбеддинга для оптимальной производительности.
  • pq_param_training_samples: автоматически определяется на основе размера таблицы, если только явно не задано.

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

Ускорение сборки индекса

Чтобы улучшить время сборки индекса, попробуйте выполнить следующие рекомендации.

Использовать больше памяти

Чтобы ускорить создание индекса, увеличьте память, выделенную на сервере PostgreSQL для сборки индекса. Укажите использование памяти с помощью maintenance_work_mem параметра.

-- Set the parameters
SET maintenance_work_mem = '8GB'; -- Depending on your resources

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

CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)

Подсказка

Масштабируйте ресурсы памяти во время сборки индекса, чтобы повысить скорость индексирования, а затем уменьшить масштаб при завершении индексирования.

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

Чтобы ускорить создание индекса, используйте параллельные рабочие роли. Укажите количество рабочих ролей с помощью parallel_workers параметра хранилища инструкции CREATE TABLE при создании таблицы. Позже это число можно скорректировать с помощью части SET инструкции ALTER TABLE.

CREATE TABLE demo (
	id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
	embedding public.vector(3)
) WITH (parallel_workers = 4);
ALTER TABLE demo SET (parallel_workers = 8);

Команда CREATE INDEX использует указанное число параллельных рабочих ролей в зависимости от доступных ресурсов для построения индекса.

CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)

Это важно

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

Если вы хотите создать индекс с помощью параллельных рабочих процессов, задайте соответствующие значения параметров max_parallel_workers, max_worker_processes и max_parallel_maintenance_workers. Дополнительные сведения об этих параметрах см. в параметрах, которые управляют использованием ресурсов и асинхронным поведением.

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

-- Set the parameters
SET max_parallel_workers = 8;
SET max_worker_processes = 8; -- Note: Requires server restart
SET max_parallel_maintenance_workers = 4;

Дополнительные сведения о других параметрах настройки этих параметров на гибком сервере База данных Azure для PostgreSQL см. в разделе Configure parameters.

Замечание

Параметр max_worker_processes вступает в силу после перезапуска сервера.

Если конфигурация этих параметров и доступных ресурсов на сервере не позволяют запускать параллельные задачи, PostgreSQL автоматически возвращается к созданию индекса в непараллельном режиме.

Параметры конфигурации

При создании diskann индекса укажите различные параметры для управления его поведением.

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

  • max_neighbors: максимальное число ребер на узел в графе. Значение по умолчанию — 32. Более высокое значение может улучшить запоминание до определенного момента.
  • l_value_ib: размер списка поиска во время сборки индекса. Значение по умолчанию — 100. Более высокое значение делает сборку медленнее, но индекс имеет более высокое качество.
  • product_quantized: включает квантизацию продуктов для более эффективного поиска. По умолчанию используется значение false.
  • pq_param_num_chunks: количество блоков для квантизации продукта. Значение по умолчанию равно 0, что означает, что система автоматически определяет это значение исходя из размерности эмбеддингов. Используйте одну треть исходного числа размерностей эмбеддинга.
  • pq_param_training_samples: число векторов, используемых для обучения опорной таблицы PQ. Значение по умолчанию равно 0, что означает, что система автоматически определяет значение на основе размера таблицы.
CREATE INDEX demo_embedding_diskann_custom_idx ON demo USING diskann (embedding vector_cosine_ops)
WITH (
 max_neighbors = 48,
 l_value_ib = 100,
 product_quantized=true, 
 pq_param_num_chunks = 0,
 pq_param_training_samples = 0
 );

Параметры расширения

  • diskann.iterative_search: управляет поведением поиска.

    Конфигурации для diskann.iterative_search:

    • relaxed_order (по умолчанию): позволяет DiskANN итеративно проводить поиск по графу партиями diskann.l_value_is, пока не будет достигнуто требуемое количество кортежей, возможно ограниченное условием LIMIT. Этот параметр может привести к тому, что результаты не упорядочены.

    • strict_order: аналогично relaxed_order, но гарантирует, что результаты возвращаются в строгом порядке, отсортированных по расстоянию.

    • off: использует неитеративную функцию поиска. Предпринимается попытка извлечь кортежи diskann.l_value_is за один шаг. Неитеративный поиск может возвращать только максимум diskann.l_value_is векторов для запроса независимо от LIMIT предложения или количества кортежей, соответствующих запросу.

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

    SET diskann.iterative_search TO 'strict_order';
    

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

    BEGIN;
    SET LOCAL diskann.iterative_search TO 'strict_order';
    -- All your queries
    COMMIT;
    
  • diskann.l_value_is: L-значение для сканирования индекса (по умолчанию — 100). Увеличение значения улучшает вспоминание, но может замедлить запросы.

    Чтобы изменить значение L для сканирования индекса до 20 для всех запросов, выполняемых в текущем сеансе, выполните следующую инструкцию:

    SET diskann.l_value_is TO 20;
    

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

    BEGIN;
    SET LOCAL diskann.l_value_is TO 20;
    -- All your queries
    COMMIT;
    
Размер набора данных (строки) Тип параметра Имя Рекомендуемое значение
<1 млн Сборка индекса l_value_ib 100
<1 млн Сборка индекса max_neighbors 32
<1 млн Время запроса diskann.l_value_is 100
 
1M-50M Сборка индекса l_value_ib 100
1M-50M Сборка индекса max_neighbors 64
1M-50M Сборка индекса product_quantized true
1M-50M Время запроса diskann.l_value_is 100
 
>50 млн Сборка индекса l_value_ib 100
>50 млн Сборка индекса max_neighbors 96
>50 млн Сборка индекса product_quantized true
>50 млн Время запроса diskann.l_value_is 100

Замечание

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

Ход ВЫПОЛНЕНИЯ CREATE INDEX и REINDEX

Начиная с PostgreSQL 12, с помощью pg_stat_progress_create_index можно отслеживать ход выполнения операций CREATE INDEX и REINDEX.

SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;

Дополнительные сведения о возможных этапах, с помощью которых выполняется операция CREATE INDEX или REINDEX, см. в разделе "Этапы CREATE INDEX".

Выбор функции доступа к индексу

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

pg_diskann поддерживает следующие операторы расстояния:

  • vector_l2_ops: <-> Евклидеан расстояние
  • vector_cosine_ops: <=> Косинус расстояние
  • vector_ip_ops: <#> внутренний продукт

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

Ошибка: : assertion left == right failed left: 40 right: 0

  • Версия общедоступной версии DiskANN версии 0.6.x содержит критические изменения в формате метаданных индекса. Индексы, созданные с помощью версии 0.5.x, не совместимы с операциями вставки v0.6.x. Если вы пытаетесь вставить в таблицу с устаревшим индексом, вы получите ошибку, даже если индекс отображается допустимым.

  • При возникновении этой ошибки устраните ее следующим образом:

    • Вариант 1: Выполнение операторов REINDEX или REDINDEX CONCURRENTLY на индексе.

    • Вариант 2. Перестроение индекса.

      DROP INDEX your_index_name;
      CREATE INDEX your_index_name ON your_table USING diskann(your_vector_column vector_cosine_ops);
      
      

Ошибка: : diskann index needs to be upgraded to version 2...

  • При возникновении этой ошибки устраните ее следующим образом:
    • Вариант 1: Выполнение операторов REINDEX или REDINDEX CONCURRENTLY на индексе.

    • Вариант 2. Так как REINDEX это может занять много времени, расширение также предоставляет определяемую пользователем функцию upgrade_diskann_index(), которая обновляет индекс быстрее, когда это возможно.

      Чтобы обновить индекс, выполните следующую инструкцию:

      SELECT upgrade_diskann_index('demo_embedding_diskann_custom_idx');
      

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

      SELECT upgrade_diskann_index(pg_class.oid)
      FROM pg_class
      JOIN pg_am ON (pg_class.relam = pg_am.oid)
      WHERE pg_am.amname = 'diskann';