Перейти к содержимому
Последнее обновление

Векторный поиск

Начиная с версии 4.0 Apache Doris имеет встроенную поддержку векторного поиска ANN (Approximate Nearest Neighbor, приближённый поиск ближайших соседей). Решение основано на Faiss и индексах HNSW и IVF и обеспечивает поиск TopN и поиск по диапазону среди миллиардов векторов с задержкой в миллисекунды.

Сценарии применения​

Векторный поиск лежит в основе RAG (Retrieval-Augmented Generation, генерация с дополнением из результатов поиска) и мультимодального поиска. Типичные области применения:

  • Поиск для RAG: извлечение Top-K текстовых фрагментов, наиболее релевантных запросу пользователя, из большой базы знаний и использование их как основы для генерации ответов LLM. Это уменьшает проблемы, связанные с галлюцинациями и устареванием знаний.
  • Мультимодальный поиск: преобразование изображений, аудио, видео и других данных в векторы для поиска по семантическому сходству. Например, в медицинских системах вопросов и ответов можно находить истории болезни и публикации, которые помогают формировать диагностические рекомендации.
  • Рекомендательные системы: поиск «похожего, но не идентичного» контента с помощью поиска по диапазону для повышения разнообразия рекомендаций.
  • Обнаружение аномалий: поиск точек данных, отклоняющихся от нормальных закономерностей.

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

Быстрая навигация​

СценарийРаздел
Узнать, как создать векторный индексПриближённый поиск ближайших соседей
Реализовать поиск по косинусному сходствуИспользование косинусного сходства
Фильтровать по пороговому расстояниюПриближённый поиск по диапазону
Совместить TopN с условиями диапазонаКомбинированный поиск
Фильтровать по другим столбцам перед поиском ANNПоиск ANN с фильтрами
Настроить параметры выполнения запросовПараметры запросов
Сэкономить память и уменьшить размер индексаКвантование векторов
Повысить QPS и уменьшить задержкуНастройка производительности
Использовать Python SDKPython SDK
Узнать об ограничениях использованияОграничения использования

Doris не вводит новый тип данных. Векторы хранятся в виде Array<Float> фиксированной длины, а для поиска по расстоянию предоставляется индекс ANN на основе Faiss.

Пример создания таблицы​

Рассмотрим пример с распространённым набором данных SIFT:

CREATE TABLE sift_1M (
id int NOT NULL,
embedding array<float> NOT NULL COMMENT "",
INDEX ann_index (embedding) USING ANN PROPERTIES(
"index_type"="hnsw",
"metric_type"="l2_distance",
"dim"="128",
"quantizer"="flat"
)
) ENGINE=OLAP
DUPLICATE KEY(id) COMMENT "OLAP"
DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES (
"replication_num" = "1"
);

Значение основных параметров:

  • index_type: алгоритм индекса. Допустимые варианты: hnsw (Hierarchical Navigable Small World), ivf (индекс Inverted File) или ivf_on_disk (вариант IVF, в котором инвертированные списки записываются на диск, а доступ к ним осуществляется через кэш).
  • metric_type: метрика расстояния. Значение l2_distance означает использование расстояния L2 в качестве функции расстояния.
  • dim: размерность вектора. Значение 128 означает, что каждый вектор в этом столбце имеет длину 128.
  • quantizer: схема кодирования. Значение flat означает, что каждая координата хранится как исходное значение float32.

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

