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.
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}]}
}
Примечание: Для автоэмбеддингов в обычном режиме см. пример ниже, который показывает, как использовать параметры 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-ключом в обычном режиме:
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":""}]}
}
Важные примечания для обычного режима:
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, 3, '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",
"k": 3
}
}
Использование векторного запроса напрямую
POST /search
{
"table": "products",
"knn": {
"field": "embedding_vector",
"query": [0.1, 0.2, 0.3, 0.4],
"k": 3
}
}
{
"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. В контексте 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 установлен.
Поиск документов, похожих на конкретный, на основе его уникального ID, является распространённой задачей. Например, когда пользователь просматривает определённый элемент, 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: 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 или меньше), где досрочное завершение даёт мало преимуществ в производительности, но может снизить точность.