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 поддерживаются только в таблицах real-time (не в plain-таблицах). В таблице должен быть как минимум один атрибут 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/ auto-optimize и при перестройке KNN черезALTER TABLE ... ADD/DROP/REBUILDвыполняется параллельно по умолчанию на многопроцессорных хостах; число worker-потоков управляется настройкой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.Для удаленных моделей MODEL_NAME можно записывать в двух формах:
openai/text-embedding-ada-002, voyage/voyage-3.5-lite, jina/jina-embeddings-v4openai:text-embedding-ada-002, openai:openai/text-embedding-ada-002, voyage:custom-model, jina:custom-modelКогда вы используете форму provider:model вместе с API_URL, часть перед : только выбирает формат запроса. Часть после : отправляется на удаленную конечную точку без изменений. Это полезно для шлюзов, совместимых с OpenAI, таких как OpenRouter или LiteLLM.
Поддерживаемые модели эмбеддингов:
| Тип модели | Пример | Требуется 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 or openai:text-embedding-ada-002 | Да | API_KEY='***' |
| Voyage | voyage/voyage-3.5-lite or voyage:voyage-3.5-lite | Да | API_KEY='***' |
| Jina | jina/jina-embeddings-v4 or jina:jina-embeddings-v4 | Да | 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 с пользовательским API URL и таймаутом (необязательно)
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'
);
Использование шлюза, совместимого с OpenAI, который ожидает модельный идентификатор с указанием провайдера
CREATE TABLE products_openrouter (
title TEXT,
description TEXT,
embedding_vector FLOAT_VECTOR KNN_TYPE='hnsw' HNSW_SIMILARITY='l2'
MODEL_NAME='openai:openai/text-embedding-ada-002' FROM='title,description'
API_KEY='***' API_URL='https://openrouter.ai/api/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: Имя атрибута float_vector, содержащего векторные данные.k: Устаревший параметр. Вместо него используйте limit в запросе. Он использовался для задания количества документов, которое должен вернуть один индекс HNSW. Однако фактическое число документов в итоговых результатах может отличаться. Например, если система работает с таблицами real-time, разделенными на disk chunks, каждый chunk может вернуть 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) расстояния пересчитываются по исходным (full-precision) векторам, и результаты пересортировываются для повышения точности ранжирования.oversampling: Задает коэффициент (значение float), на который умножается k при выполнении поиска KNN, из-за чего с использованием квантизованных векторов извлекается больше кандидатов, чем требуется. По умолчанию применяется oversampling=3.0. Эти кандидаты можно затем переоценить, если повторное оценивание включено. Oversampling также работает и с неквантизованными векторами. Поскольку он увеличивает 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-битного float до 8 бит или даже до 1 бита, уменьшая использование памяти в 4 раза или 32 раза соответственно. Эти сжатые представления также позволяют быстрее вычислять расстояния, поскольку больше компонент вектора можно обработать одной SIMD-инструкцией. Хотя скалярное квантование вносит некоторую погрешность аппроксимации, часто это оправданный компромисс между точностью поиска и эффективностью использования ресурсов. Для еще более высокой точности квантование можно сочетать с повторным оцениванием и oversampling: запрашивается больше кандидатов, чем нужно, а расстояния для этих кандидатов пересчитываются с использованием исходных 32-битных float-векторов.
Поддерживаемые типы квантования:
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: Имя атрибута float_vector, содержащего векторные данные.k: Это число документов, которые нужно вернуть, и ключевой параметр для индексов Hierarchical Navigable Small World (HNSW). Он задает количество документов, которое должен вернуть один индекс HNSW. Однако фактическое число документов в итоговых результатах может отличаться. Например, если система работает с таблицами real-time, разделенными на disk chunks, каждый chunk может вернуть 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, default)) передает фильтр непосредственно в обход HNSW. Каждый кандидат проверяется на соответствие фильтру до добавления в результирующую кучу - в итоговые k результатов попадают только подходящие документы. Это уменьшает число бесполезных вычислений расстояния и гарантирует, что будет возвращено ровно k подходящих документов (если существует k подходящих документов).
Постфильтрация (prefilter=0 (SQL) или "prefilter": false (JSON)) сначала выполняет поиск KNN по всему набору данных, а затем применяет фильтр к результатам. Это безопасно и предсказуемо: граф HNSW обходится без вмешательства, а фильтр влияет только на то, какие результаты возвращаются клиенту. Недостаток в том, что на кандидатов, которые в итоге будут отброшены, граф может потратить ресурсы. При жестком фильтре, который совпадает лишь с небольшой долей документов, возвращаемые k результатов могут оказаться значительно меньше запрошенного числа, потому что большинство кандидатов KNN не пройдет фильтр.
Внутри Manticore использует алгоритм на основе ACORN-1 для предварительной фильтрации. Наивная предварительная фильтрация просто пропускала бы несовпадающие узлы, что создает риск потерять "bridge"-узлы, соединяющие разъединенные части графа HNSW, из-за чего полнота резко падает по мере ужесточения фильтра. ACORN-1 избегает этого: когда узел не проходит фильтр, его соседи все равно добавляются в очередь обхода. Это позволяет обходу обходить отфильтрованные узлы и сохранять связность графа. Обход ACORN-1 автоматически включается, когда фильтр проходит менее 60% всех документов.
Автоматический переход на brute-force: Когда включена предварительная фильтрация, Manticore оценивает, что дешевле - выполнить полный перебор расстояний по отфильтрованному подмножеству или обходить граф HNSW. Оценка сравнивает ожидаемое число узлов, посещаемых HNSW, с числом документов, прошедших фильтр. Если отфильтрованное множество достаточно мало, чтобы его прямой перебор был быстрее, Manticore автоматически переключается на brute-force, полностью пропуская 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 - чем больше набор результатов, тем больше вычислений расстояния можно сэкономить за счет раннего завершения.
Учтите, что oversampling умножает эффективное k, используемое во время обхода HNSW, поэтому раннее завершение тоже выигрывает от oversampling: более высокое эффективное 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 или меньше), при которых раннее завершение дает мало выигрыша в производительности, но может снизить точность.