ПараметрОбязательныйПоддерживаемые / допустимые значенияПо умолчаниюОписание
index_typeДаhnsw, ivf, ivf_on_disk(нет)Задаёт алгоритм индекса ANN. Сейчас поддерживаются HNSW, IVF в памяти и IVF On-Disk.
metric_typeДаl2_distance, inner_product(нет)Задаёт метрику сходства / расстояния между векторами. l2_distance означает евклидово расстояние. inner_product можно использовать для поиска по косинусному сходству, но сначала векторы необходимо нормализовать.
dimДаПоложительное целое число (> 0)(нет)Задаёт размерность вектора. Все загружаемые впоследствии векторы должны иметь такую же размерность, иначе возникнет ошибка.
nlistНетПоложительное целое число1024Количество инвертированных корзин в IVF. Действует при index_type=ivf или ivf_on_disk. Большее значение обычно позволяет лучше сбалансировать полноту поиска и скорость, но увеличивает затраты на построение.
max_degreeНетПоложительное целое число32Максимальное количество соседей у узла в графе HNSW (M). Влияет на потребление памяти индексом и производительность поиска.
ef_constructionНетПоложительное целое число40Размер очереди кандидатов при построении HNSW (efConstruction). Большее значение повышает качество графа, но замедляет построение.
quantizerНетflat, sq8, sq4, pqflatСхема кодирования / квантования векторов. flat: хранение исходных значений. sq8 / sq4: скалярное квантование (8 / 4 бита). pq: продуктовое квантование.
pq_mОбязательный при quantizer=pqПоложительное целое число(нет)Количество подвекторов, на которые разбивается исходный вектор высокой размерности. dim должен делиться на pq_m без остатка.
pq_nbitsОбязательный при quantizer=pqПоложительное целое число(нет)Количество битов для квантования каждого подвектора, определяющее размер кодовой книги подпространства (k = 2 ^ pq_nbits). В Faiss это значение обычно не должно превышать 24.

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

Загрузите набор данных SIFT через S3 TVF:

INSERT INTO sift_1M
SELECT *
FROM S3(
"uri" = "https://selectdb-customers-tools-bj.oss-cn-beijing.aliyuncs.com/sift_database.tsv",
"format" = "csv");

select count(*) from sift_1M
--------------

+----------+
| count(*) |
+----------+
| 1000000 |
+----------+

Пример запроса​

Вызов l2_distance_approximate / inner_product_approximate задействует индекс ANN.

Правила вызова:

  • Имя функции должно точно соответствовать параметру индекса metric_type:
    • metric_type=l2_distance → используйте l2_distance_approximate
    • metric_type=inner_product → используйте inner_product_approximate
  • Порядок сортировки:
    • Для расстояния L2 используется сортировка по возрастанию (ORDER BY dist ASC, меньшее значение означает большую близость).
    • Для скалярного произведения используется сортировка по убыванию (ORDER BY dist DESC, большее значение означает большую близость).
SELECT id,
l2_distance_approximate(
embedding,
[0,11,77,24,3,0,0,0,28,70,125,8,0,0,0,0,44,35,50,45,9,0,0,0,4,0,4,56,18,0,3,9,16,17,59,10,10,8,57,57,100,105,125,41,1,0,6,92,8,14,73,125,29,7,0,5,0,0,8,124,66,6,3,1,63,5,0,1,49,32,17,35,125,21,0,3,2,12,6,109,21,0,0,35,74,125,14,23,0,0,6,50,25,70,64,7,59,18,7,16,22,5,0,1,125,23,1,0,7,30,14,32,4,0,2,2,59,125,19,4,0,0,2,1,6,53,33,2]
) AS distance
FROM sift_1M
ORDER BY distance
LIMIT 10;
--------------

+--------+----------+
| id | distance |
+--------+----------+
| 178811 | 210.1595 |
| 177646 | 217.0161 |
| 181997 | 218.5406 |
| 181605 | 219.2989 |
| 821938 | 221.7228 |
| 807785 | 226.7135 |
| 716433 | 227.3148 |
| 358802 | 230.7314 |
| 803100 | 230.9112 |
| 866737 | 231.6441 |
+--------+----------+
10 rows in set (0.02 sec)

Для сравнения с точными результатами используйте l2_distance / inner_product (без суффикса _approximate). В этом примере точный поиск занимает около 290 мс; при использовании индекса ANN задержка запроса уменьшается примерно с 290 мс до 20 мс.

10 rows in set (0.29 sec)

Механизм выполнения​

Индекс ANN строится на уровне сегментов. В распределённой таблице:

  1. Каждый сегмент возвращает свои локальные результаты TopN.
  2. Оператор TopN объединяет результаты из разных tablet и сегментов, формируя глобальный TopN.

Использование косинусного сходства​

Параметр индекса ANN в Doris metric_type сейчас поддерживает только l2_distance и inner_product и не поддерживает cosine напрямую. Если в приложении используется косинусное сходство, его можно эквивалентно заменить скалярным произведением с помощью нормализации.

