manual/russian/Searching/KNN.md
Manticore Search поддерживает возможность добавления эмбеддингов, сгенерированных моделями машинного обучения, к каждому документу, а затем выполнение поиска ближайших соседей по ним. Это позволяет создавать такие функции, как поиск по сходству, рекомендации, семантический поиск и ранжирование по релевантности на основе алгоритмов NLP, среди прочего, включая поиск по изображениям, видео и звуку.
Для объединения векторного поиска KNN с полнотекстовым поиском для повышения релевантности см. Гибридный поиск.
Эмбеддинг — это метод представления данных — таких как текст, изображения или звук — в виде векторов в многомерном пространстве. Эти векторы созданы таким образом, чтобы расстояние между ними отражало сходство представляемых ими данных. Этот процесс обычно использует алгоритмы, такие как word embeddings (например, Word2Vec, BERT) для текста или нейронные сети для изображений. Многомерная природа векторного пространства, с множеством компонентов на вектор, позволяет представлять сложные и тонкие взаимосвязи между элементами. Их сходство измеряется расстоянием между этими векторами, часто с использованием методов, таких как евклидово расстояние или косинусное сходство.
Manticore Search позволяет выполнять поиск по векторам методом k-ближайших соседей (KNN) с использованием библиотеки HNSW. Эта функциональность является частью Manticore Columnar Library.
<!-- example KNN -->Для выполнения поиска KNN необходимо сначала настроить вашу таблицу. Векторы с плавающей точкой и поиск KNN поддерживаются только в таблицах реального времени (не в обычных таблицах). Таблица должна иметь хотя бы один атрибут типа float_vector, который служит вектором данных. Необходимо указать следующие свойства:
knn_type: Обязательная настройка; в настоящее время поддерживается только hnsw.
knn_dims: Обязательная настройка, определяющая размерность индексируемых векторов.
hnsw_similarity: Обязательная настройка, определяющая функцию расстояния, используемую индексом HNSW. Допустимые значения:
L2 - Квадрат L2IP - Скалярное произведениеCOSINE - Косинусное сходствоПримечание: При использовании сходства COSINE векторы автоматически нормализуются при вставке. Это означает, что сохраненные значения векторов могут отличаться от исходных входных значений, так как они будут преобразованы в единичные векторы (векторы с математической длиной/величиной 1.0) для обеспечения эффективных вычислений косинусного сходства. Эта нормализация сохраняет направление вектора, стандартизируя его длину.
hnsw_m: Необязательная настройка, определяющая максимальное количество исходящих соединений в графе. По умолчанию 16.
hnsw_ef_construction: Необязательная настройка, определяющая компромисс между временем построения и точностью. По умолчанию 200.
<!-- intro -->ПРИМЕЧАНИЕ: Построение графа HNSW во время сохранения RT-чанков,
OPTIMIZE TABLE/ автоматическое слияние чанков и перестроение KNN черезALTER TABLE ... ADD/DROP/REBUILDпо умолчанию выполняется параллельно на многоядерных хостах; количество рабочих процессов контролируется настройкой searchdknn_parallel_build(установите в1для принудительного последовательного выполнения). Это влияет только на производительность при построении. Поскольку параллельное построение HNSW может вставлять векторы в другом порядке, результирующий граф может не быть битово идентичным последовательному построению.
create table test ( title text, image_vector float_vector knn_type='hnsw' knn_dims='4' hnsw_similarity='l2' );
Query OK, 0 rows affected (0.01 sec)
POST /sql?mode=raw -d "create table test ( title text, image_vector float_vector knn_type='hnsw' knn_dims='4' hnsw_similarity='l2' )"
[
{
"total": 0,
"error": "",
"warning": ""
}
]
table test_vec {
type = rt
...
rt_attr_float_vector = image_vector
knn = {"attrs":[{"name":"image_vector","type":"hnsw","dims":4,"hnsw_similarity":"L2","hnsw_m":16,"hnsw_ef_construction":200}]}
}
Примечание: Для автоматических эмбеддингов в режиме plain см. пример ниже, который показывает, как использовать параметры model_name и from в конфигурации knn.
Самый простой способ работы с векторными данными — использование автоматических эмбеддингов. С этой функцией вы создаете таблицу с параметрами MODEL_NAME и FROM, а затем просто вставляете свои текстовые данные — Manticore автоматически генерирует эмбеддинги для вас.
При создании таблицы для автоматических эмбеддингов укажите:
MODEL_NAME: Модель эмбеддингов для использованияFROM: Какие поля использовать для генерации эмбеддингов (пустое значение означает все текстовые/строковые поля)API_KEY: Требуется для удаленных моделей (OpenAI, Voyage, Jina). API-ключ проверяется при создании таблицы путем выполнения реального API запроса.API_URL: Необязательно. Пользовательский URL конечной точки API. Если не указан, используется конечная точка провайдера по умолчанию (например, https://api.openai.com/v1/embeddings для OpenAI).API_TIMEOUT: Необязательно. HTTP-таймаут в секундах для API запросов. По умолчанию 10 секунд. Установите в '0' для использования таймаута по умолчанию. Применяется как к запросам валидации при создании таблицы, так и к генерации эмбеддингов во время операций INSERT.Поддерживаемые модели эмбеддингов:
| Тип модели | Пример | Требуется API ключ | Примечания |
|---|---|---|---|
| Sentence Transformers | sentence-transformers/all-MiniLM-L6-v2 | Нет | Локальные модели на основе BERT, автоматически загружаются |
| Qwen | Qwen/Qwen3-Embedding-0.6B | Нет | Локальные модели семейства Qwen |
| Llama | TinyLlama/TinyLlama-1.1B-Chat-v1.0 | Нет | Локальные модели семейства Llama |
| Mistral | Locutusque/TinyMistral-248M-v2 | Нет | Локальные модели семейства Mistral |
| Gemma | h2oai/embeddinggemma-300m | Нет | Локальные модели семейства Gemma |
| OpenAI | openai/text-embedding-ada-002 | Да | API_KEY='<OPENAI_API_KEY>' |
| Voyage | Модели Voyage AI | Да | API_KEY='<VOYAGE_API_KEY>' |
| Jina | Модели Jina AI | Да | API_KEY='<JINA_API_KEY>' |
Требования к формату локальных моделей:
safetensors (только однофайловый)TinyLlama/TinyLlama-1.1B-Chat-v1.0, Locutusque/TinyMistral-248M-v2, Qwen/Qwen3-Embedding-0.6B, h2oai/embeddinggemma-300msafetensors также могут работать, но не гарантируетсяДополнительную информацию о настройке атрибута float_vector можно найти здесь.
Использование sentence-transformers (ключ API не требуется)
CREATE TABLE products (
title TEXT,
description TEXT,
embedding_vector FLOAT_VECTOR KNN_TYPE='hnsw' HNSW_SIMILARITY='l2'
MODEL_NAME='sentence-transformers/all-MiniLM-L6-v2' FROM='title'
);
Использование локальных эмбеддингов Qwen (ключ API не требуется)
CREATE TABLE products_qwen (
title TEXT,
description TEXT,
embedding_vector FLOAT_VECTOR KNN_TYPE='hnsw' HNSW_SIMILARITY='l2'
MODEL_NAME='Qwen/Qwen3-Embedding-0.6B' FROM='title' CACHE_PATH='/opt/homebrew/var/manticore/.cache/manticore'
);
Использование OpenAI (требуется параметр API_KEY)
CREATE TABLE products_openai (
title TEXT,
description TEXT,
embedding_vector FLOAT_VECTOR KNN_TYPE='hnsw' HNSW_SIMILARITY='l2'
MODEL_NAME='openai/text-embedding-ada-002' FROM='title,description' API_KEY='...'
);
Использование OpenAI с пользовательским URL API и таймаутом (опционально)
CREATE TABLE products_openai_custom (
title TEXT,
description TEXT,
embedding_vector FLOAT_VECTOR KNN_TYPE='hnsw' HNSW_SIMILARITY='l2'
MODEL_NAME='openai/text-embedding-ada-002' FROM='title,description'
API_KEY='...' API_URL='https://custom-api.example.com/v1/embeddings' API_TIMEOUT='30'
);
Использование всех текстовых полей для эмбеддингов (FROM пуст)
CREATE TABLE products_all (
title TEXT,
description TEXT,
embedding_vector FLOAT_VECTOR KNN_TYPE='hnsw' HNSW_SIMILARITY='l2'
MODEL_NAME='sentence-transformers/all-MiniLM-L6-v2' FROM=''
);
table products {
type = rt
path = /path/to/products
rt_field = title
rt_field = description
rt_attr_float_vector = embedding_vector
knn = {"attrs":[{"name":"embedding_vector","type":"hnsw","hnsw_similarity":"L2","hnsw_m":16,"hnsw_ef_construction":200,"model_name":"sentence-transformers/all-MiniLM-L6-v2","from":"title"}]}
}
Использование OpenAI с ключом API в режиме plain:
table products_openai {
type = rt
path = /path/to/products_openai
rt_field = title
rt_field = description
rt_attr_float_vector = embedding_vector
knn = {"attrs":[{"name":"embedding_vector","type":"hnsw","hnsw_similarity":"L2","hnsw_m":16,"hnsw_ef_construction":200,"model_name":"openai/text-embedding-ada-002","from":"title,description","api_key":"your-api-key-here"}]}
}
Использование всех текстовых полей (пустой FROM):
table products_all {
type = rt
path = /path/to/products_all
rt_field = title
rt_field = description
rt_attr_float_vector = embedding_vector
knn = {"attrs":[{"name":"embedding_vector","type":"hnsw","hnsw_similarity":"L2","hnsw_m":16,"hnsw_ef_construction":200,"model_name":"sentence-transformers/all-MiniLM-L6-v2","from":""}]}
}
Важные замечания для режима plain:
model_name вы не должны указывать dims — модель автоматически определяет размерность вектора. Параметры dims и model_name являются взаимоисключающими.model_name (ручная вставка вектора), вы должны указать dims, чтобы обозначить размерность вектора.from указывает, какие поля использовать для генерации эмбеддингов (список, разделенный запятыми, или пустая строка для всех текстовых/строковых полей). Этот параметр обязателен при использовании model_name.api_key в конфигурацию knnПри использовании автоматических эмбеддингов вы можете:
FROM(), чтобы пропустить генерацию и сохранить вектор, состоящий из нулейЕсли позже вы запустите ALTER TABLE ... REBUILD EMBEDDINGS, строки, которые в данный момент содержат нулевые векторы из (), также будут перегенерированы.
Вставить только текстовые данные — эмбеддинги генерируются автоматически
INSERT INTO products (title) VALUES
('machine learning artificial intelligence'),
('banana fruit sweet yellow');
Вставить пользовательский вектор
INSERT INTO products (title, embedding_vector) VALUES
('machine learning artificial intelligence', (0.653448,0.192478,0.017971,0.339821));
Вставить несколько полей — оба используются для эмбеддинга, если FROM='title,description'
INSERT INTO products_openai (title, description) VALUES
('smartphone', 'latest mobile device with advanced features'),
('laptop', 'portable computer for work and gaming');
Вставить пустой вектор (без автоматической генерации; сохраняет нулевой вектор)
INSERT INTO products (title, embedding_vector) VALUES
('no embedding item', ());
Вставить только текстовые данные — эмбеддинги генерируются автоматически
POST /sql?mode=raw -d "INSERT INTO products (title) VALUES ('machine learning artificial intelligence'),('banana fruit sweet yellow')"
Вставить несколько полей — оба используются для эмбеддинга, если FROM='title,description'
POST /sql?mode=raw -d "INSERT INTO products_openai (title, description) VALUES ('smartphone', 'latest mobile device with advanced features'), ('laptop', 'portable computer for work and gaming')"
Вставить пустой вектор (документ исключен из векторного поиска)
POST /sql?mode=raw -d "INSERT INTO products (title, embedding_vector) VALUES ('no embedding item', ())"
Поиск работает таким же образом — предоставьте текст запроса, и Manticore сгенерирует эмбеддинги и найдет похожие документы:
<!-- intro -->SELECT id, knn_dist() FROM products WHERE knn(embedding_vector, 'machine learning');
+------+------------+
| id | knn_dist() |
+------+------------+
| 1 | 0.12345678 |
| 2 | 0.87654321 |
+------+------------+
2 rows in set (0.00 sec)
Использование текстового запроса с автоматическими эмбеддингами
POST /search
{
"table": "products",
"knn": {
"field": "embedding_vector",
"query": "machine learning"
}
}
Использование векторного запроса напрямую
POST /search
{
"table": "products",
"knn": {
"field": "embedding_vector",
"query": [0.1, 0.2, 0.3, 0.4]
}
}
{
"took": 0,
"timed_out": false,
"hits": {
"total": 2,
"total_relation": "eq",
"hits": [
{
"_id": 1,
"_score": 1,
"_knn_dist": 0.12345678,
"_source": {
"title": "machine learning artificial intelligence"
}
},
{
"_id": 2,
"_score": 1,
"_knn_dist": 0.87654321,
"_source": {
"title": "banana fruit sweet yellow"
}
}
]
}
}
В качестве альтернативы вы можете вручную вставлять предварительно вычисленные векторные данные, убедившись, что они соответствуют размерности, указанной вами при создании таблицы. Вы также можете вставить пустой вектор; это означает, что документ будет исключен из результатов векторного поиска.
Важно: При использовании hnsw_similarity='cosine' векторы автоматически нормализуются при вставке в единичные векторы (векторы с математической длиной/величиной 1.0). Эта нормализация сохраняет направление вектора, стандартизируя его длину, что необходимо для эффективных вычислений косинусного сходства. Это означает, что сохраненные значения будут отличаться от ваших исходных входных значений.
insert into test values ( 1, 'yellow bag', (0.653448,0.192478,0.017971,0.339821) ), ( 2, 'white bag', (-0.148894,0.748278,0.091892,-0.095406) );
Query OK, 2 rows affected (0.00 sec)
POST /insert
{
"table":"test_vec",
"id":1,
"doc": { "title" : "yellow bag", "image_vector" : [0.653448,0.192478,0.017971,0.339821] }
}
POST /insert
{
"table":"test_vec",
"id":2,
"doc": { "title" : "white bag", "image_vector" : [-0.148894,0.748278,0.091892,-0.095406] }
}
{
"table":"test",
"_id":1,
"created":true,
"result":"created",
"status":201
}
{
"table":"test",
"_id":2,
"created":true,
"result":"created",
"status":201
}
Теперь вы можете выполнить KNN-поиск, используя предложение knn в формате SQL или JSON. Оба интерфейса поддерживают одинаковые основные параметры, обеспечивая согласованный опыт независимо от выбранного формата:
select ... from <table name> where knn ( <field>, <query vector> [,<options>] )POST /search
{
"table": "<table name>",
"knn":
{
"field": "<field>",
"query": "<text or vector>",
"ef": <ef>,
"rescore": <rescore>,
"oversampling": <oversampling>
}
}
Параметры:
field: Это имя атрибута вектора с плавающей точкой, содержащего векторные данные.k: Устаревшая опция. Используйте параметр запроса limit вместо этого. Ранее использовалась для указания количества документов, которые должен вернуть один индекс HNSW. Однако фактическое количество документов, включенных в окончательные результаты, может отличаться. Например, если система работает с таблицами реального времени, разделенными на дисковые чанки, каждый чанк может вернуть k документов, что приведет к общему количеству, превышающему указанное k (так как совокупное количество будет num_chunks * k). С другой стороны, окончательное количество документов может быть меньше k, если после запроса k документов некоторые из них будут отфильтрованы на основе определенных атрибутов. Важно отметить, что параметр k не применяется к оперативным чанкам (ramchunks). В контексте оперативных чанков процесс извлечения работает иначе, и поэтому влияние параметра k на количество возвращаемых документов неприменимо.query: (Рекомендуемый параметр) Поисковый запрос, который может быть:
query_vector.query_vector: (Устаревший параметр) Поисковый вектор в виде массива чисел. Все еще поддерживается для обратной совместимости.
Примечание: Используйте либо query, либо query_vector, но не оба в одном запросе.ef: необязательный размер динамического списка, используемого во время поиска. Более высокое значение ef приводит к более точному, но более медленному поиску. По умолчанию равно 10.rescore: Включает повторное ранжирование KNN (включено по умолчанию). Установите в 0 в SQL или false в JSON, чтобы отключить повторное ранжирование. После завершения поиска KNN с использованием квантованных векторов (с возможным передискретизацией) расстояния пересчитываются с исходными (полноразрядными) векторами, и результаты пересортировываются для повышения точности ранжирования.oversampling: Устанавливает коэффициент (значение с плавающей точкой), на который умножается k при выполнении поиска KNN, что приводит к извлечению большего количества кандидатов, чем требуется, с использованием квантованных векторов. По умолчанию применяется oversampling=3.0. Эти кандидаты могут быть позже переоценены, если повторное ранжирование включено. Передискретизация также работает с неквантованными векторами. Поскольку она увеличивает k, что влияет на работу индекса HNSW, это может вызвать небольшое изменение точности результатов.early_termination: Включает или отключает адаптивное досрочное завершение во время обхода графа HNSW. Включено по умолчанию. Установите в 0 в SQL или false в JSON, чтобы отключить. Подробности см. в разделе Досрочное завершение.Документы всегда сортируются по расстоянию до поискового вектора. Любые дополнительные критерии сортировки, которые вы укажете, будут применены после этого основного условия сортировки. Для получения расстояния существует встроенная функция knn_dist().
<!-- intro -->select id, knn_dist() from test where knn ( image_vector, (0.286569,-0.031816,0.066684,0.032926), { ef=2000, oversampling=3.0, rescore=1 } );
+------+------------+
| id | knn_dist() |
+------+------------+
| 1 | 0.28146550 |
| 2 | 0.81527930 |
+------+------------+
2 rows in set (0.00 sec)
POST /search
{
"table": "test",
"knn":
{
"field": "image_vector",
"query": [0.286569,-0.031816,0.066684,0.032926],
"ef": 2000,
"rescore": true,
"oversampling": 3.0
}
}
{
"took":0,
"timed_out":false,
"hits":
{
"total":2,
"total_relation":"eq",
"hits":
[
{
"_id": 1,
"_score":1,
"_knn_dist":0.28146550,
"_source":
{
"title":"yellow bag",
"image_vector":[0.653448,0.192478,0.017971,0.339821]
}
},
{
"_id": 2,
"_score":1,
"_knn_dist":0.81527930,
"_source":
{
"title":"white bag",
"image_vector":[-0.148894,0.748278,0.091892,-0.095406]
}
}
]
}
}
Индексы HNSW необходимо полностью загружать в память для выполнения поиска KNN, что может привести к значительному потреблению памяти. Для уменьшения использования памяти может применяться скалярное квантование — техника, которая сжимает многомерные векторы, представляя каждый компонент (измерение) ограниченным количеством дискретных значений. Manticore поддерживает 8-битное и 1-битное квантование, что означает, что каждый компонент вектора сжимается с 32-битного числа с плавающей точкой до 8 бит или даже 1 бита, уменьшая использование памяти в 4 или 32 раза соответственно. Эти сжатые представления также позволяют выполнять более быстрые вычисления расстояний, так как больше компонентов вектора может быть обработано за одну SIMD инструкцию. Хотя скалярное квантование вносит некоторую ошибку аппроксимации, это часто является оправданным компромиссом между точностью поиска и эффективностью использования ресурсов. Для еще большей точности квантование можно комбинировать с повторным ранжированием и передискретизацией: извлекается больше кандидатов, чем запрошено, и расстояния для этих кандидатов пересчитываются с использованием исходных 32-битных векторов с плавающей точкой.
Поддерживаемые типы квантования включают:
8bit: Каждый компонент вектора квантуется до 8 бит.1bit: Каждый компонент вектора квантуется до 1 бита. Используется асимметричное квантование, при котором векторы запросов квантуются до 4 бит, а хранимые векторы — до 1 бита. Этот подход обеспечивает большую точность, чем более простые методы, хотя и с некоторым компромиссом по производительности.1bitsimple: Каждый компонент вектора квантуется до 1 бита. Этот метод быстрее, чем 1bit, но обычно менее точен.create table test ( title text, image_vector float_vector knn_type='hnsw' knn_dims='4' hnsw_similarity='l2' quantization='1bit');
Query OK, 0 rows affected (0.01 sec)
POST /sql?mode=raw -d "create table test ( title text, image_vector float_vector knn_type='hnsw' knn_dims='4' hnsw_similarity='l2' quantization='1bit')"
[
{
"total": 0,
"error": "",
"warning": ""
}
]
ПРИМЕЧАНИЕ: Поиск похожих документов по id требует наличия Manticore Buddy. Если это не работает, убедитесь, что Buddy установлен.
Поиск документов, похожих на конкретный, на основе его уникального идентификатора, является распространенной задачей. Например, когда пользователь просматривает определенный элемент, Manticore Search может эффективно идентифицировать и отобразить список элементов, наиболее похожих на него в векторном пространстве. Вот как это можно сделать:
select ... from <table name> where knn ( <field>, <k>, <document id> )POST /search
{
"table": "<table name>",
"knn":
{
"field": "<field>",
"doc_id": <document id>,
"k": <k>
}
}
Параметры:
field: Это имя атрибута вектора с плавающей точкой, содержащего векторные данные.k: Это количество документов для возврата и ключевой параметр для индексов Hierarchical Navigable Small World (HNSW). Он определяет количество документов, которое должен вернуть один индекс HNSW. Однако фактическое количество документов, включенных в окончательные результаты, может варьироваться. Например, если система работает с таблицами реального времени, разделенными на дисковые чанки, каждый чанк может вернуть k документов, что приводит к общему количеству, превышающему указанное k (так как совокупное количество будет num_chunks * k). С другой стороны, окончательное количество документов может быть меньше k, если после запроса k документов некоторые из них отфильтровываются на основе определенных атрибутов. Важно отметить, что параметр k не применяется к ramchunks. В контексте ramchunks процесс извлечения работает по-другому, и поэтому влияние параметра k на количество возвращаемых документов не применимо.document id: Идентификатор документа для поиска сходства KNN.select id, knn_dist() from test where knn ( image_vector, 5, 1 );
+------+------------+
| id | knn_dist() |
+------+------------+
| 2 | 0.81527930 |
+------+------------+
1 row in set (0.00 sec)
POST /search
{
"table": "test",
"knn":
{
"field": "image_vector",
"doc_id": 1,
"k": 5
}
}
{
"took":0,
"timed_out":false,
"hits":
{
"total":1,
"total_relation":"eq",
"hits":
[
{
"_id": 2,
"_score":1643,
"_knn_dist":0.81527930,
"_source":
{
"title":"white bag",
"image_vector":[-0.148894,0.748278,0.091892,-0.095406]
}
}
]
}
}
Manticore также поддерживает дополнительную фильтрацию документов, возвращаемых поиском KNN, либо по полнотекстовому соответствию, либо по фильтрам атрибутов, либо по обоим.
<!-- intro -->select id, knn_dist() from test where knn ( image_vector, 5, (0.286569,-0.031816,0.066684,0.032926) ) and match('white') and id < 10;
+------+------------+
| id | knn_dist() |
+------+------------+
| 2 | 0.81527930 |
+------+------------+
1 row in set (0.00 sec)
POST /search
{
"table": "test",
"knn":
{
"field": "image_vector",
"query": [0.286569,-0.031816,0.066684,0.032926],
"k": 5
},
"query":
{
"bool":
{
"must":
[
{ "match": {"_all":"white"} },
{ "range": { "id": { "lt": 10 } } }
]
}
}
}
{
"took":0,
"timed_out":false,
"hits":
{
"total":1,
"total_relation":"eq",
"hits":
[
{
"_id": 2,
"_score":1643,
"_knn_dist":0.81527930,
"_source":
{
"title":"white bag",
"image_vector":[-0.148894,0.748278,0.091892,-0.095406]
}
}
]
}
}
При объединении векторного поиска KNN с фильтрами атрибутов Manticore поддерживает две стратегии, которые отличаются тем, когда фильтр применяется относительно обхода графа HNSW.
Предварительная фильтрация (по умолчанию; prefilter=1 (SQL) или "prefilter": true (JSON, по умолчанию)) передает фильтр в сам обход HNSW. Каждый кандидат проверяется фильтром перед добавлением в кучу результатов - только соответствующие документы вносят вклад в окончательные k результатов. Это уменьшает бесполезные вычисления расстояний и гарантирует возврат ровно k соответствующих документов (при условии, что существует k соответствующих документов).
Последующая фильтрация (prefilter=0 (SQL) или "prefilter": false (JSON)) сначала выполняет поиск KNN по всему набору данных, а затем применяет фильтр к результатам. Это безопасно и предсказуемо: граф HNSW обходится без помех, и фильтр влияет только на то, какие результаты возвращаются клиенту. Недостаток в том, что граф может тратить усилия на кандидатов, которые в конечном итоге будут отброшены. При строгом фильтре, который соответствует только небольшой части документов, возвращаемых k результатов может быть значительно меньше запрошенного, потому что большинство кандидатов KNN не проходят фильтр.
Внутренне Manticore использует алгоритм на основе ACORN-1 для предварительной фильтрации. Наивная предварительная фильтрация просто пропускала бы несоответствующие узлы, что рискует потерей "мостовых" узлов, соединяющих иначе разделенные части графа HNSW, вызывая коллапс полноты при увеличении избирательности фильтра. ACORN-1 избегает этого: когда узел не проходит фильтр, его соседи все равно добавляются в очередь исследования. Это позволяет обходу обходить отфильтрованные узлы и поддерживать связность графа. Исследование ACORN-1 активируется автоматически, когда менее 60% от общего количества документов проходят фильтр.
Автоматический переход на полный перебор: Когда предварительная фильтрация включена, Manticore оценивает, будет ли дешевле выполнить сканирование расстояний полным перебором по отфильтрованному подмножеству, чем обходить граф HNSW. Оценка сравнивает ожидаемое количество узлов, посещаемых HNSW, с количеством документов, проходящих фильтр. Если отфильтрованный набор достаточно мал, чтобы его прямое сканирование было быстрее, Manticore автоматически переключается на полный перебор, полностью пропуская HNSW. Это обеспечивает корректность и хорошую производительность даже при экстремальной избирательности.
<!-- intro -->-- prefilter (default): filter applied during HNSW traversal (ACORN-1 used automatically)
SELECT id, knn_dist() FROM test
WHERE knn ( image_vector, (0.286569,-0.031816,0.066684,0.032926) )
AND price < 100;
-- postfilter: KNN runs over full dataset, filter applied to results
SELECT id, knn_dist() FROM test
WHERE knn ( image_vector, (0.286569,-0.031816,0.066684,0.032926), { prefilter=0 } )
AND price < 100;
// prefilter (default): filter applied during HNSW traversal
POST /search
{
"table": "test",
"knn": {
"field": "image_vector",
"query": [0.286569,-0.031816,0.066684,0.032926]
},
"query": {
"range": { "price": { "lt": 100 } }
}
}
// postfilter: filter applied after KNN search
POST /search
{
"table": "test",
"knn": {
"field": "image_vector",
"query": [0.286569,-0.031816,0.066684,0.032926],
"prefilter": false
},
"query": {
"range": { "price": { "lt": 100 } }
}
}
По умолчанию Manticore использует адаптивный алгоритм досрочного завершения во время обхода графа HNSW. Вместо того чтобы всегда исследовать полный набор кандидатов, определенный ef, он отслеживает скорость, с которой новые кандидаты улучшают набор результатов, и останавливается досрочно, когда эта скорость последовательно падает ниже порога. Это уменьшает количество вычислений расстояний без значительного влияния на качество результатов.
Досрочное завершение включено по умолчанию и автоматически отключается, когда k равно 10 или меньше, поскольку накладные расходы алгоритма не оправданы для таких маленьких наборов результатов. Преимущество в производительности масштабируется с k — чем больше набор результатов, тем больше вычислений расстояний можно сэкономить, остановившись раньше.
Обратите внимание, что передискретизация умножает эффективное k, используемое во время обхода HNSW, поэтому досрочное завершение также выигрывает от передискретизации: более высокое эффективное k означает больше кандидатов, которых можно потенциально пропустить.
Для явного управления досрочным завершением используйте опцию early_termination:
-- disable early termination
SELECT id, knn_dist() FROM test WHERE knn ( image_vector, (0.286569,-0.031816,0.066684,0.032926), { ef=200, early_termination=0 } );
-- enable early termination explicitly (default)
SELECT id, knn_dist() FROM test WHERE knn ( image_vector, (0.286569,-0.031816,0.066684,0.032926), { ef=200, early_termination=1 } );
POST /search
{
"table": "test",
"knn":
{
"field": "image_vector",
"query": [0.286569,-0.031816,0.066684,0.032926],
"ef": 200,
"early_termination": false
}
}
Когда отключать досрочное завершение:
k (около 30 или меньше), где досрочное завершение дает мало преимуществ в производительности, но может снизить точность.