Порядок действий​

  1. Перед записью: выполните L2-нормализацию векторов (приведите их к единичной длине).
  2. При создании индекса: используйте metric_type="inner_product".
  3. При выполнении запроса: используйте inner_product_approximate(...) с сортировкой ORDER BY ... DESC.

Пример:

CREATE INDEX idx_emb_cosine ON your_table (embedding) USING ANN PROPERTIES (
"index_type"="hnsw",
"metric_type"="inner_product",
"dim"="768"
);

Обоснование эквивалентности​

  • Формула косинусного сходства: cos(x, y) = (x · y) / (||x|| ||y||)
  • Для L2-нормализованных векторов (||x|| = ||y|| = 1): cos(x, y) = x · y

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


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

Типичные области применения:

  • В рекомендательных системах: поиск «близкого, но не идентичного» контента для повышения разнообразия.
  • При обнаружении аномалий: поиск точек данных, отклоняющихся от нормальных закономерностей.

Пример: подсчёт строк, у которых расстояние L2 до целевого вектора больше 300:

SELECT count(*)
FROM sift_1M
WHERE l2_distance_approximate(
embedding,
[0,11,77,24,3,0,0,0,28,70,125,8,0,0,0,0,44,35,50,45,9,0,0,0,4,0,4,56,18,0,3,9,16,17,59,10,10,8,57,57,100,105,125,41,1,0,6,92,8,14,73,125,29,7,0,5,0,0,8,124,66,6,3,1,63,5,0,1,49,32,17,35,125,21,0,3,2,12,6,109,21,0,0,35,74,125,14,23,0,0,6,50,25,70,64,7,59,18,7,16,22,5,0,1,125,23,1,0,7,30,14,32,4,0,2,2,59,125,19,4,0,0,2,1,6,53,33,2])
> 300
--------------

+----------+
| count(*) |
+----------+
| 999271 |
+----------+
1 row in set (0.19 sec)

Индекс ANN также ускоряет поиск по диапазону: система сначала быстро отбирает множество векторов-кандидатов, а затем вычисляет точное значение приближённого расстояния, существенно сокращая накладные расходы. Сейчас поддерживаются следующие условия диапазона: >, >=, <, <=.


Комбинированный поиск совмещает ANN TopN и фильтрацию по диапазону в одном SQL-запросе и возвращает TopN, удовлетворяющий ограничению диапазона.

SELECT id,
l2_distance_approximate(
embedding, [0,11,77,24,3,0,0,0,28,70,125,8,0,0,0,0,44,35,50,45,9,0,0,0,4,0,4,56,18,0,3,9,16,17,59,10,10,8,57,57,100,105,125,41,1,0,6,92,8,14,73,125,29,7,0,5,0,0,8,124,66,6,3,1,63,5,0,1,49,32,17,35,125,21,0,3,2,12,6,109,21,0,0,35,74,125,14,23,0,0,6,50,25,70,64,7,59,18,7,16,22,5,0,1,125,23,1,0,7,30,14,32,4,0,2,2,59,125,19,4,0,0,2,1,6,53,33,2]) as dist
FROM sift_1M
WHERE l2_distance_approximate(
embedding, [0,11,77,24,3,0,0,0,28,70,125,8,0,0,0,0,44,35,50,45,9,0,0,0,4,0,4,56,18,0,3,9,16,17,59,10,10,8,57,57,100,105,125,41,1,0,6,92,8,14,73,125,29,7,0,5,0,0,8,124,66,6,3,1,63,5,0,1,49,32,17,35,125,21,0,3,2,12,6,109,21,0,0,35,74,125,14,23,0,0,6,50,25,70,64,7,59,18,7,16,22,5,0,1,125,23,1,0,7,30,14,32,4,0,2,2,59,125,19,4,0,0,2,1,6,53,33,2])
> 300
ORDER BY dist limit 10
--------------

+--------+----------+
| id | dist |
+--------+----------+
| 243590 | 300.005 |
| 549298 | 300.0317 |
| 429685 | 300.0533 |
| 690172 | 300.0916 |
| 123410 | 300.1333 |
| 232540 | 300.1649 |
| 547696 | 300.2066 |
| 855437 | 300.2782 |
| 589017 | 300.3048 |
| 930696 | 300.3381 |
+--------+----------+
10 rows in set (0.12 sec)

Предварительная и последующая фильтрация​

СтратегияСмыслПреимуществаНедостатки
Предварительная фильтрация (используется в Doris)Сначала применить предикат, затем выбрать TopN из оставшегося множестваВысокая полнота поискаОтносительно низкая скорость
Последующая фильтрацияСначала выбрать TopN, затем отфильтроватьВысокая скоростьМожет значительно снизить полноту поиска

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


Поиск ANN с фильтрами​

Поиск ANN с фильтрами означает применение других предикатов перед выполнением ANN TopN и возврат TopN, удовлетворяющего условиям.

Следующий пример с векторами размерности 8 иллюстрирует процесс гибридного поиска:

CREATE TABLE ann_with_fulltext (
id int NOT NULL,
embedding array<float> NOT NULL,
comment String NOT NULL,
value int NULL,
INDEX idx_comment(`comment`) USING INVERTED PROPERTIES("parser" = "english") COMMENT 'inverted index for comment',
INDEX ann_embedding(`embedding`) USING ANN PROPERTIES("index_type"="hnsw","metric_type"="l2_distance","dim"="8")
) DUPLICATE KEY (`id`)
DISTRIBUTED BY HASH(`id`) BUCKETS 1
PROPERTIES("replication_num"="1");

INSERT INTO ann_with_fulltext VALUES
(1, [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8], 'this is about music', 10),
(2, [0.2,0.1,0.5,0.3,0.9,0.4,0.7,0.1], 'sports news today', 20),
(3, [0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2], 'latest music trend', 30),
(4, [0.05,0.06,0.07,0.08,0.09,0.1,0.2,0.3], 'politics update',40)

Для вектора запроса пользователя [0.1,0.1,0.2,0.2,0.3,0.3,0.4,0.4] найдём 2 наиболее похожих документа только среди тех, у которых comment содержит «music»:

SELECT id, comment,
l2_distance_approximate(embedding, [0.1,0.1,0.2,0.2,0.3,0.3,0.4,0.4]) AS dist
FROM ann_with_fulltext
WHERE comment MATCH_ANY 'music' -- Filter using the inverted index first
ORDER BY dist ASC -- Then perform ANN TopN over the filtered result set
LIMIT 2;

+------+---------------------+----------+
| id | comment | dist |
+------+---------------------+----------+
| 1 | this is about music | 0.663325 |
| 3 | latest music trend | 1.280625 |
+------+---------------------+----------+
2 rows in set (0.04 sec)
Важный совет

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


Параметры запросов​

Помимо параметров, задаваемых при построении индекса HNSW, поведение на этапе выполнения запроса можно настраивать с помощью переменных сеанса:

Переменная сеансаПо умолчаниюОписание
hnsw_ef_search32Параметр поиска EF для индекса HNSW. Управляет максимальной длиной очереди кандидатов во время поиска. Большее значение повышает точность ценой увеличения задержки.
hnsw_check_relative_distancetrueВключает или отключает механизм проверки относительного расстояния для повышения точности поиска HNSW.
hnsw_bounded_queuetrueОпределяет, использовать ли ограниченную очередь с приоритетами для оптимизации производительности поиска HNSW.

Квантование векторов​

При кодировании FLAT индекс HNSW, включающий исходные векторы и структуру графа, может потреблять большой объём памяти. Для работы HNSW должен полностью находиться в памяти, поэтому на очень больших наборах данных это легко становится узким местом.

Doris предоставляет две категории схем квантования:

КвантованиеПринципПоддержка в Doris
Скалярное квантование (SQ)Сжимает каждую координату FLOAT32 для уменьшения потребления памятиsq8 (INT8), sq4 (INT4)
Продуктовое квантование (PQ)Разбивает вектор высокой размерности и квантует каждый подвектор отдельноpq

Пример скалярного квантования (SQ)​

CREATE TABLE sift_1M (
id int NOT NULL,
embedding array<float> NOT NULL COMMENT "",
INDEX ann_index (embedding) USING ANN PROPERTIES(
"index_type"="hnsw",
"metric_type"="l2_distance",
"dim"="128",
"quantizer"="sq8" -- Use INT8 for quantization
)
) ENGINE=OLAP
DUPLICATE KEY(id) COMMENT "OLAP"
DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES (
"replication_num" = "1"
);

В тестах на наборах данных Cohere-MEDIUM-1M и Cohere-LARGE-10M с размерностью 768 квантование SQ8 уменьшает размер индекса примерно до 1/3 от размера FLAT.

Сравнение схем квантования​

Набор данныхРазмерность вектораСхема хранения / индексаОбщий объём на дискеДанныеИндексПримечания
Cohere-MEDIUM-1M768DDoris (FLAT)5.647 GB (2.533 + 3.114)2.533 GB3.114 GB1M векторов, исходные данные + индекс HNSW FLAT
Cohere-MEDIUM-1M768DDoris SQ INT83.501 GB (2.533 + 0.992)2.533 GB0.992 GBСимметричное квантование INT8
Cohere-MEDIUM-1M768DDoris PQ (pq_m=384, pq_nbits=8)3.149 GB (2.535 + 0.614)2.535 GB0.614 GBПродуктовое квантование
Cohere-LARGE-10M768DDoris (FLAT)56.472 GB (25.328 + 31.145)25.328 GB31.145 GB10M векторов
Cohere-LARGE-10M768DDoris SQ INT835.016 GB (25.329 + 9.687)25.329 GB9.687 GBКвантование INT8, размер индекса значительно меньше

Продуктовое квантование (PQ)​

Doris также поддерживает продуктовое квантование, но для использования PQ требуются дополнительные параметры:

  • pq_m: количество подвекторов, на которые разбивается исходный вектор высокой размерности. Размерность вектора dim должна делиться на pq_m без остатка.
  • pq_nbits: количество битов для квантования каждого подвектора, определяющее размер кодовой книги подпространства. В Faiss это значение обычно не должно превышать 24.
Примечание

На этапе обучения квантование PQ предъявляет требования к обучающим данным: точек должно быть не меньше, чем центров кластеров. То есть количество обучающих точек n >= 2 ^ pq_nbits.

CREATE TABLE sift_1M (
id int NOT NULL,
embedding array<float> NOT NULL COMMENT "",
INDEX ann_index (embedding) USING ANN PROPERTIES(
"index_type"="hnsw",
"metric_type"="l2_distance",
"dim"="128",
"quantizer"="pq", -- Use PQ for quantization
"pq_m"="2", -- Required when using PQ. Number of low-dim sub-vectors the high-dim vector is split into
"pq_nbits"="2" -- Required when using PQ. Number of bits per subspace codebook
)
) ENGINE=OLAP
DUPLICATE KEY(id) COMMENT "OLAP"
DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES (
"replication_num" = "1"
);

Затраты на квантование​

Квантование увеличивает накладные расходы на построение индекса: на этом этапе требуется множество вычислений расстояния, и каждое вычисление должно декодировать квантованные значения. Для векторов размерности 128 время построения растёт с количеством строк, а SQ может увеличить затраты на построение примерно в 10 раз по сравнению с FLAT.

ЗАТРАТЫ НА ПОСТРОЕНИЕ ANN-SQ


Настройка производительности​

Векторный поиск представляет собой типичный сценарий точечных запросов с использованием вторичного индекса. Если вам важны высокий QPS и низкая задержка, воспользуйтесь рекомендациями ниже. После настройки на машинах FE 32C 64GB + BE 32C 64GB Doris может достигать 3000+ QPS (набор данных: Cohere-MEDIUM-1M).

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

Число одновременных запросовСхемаQPSСредняя задержка (с)Задержка P99 (с)Использование CPUПолнота поиска
240Doris3340.43990.0713681680.16339982540%91.00%
240Doris SQ INT83188.63590.0747288520.16037019540%88.26%
240Doris SQ INT42818.22910.0846638680.17482681543%80.38%
240Doris, полный перебор3.678725.55487882629.363227973100%100.00%
480Doris4155.72200.1133872710.26108607560%91.00%
480Doris SQ INT83833.11300.1230402140.27691286750%88.26%
480Doris SQ INT43431.05380.1376369950.28163124957%80.38%
480Doris, полный перебор3.678725.55487882629.363227973100%100.00%

Используйте подготовленные запросы​

Распространённые модели эмбеддингов обычно выдают векторы размерности 768 или выше. Если вставить такой вектор непосредственно в SQL в виде литерала, время синтаксического разбора может превысить время самого выполнения. Поэтому рекомендуется использовать подготовленные запросы. Сейчас Doris не поддерживает выполнение этих команд напрямую через клиент mysql, поэтому требуется JDBC.

  1. Включите подготовленные запросы на стороне сервера в JDBC URL.

    url = jdbc:mysql://127.0.0.1:9030/demo?useServerPrepStmts=true
  2. Используйте подготовленный запрос.

    // use `?` for placement holders, readStatement should be reused
    PreparedStatement readStatement = conn.prepareStatement("SELECT id, l2_distance_approximate(embedding, cast (? as ARRAY<FLOAT>)) AS distance
    FROM sift_1M
    ORDER BY distance
    LIMIT 10");

    ...

    readStatement.setString("[0,11,77,24,3,0,0,0,28,70,125,8,0,0,0,0,44,35,50,45,9,0,0,0,4,0,4,56,18,0,3,9,16,17,59,10,10,8,57,57,100,105,125,41,1,0,6,92,8,14,73,125,29,7,0,5,0,0,8,124,66,6,3,1,63,5,0,1,49,32,17,35,125,21,0,3,2,12,6,109,21,0,0,35,74,125,14,23,0,0,6,50,25,70,64,7,59,18,7,16,22,5,0,1,125,23,1,0,7,30,14,32,4,0,2,2,59,125,19,4,0,0,2,1,6,53,33,2]");

    ResultSet resultSet = readStatement.executeQuery();

Уменьшите количество сегментов​

Индекс ANN в Doris строится на уровне сегментов. Слишком большое количество сегментов создаёт дополнительные накладные расходы.

  • Рекомендация: для таблиц с индексом ANN количество сегментов в каждом tablet не должно превышать 5.
  • Как это сделать: настройте write_buffer_size и vertical_compaction_max_segment_size в be.conf, чтобы увеличить размер отдельного сегмента и уменьшить их количество. Рекомендуется установить для обоих параметров значение 10737418240 (10 GB).

Уменьшите количество rowset​

Каждая загрузка создаёт один rowset, и слишком большое количество rowset также увеличивает накладные расходы на планирование. Используйте Stream Load или INSERT INTO SELECT для пакетной загрузки.

Держите индексы ANN в памяти​

Текущий алгоритм индекса ANN работает в памяти. Если индекс запрашиваемого сегмента отсутствует в памяти, возникает дисковый ввод-вывод. Для повышения производительности держите его в памяти, задав в be.conf:

enable_segment_cache_prune=false

parallel_pipeline_task_num = 1​

Запросы ANN TopN возвращают очень мало строк и не требуют высокой степени параллелизма. Используйте:

SET parallel_pipeline_task_num = 1;

enable_profile = false​

Если задержка особенно критична, отключите профилирование запроса:

SET enable_profile = false;

Python SDK​

В эпоху ИИ Python стал основным языком для обработки данных и разработки интеллектуальных приложений. Чтобы разработчикам было проще использовать векторный поиск Doris в Python, сообщество создало Python SDK:

  • doris_vector_search: оптимизирован для поиска векторов по расстоянию. На данный момент это самый производительный Python SDK для векторного поиска Doris.

Ограничения использования​

При использовании векторного индекса Doris учитывайте следующие ограничения:

  1. Ограничение типа данных: столбец, на котором строится индекс ANN, должен иметь тип NOT NULLABLE Array<Float>. При загрузке данных длина каждого вектора в этом столбце должна совпадать с размерностью, указанной в свойстве индекса (dim), иначе возникнет ошибка.

  2. Ограничение модели таблицы: индекс ANN можно использовать только для таблиц модели Duplicate Key или таблиц Unique Key с включённым merge-on-write (enable_unique_key_merge_on_write = true). Поддержка таблиц Unique Key добавлена в версии 4.1.4. Таблицы Unique Key с merge-on-read и таблицы Aggregate Key по-прежнему не поддерживаются; попытка создать для них индекс вызывает ошибку: ANN index can only be used in DUP_KEYS table or UNIQUE_KEYS table with merge-on-write enabled.

  3. Столбцы предикатов должны иметь вторичный индекс: Doris использует семантику предварительной фильтрации: предикаты вычисляются до AnnTopN. Если столбцы, на которые ссылаются предикаты в SQL, не имеют вторичного индекса, Doris переходит к вычислению полным перебором, чтобы обеспечить корректность. Например:

    SELECT id, l2_distance_approximate(embedding, [xxx]) AS distance
    FROM sift_1M
    WHERE round(id) > 100
    ORDER BY distance limit 10;

    Хотя id является первичным ключом, на этом столбце не построен вторичный индекс, например инвертированный, позволяющий точно определять номера строк. Такие предикаты вычисляются после анализа индексов. Чтобы сохранить семантику предварительной фильтрации ANN TopN, система переходит к вычислению полным перебором.

  4. Функция расстояния должна соответствовать типу метрики: если функция расстояния в SQL не соответствует metric_type индекса, определённого в DDL, Doris не сможет использовать индекс ANN для вычисления TopN, даже при использовании l2_distance_approximate / inner_product_approximate.

  5. Для inner_product требуется сортировка DESC: когда metric_type имеет значение inner_product, индекс ANN может ускорять только запросы вида ORDER BY inner_product_approximate() DESC LIMIT N (DESC нельзя опускать).

  6. Порядок аргументов функции: функция xxx_approximate() запускает анализ индексов, только если первый аргумент имеет тип ColumnArray, а второй является CAST или ArrayLiteral. Перестановка аргументов приводит к переходу на поиск полным перебором.


Часто задаваемые вопросы​

Q1: Какие метрики расстояния поддерживает индекс ANN в Doris?​

Сейчас поддерживаются l2_distance (евклидово расстояние) и inner_product. О косинусном сходстве см. раздел Использование косинусного сходства.

Q2: Почему мой запрос ANN не использует индекс?​

Возможные причины:

  • Функция расстояния не соответствует metric_type.
  • При использовании inner_product не указана сортировка ORDER BY ... DESC.
  • Аргументы функции указаны в обратном порядке (ColumnArray должен быть первым аргументом).
  • На столбцах фильтрации нет вторичного индекса, например инвертированного, что приводит к переходу на полный перебор.

Q3: Как выбрать между HNSW, IVF и IVF On-Disk?​

ИндексПотребление памятиПроизводительность запросовСценарии применения
HNSWВысокое (должен полностью находиться в памяти)ВысокаяНебольшие и средние объёмы данных, строгие требования к низкой задержке
IVFСреднееСредняяБольшие объёмы данных
IVF On-DiskНизкое (диск + кэш)СредняяОчень большие объёмы данных, ограниченная память

Q4: Что делать, если памяти недостаточно?​

Уменьшите потребление памяти с помощью квантования:

  • Сначала попробуйте sq8 (скалярное квантование INT8). Обычно оно уменьшает индекс примерно до 1/3 исходного размера с небольшим влиянием на полноту поиска.
  • При очень жёстких ограничениях памяти используйте sq4 или pq, но полнота поиска несколько снизится.

Q5: Как совместить фильтрацию по ключевым словам с векторным поиском?​

Постройте инвертированный индекс на столбцах фильтрации, а затем используйте запрос ANN с условием WHERE. См. раздел Поиск ANN с фильтрами.

Q6: Как повысить QPS?​

См. раздел Настройка производительности. Основные рекомендации:

  • Используйте подготовленные запросы, чтобы избежать накладных расходов на синтаксический разбор SQL.
  • Уменьшите количество сегментов и rowset.
  • Держите индекс ANN в памяти.
  • parallel_pipeline_task_num = 1.
  • Отключите профилирование запроса.
На этой странице