Кэш запросов хранит сжатые наборы результатов в памяти и повторно использует их для последующих запросов, когда это возможно. Вы можете настроить его с помощью следующих директив:
- qcache_max_bytes — ограничение на использование RAM для хранения кэшированных запросов. По умолчанию установлено в 16 МБ. Установка
qcache_max_bytesв 0 полностью отключает кэш запросов. - qcache_thresh_msec — минимальное время выполнения запроса в миллисекундах для кеширования. Запросы, которые выполняются быстрее этого времени, не будут кешироваться. По умолчанию 3000 мс, или 3 секунды.
- qcache_ttl_sec — время жизни кэшированной записи, или TTL. Запросы будут оставаться в кэше в течение этого времени. По умолчанию 60 секунд, или 1 минута.
Эти настройки можно изменить на лету, используя оператор SET GLOBAL:
mysql> SET GLOBAL qcache_max_bytes=128000000;
Эти изменения применяются немедленно, и кэшированные наборы результатов, которые больше не соответствуют ограничениям, сразу же отбрасываются. При уменьшении размера кэша на лету выигрыш получают наиболее недавно использованные (MRU) наборы результатов.
Кэш запросов работает следующим образом. При включении каждый результат полнотекстового поиска полностью сохраняется в памяти. Это происходит после полнотекстового совпадения, фильтрации и ранжирования, так что по сути мы сохраняем пары {docid,weight} для total_found. Сжатые совпадения могут занимать в среднем от 2 до 12 байт на совпадение, в основном в зависимости от дельт между последовательными docid. По завершении запроса мы проверяем пороги времени и размера, и либо сохраняем сжатый набор результатов для повторного использования, либо отбрасываем его.
Обратите внимание, что влияние кэша запросов на RAM не ограничивается qcache_max_bytes! Например, если у вас выполняется 10 одновременных запросов, каждый из которых находит до 1 млн совпадений (после фильтров), то пиковое временное использование RAM окажется в диапазоне от 40 МБ до 240 МБ, даже если запросы достаточно быстрые и не кэшируются.
Запросы могут использовать кэш, когда совпадают таблица, полнотекстовый запрос (то есть содержимое MATCH()), ранжировщик и совместимы фильтры. Это значит:
- Полнотекстовая часть внутри
MATCH()должна совпадать посимвольно. Добавьте один пробел — и это уже другой запрос, с точки зрения кэша запросов. - Ранжировщик (и его параметры, если есть, для пользовательских ранжировщиков) должен совпадать посимвольно.
- Фильтры должны быть надмножеством оригинальных фильтров. Вы можете добавить дополнительные фильтры и все равно попасть в кэш. (В этом случае дополнительные фильтры будут применены к кэшированному результату.) Но если вы уберёте какой-то фильтр, это уже будет новый запрос.
Записи кэша истекают по TTL и также инвалидируются при ротации таблиц, или при выполнении TRUNCATE, или ATTACH. Обратите внимание, что в настоящее время записи не инвалидируются при произвольных записях в RT-таблицу! Поэтому кэшированный запрос может возвращать старые результаты в течение времени жизни TTL.
Вы можете проверить текущий статус кэша с помощью SHOW STATUS через переменные qcache_XXX:
mysql> SHOW STATUS LIKE 'qcache%';
+-----------------------+----------+
| Counter | Value |
+-----------------------+----------+
| qcache_max_bytes | 16777216 |
| qcache_thresh_msec | 3000 |
| qcache_ttl_sec | 60 |
| qcache_cached_queries | 0 |
| qcache_used_bytes | 0 |
| qcache_hits | 0 |
+-----------------------+----------+
6 rows in set (0.00 sec)
Сортировки в первую очередь влияют на сравнения строковых атрибутов. Они определяют как кодировку набора символов, так и стратегию, которую Manticore использует для сравнения строк при выполнении ORDER BY или GROUP BY с участием строкового атрибута.
Строковые атрибуты хранятся в неизменном виде во время индексирования, и к ним не прикрепляется информация о наборе символов или языке. Это приемлемо, пока Manticore нужно лишь хранить и возвращать строки вызывающему приложению дословно. Однако, когда вы просите Manticore отсортировать по строковому значению, запрос сразу же становится неоднозначным.
Во-первых, строки с одним байтом (ASCII, ISO-8859-1 или Windows-1251) требуют иной обработки, чем строки UTF-8, которые могут кодировать каждый символ переменным числом байт. Поэтому нам нужно знать тип набора символов, чтобы правильно интерпретировать сырые байты как осмысленные символы.
Во-вторых, нам также необходимо знать правила сортировки, специфичные для языка. Например, при сортировке по правилам США в локали en_US, акцентированный символ ï (малая буква i с диарезой) должен размещаться где-то после z. Однако при сортировке с учётом французских правил и локали fr_FR, его следует поместить между i и j. Другой набор правил может вовсе игнорировать акценты, позволяя ï и i смешиваться произвольно.
В-третьих, в некоторых случаях требуется чувствительная к регистру сортировка, а в других — регистронезависимая.
Сортировки инкапсулируют всё перечисленное: набор символов, языковые правила и чувствительность к регистру. В настоящее время Manticore предоставляет четыре сортировки:
libc_cilibc_csutf8_general_cibinary
Первые две сортировки опираются на несколько стандартных вызовов библиотеки C (libc) и, таким образом, могут поддерживать любую локаль, установленную в вашей системе. Они обеспечивают регистронезависимые (_ci) и регистрозависимые (_cs) сравнения соответственно. По умолчанию используется локаль C, что фактически сводит сортировку к побайтовому сравнению. Чтобы изменить это, необходимо указать другую доступную локаль с помощью директивы collation_libc_locale. Список локалей, доступных в вашей системе, обычно можно получить с помощью команды locale:
$ locale -a
C
en_AG
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_NG
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZW.utf8
es_ES
fr_FR
POSIX
ru_RU.utf8
ru_UA.utf8
Конкретный список системных локалей может варьироваться. Обратитесь к документации вашей ОС для установки дополнительных нужных локалей.
Локали utf8_general_ci и binary встроены в Manticore. Первая — это универсальная сортировка для UTF-8 данных (без так называемой языковой адаптации); она должна вести себя аналогично сортировке utf8_general_ci в MySQL. Вторая — простое побайтовое сравнение.
Сортировка может быть переопределена через SQL на уровне сессии с помощью оператора SET collation_connection. Все последующие SQL-запросы будут использовать эту сортировку. В противном случае все запросы будут использовать сортировку, установленную по умолчанию на сервере, или указанную в конфигурационной директиве collation_server. В настоящее время по умолчанию в Manticore используется сортировка libc_ci.
Сортировки влияют на все сравнения строковых атрибутов, включая сортировки в ORDER BY и GROUP BY, поэтому можно получить результаты, отсортированные или сгруппированные по-разному в зависимости от выбранной сортировки. Обратите внимание, что сортировки не влияют на полнотекстовый поиск; для этого используйте charset_table.
Когда Manticore выполняет полносканирующий запрос, он может либо использовать простой скан для проверки каждого документа с учётом фильтров, либо применять дополнительные данные и/или алгоритмы для ускорения выполнения запроса. Manticore использует оптимизатор на основе стоимости (CBO), также известный как «оптимизатор запросов», для определения подходящего способа.
CBO также может улучшать производительность полнотекстовых запросов. Подробнее см. ниже.
CBO может решить заменить один или несколько фильтров запроса одним из следующих элементов, если он определит, что это улучшит производительность:
- Индекс docid использует специальный вторичный индекс только по docid, хранящийся в файлах с расширением
.spt. Помимо улучшения фильтрации по числовым ID документов, индекс docid также используется для ускорения сопоставления ID документа с ID строки и для более быстрой обработки больших killlist при запуске демона. - колоночное сканирование опирается на колоночное хранение и может использоваться только на колоночном атрибуте. Оно сканирует каждое значение и проверяет его по фильтру, но при этом сильно оптимизировано и обычно быстрее подхода по умолчанию.
- вторичные индексы создаются по умолчанию для всех атрибутов (кроме JSON). Они используют PGM индекс вместе с встроенным инвертированным индексом Manticore для получения списка идентификаторов строк, соответствующих значению или диапазону значений. Вторичные индексы хранятся в файлах с расширениями
.spidxи.spjidx. Для информации о том, как создавать вторичные индексы по JSON атрибутам, см. json_secondary_indexes.
Оптимизатор оценивает стоимость каждого пути выполнения, используя различные статистики атрибутов, включая:
- Информацию о распределении данных внутри атрибута (гистограммы, хранящиеся в файлах
.sphi). Гистограммы создаются автоматически при индексации данных и служат основным источником информации для CBO. - Информацию от PGM (вторичных индексов), которая помогает оценить количество списков документов для чтения. Это помогает оценить производительность объединения doclist и выбрать подходящий алгоритм слияния (слияние с приоритетной очередью или слияние битмапов).
- Статистику кодирования колонок, используемую для оценки производительности декомпрессии колоночных данных.
- Колоночное дерево min-max. В то время как CBO использует гистограммы для оценки количества документов, остающихся после применения фильтра, он также должен определить, сколько документов фильтр пришлось обработать. Для колоночных атрибутов частичная оценка min-max дерева служит этой цели.
- Полнотекстовый словарь. CBO использует статистику терминов для оценки стоимости вычисления полнотекстового дерева.
Оптимизатор вычисляет стоимость выполнения для каждого фильтра, используемого в запросе. Поскольку некоторые фильтры можно заменить несколькими разными сущностями (например, для числового ID документа Manticore может использовать обычный проход, обращение к индексу docid, колоночный проход (если ID документа хранится в колонках) и вторичный индекс), оптимизатор оценивает все доступные комбинации. Однако максимальный предел составляет 1024 комбинации.
Для оценки стоимости выполнения запроса оптимизатор рассчитывает предполагаемые стоимости наиболее значимых операций, выполняемых при выполнении запроса. Он использует предустановленные константы для представления стоимости каждой операции.
Оптимизатор сравнивает стоимости каждого пути выполнения и выбирает путь с наименьшей стоимостью для выполнения запроса.
При работе с полнотекстовыми запросами, которые содержат фильтры по атрибутам, оптимизатор запросов выбирает один из двух возможных путей выполнения. Либо выполнить полнотекстовый запрос, получить совпадения и применить фильтры. Либо заменить фильтры одним или несколькими элементами, описанными выше, получить из них rowid и внедрить их в полнотекстовое дерево. Таким образом результаты полнотекстового поиска пересекутся с результатами полносканирования. Оптимизатор оценивает стоимость вычисления полнотекстового дерева и наилучший возможный путь вычисления результатов фильтра. Используя эту информацию, оптимизатор выбирает путь выполнения.
Ещё один фактор — многопоточное выполнение запросов (когда включён pseudo_sharding). CBO знает, что некоторые запросы могут выполняться в нескольких потоках, и учитывает это. CBO отдаёт предпочтение более короткому времени выполнения запроса (то есть задержке) по сравнению с пропускной способностью. Например, если запрос с использованием колоночного сканирования может быть выполнен в нескольких потоках (и занять несколько ядер CPU) и при этом быстрее, чем запрос, выполненный в одном потоке с использованием вторичных индексов, будет предпочтительным многопоточное выполнение.
Запросы с использованием вторичных индексов и docid индексов всегда выполняются в одном потоке, поскольку бенчмарки показывают, что многопоточность для них малоэффективна.
На данный момент оптимизатор учитывает только затраты CPU и не принимает во внимание использование памяти или диска.
Manticore Search поддерживает добавление эмбеддингов, сгенерированных моделями машинного обучения, к каждому документу, а затем поиск ближайших соседей по ним. Это позволяет строить такие функции, как поиск по сходству, рекомендации, семантический поиск и ранжирование релевантности на основе алгоритмов NLP, а также поиск по изображениям, видео и звуку.
Чтобы объединить векторный поиск KNN с полнотекстовым поиском для лучшей релевантности, см. Гибридный поиск.
Эмбеддинг - это способ представления данных, таких как текст, изображения или звук, в виде векторов в многомерном пространстве. Эти векторы строятся так, чтобы расстояние между ними отражало сходство представляемых ими данных. Обычно для этого используют такие алгоритмы, как word embeddings (например, Word2Vec, BERT) для текста или нейросети для изображений. Многомерная природа векторного пространства, где у каждого вектора много компонент, позволяет описывать сложные и тонкие связи между объектами. Их сходство оценивают по расстоянию между этими векторами, которое часто измеряют с помощью евклидова расстояния или косинусного сходства.
Manticore Search поддерживает поиск k ближайших соседей (KNN) с использованием библиотеки HNSW. Эта функциональность входит в состав Manticore Columnar Library.
Чтобы выполнять поиск 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.
ПРИМЕЧАНИЕ: Построение графа HNSW при сохранении чанков RT, при слиянии чанков
OPTIMIZE TABLE/ auto-optimize и при перестройке KNN черезALTER TABLE ... ADD/DROP/REBUILDвыполняется параллельно по умолчанию на многопроцессорных хостах; число worker-потоков управляется настройкойsearchdknn_parallel_build(установите1, чтобы принудительно использовать последовательный путь). Это влияет только на скорость построения. Поскольку параллельное построение HNSW может вставлять векторы в другом порядке, итоговый граф может не быть побитово идентичен последовательной сборке.
- SQL
- JSON
- Config
create table test ( title text, image_vector float_vector knn_type='hnsw' knn_dims='4' hnsw_similarity='l2' );POST /sql?mode=raw -d "create table test ( title text, image_vector float_vector knn_type='hnsw' knn_dims='4' hnsw_similarity='l2' )"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.
Query OK, 0 rows affected (0.01 sec)[
{
"total": 0,
"error": "",
"warning": ""
}
]Самый простой способ работать с векторными данными - использовать автоэмбеддинги. С этой функцией вы создаете таблицу с параметрами 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-v4 - Явная форма provider-signal для пользовательских endpoint'ов:
openai:text-embedding-ada-002,openai:openai/text-embedding-ada-002,voyage:custom-model,jina:custom-model
Когда вы используете форму provider:model вместе с API_URL, часть перед : только выбирает формат запроса. Часть после : отправляется на удаленную конечную точку без изменений. Это полезно для шлюзов, совместимых с OpenAI, таких как OpenRouter или LiteLLM.
Поддерживаемые модели эмбеддингов:
| Тип модели | Пример | Требуется API-ключ | Примечания |
|---|---|---|---|
| ONNX (рекомендуется) | Xenova/all-MiniLM-L6-v2 |
Нет | Локальные модели из любого репозитория Hugging Face, который содержит файл .onnx. Работают на быстром бэкенде Manticore ONNX Runtime. Список: модели feature-extraction ONNX. |
| Sentence Transformers | sentence-transformers/all-MiniLM-L6-v2 |
Нет | Локальные модели на основе BERT, загружаются автоматически. По-прежнему поддерживаются — если доступно, используйте ONNX выше. |
| 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(только один файл) - Поддерживаемые семейства: Qwen, Llama, Mistral, Gemma
- Проверенные модели:
TinyLlama/TinyLlama-1.1B-Chat-v1.0,Locutusque/TinyMistral-248M-v2,Qwen/Qwen3-Embedding-0.6B,h2oai/embeddinggemma-300m - Другие модели
safetensorsтоже могут работать, но это не гарантируется
Дополнительную информацию о настройке атрибута float_vector можно найти здесь.
- SQL
- Config
Использование локальной ONNX-модели — рекомендуется (ключ API не нужен)
CREATE TABLE products (
title TEXT,
description TEXT,
embedding_vector FLOAT_VECTOR KNN_TYPE='hnsw' HNSW_SIMILARITY='l2'
MODEL_NAME='Xenova/all-MiniLM-L6-v2' FROM='title'
);Использование sentence-transformers (ключ API не нужен; работает через путь Candle — если доступно, используйте ONNX выше)
CREATE TABLE products_st (
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='Xenova/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":"Xenova/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":"Xenova/all-MiniLM-L6-v2","from":""}]}
}Важные замечания для plain-режима:
- При использовании
model_nameвы не должны указыватьdims- модель автоматически определяет размерность вектора. Параметрыdimsиmodel_nameвзаимоисключающие. - Если вы не используете
model_name(ручная вставка вектора), вы должны указатьdims, чтобы задать размерность вектора. - Параметр
fromзадает, какие поля использовать для генерации эмбеддингов (список через запятую или пустая строка для всех текстовых/строковых полей). Этот параметр обязателен при использованииmodel_name. - Для моделей на основе API (OpenAI, Voyage, Jina) включите параметр
api_keyв конфигурацию knn
При использовании автоэмбеддингов вы можете:
- Не указывать поле вектора и позволить Manticore сгенерировать эмбеддинги из полей, перечисленных в
FROM - Явно передать свой вектор для строки
- Передать
(), чтобы пропустить генерацию и сохранить нулевой вектор
Если позже вы выполните ALTER TABLE ... REBUILD EMBEDDINGS, строки, которые сейчас содержат нулевые векторы из (), тоже будут пересозданы.
- SQL
- JSON
Вставка только текстовых данных - эмбеддинги генерируются автоматически
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 сгенерирует эмбеддинги и найдет похожие документы:
- SQL
- JSON
SELECT id, knn_dist() FROM products WHERE knn(embedding_vector, 'machine learning');Использование текстового запроса с автоэмбеддингами
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]
}
}+------+------------+
| id | knn_dist() |
+------+------------+
| 1 | 0.12345678 |
| 2 | 0.87654321 |
+------+------------+
2 rows in set (0.00 sec){
"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). Такая нормализация сохраняет направление вектора, одновременно стандартизируя его длину, что требуется для эффективных вычислений косинусного сходства. Это означает, что сохраненные значения будут отличаться от исходных входных значений.
- SQL
- JSON
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) );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] }
}Query OK, 2 rows affected (0.00 sec){
"table":"test",
"id":1,
"created":true,
"result":"created",
"status":201
}
{
"table":"test",
"id":2,
"created":true,
"result":"created",
"status":201
}Теперь вы можете выполнять поиск KNN с помощью предложения knn как в формате SQL, так и в формате JSON. Оба интерфейса поддерживают одни и те же основные параметры, обеспечивая единообразный опыт независимо от выбранного формата:
- SQL:
select ... from <table name> where knn ( <field>, <query vector> [,<options>] ) - JSON:
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, чтобы отключить. Подробности см. в разделе Раннее завершение.
Когда задан текстовый запрос (то есть Manticore сначала встраивает строку перед поиском), число потоков, используемых библиотекой embeddings, можно переопределить для каждого запроса в SQL с помощью OPTION embeddings_threads = N. Это значение ограничивает вызов embeddings только для этого запроса, переопределяя глобальную настройку embeddings_threads; 0 означает отсутствие ограничения. Эта опция не влияет на запрос, если он передан в виде массива векторов.
Документы всегда сортируются по расстоянию до вектора поиска. Любые дополнительные критерии сортировки, которые вы укажете, будут применяться после этого основного условия сортировки. Чтобы получить расстояние, есть встроенная функция knn_dist().
- SQL
- JSON
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 } );POST /search
{
"table": "test",
"knn":
{
"field": "image_vector",
"query": [0.286569,-0.031816,0.066684,0.032926],
"ef": 2000,
"rescore": true,
"oversampling": 3.0
}
}+------+------------+
| id | knn_dist() |
+------+------------+
| 1 | 0.28146550 |
| 2 | 0.81527930 |
+------+------------+
2 rows in set (0.00 sec){
"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, но обычно менее точен.
- SQL
- JSON
create table test ( title text, image_vector float_vector knn_type='hnsw' knn_dims='4' hnsw_similarity='l2' quantization='1bit');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')"Query OK, 0 rows affected (0.01 sec)[
{
"total": 0,
"error": "",
"warning": ""
}
]ПРИМЕЧАНИЕ: Поиск похожих документов по id требует Manticore Buddy. Если он не работает, убедитесь, что Buddy установлен.
Поиск документов, похожих на конкретный документ по его уникальному ID, - распространенная задача. Например, когда пользователь просматривает определенный товар, Manticore Search может эффективно определить и показать список товаров, которые наиболее похожи на него в векторном пространстве. Вот как это сделать:
- SQL:
select ... from <table name> where knn ( <field>, <k>, <document id> ) - JSON:
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-поиска похожих документов.
- SQL
- JSON
select id, knn_dist() from test where knn ( image_vector, 5, 1 );POST /search
{
"table": "test",
"knn":
{
"field": "image_vector",
"doc_id": 1,
"k": 5
}
}+------+------------+
| id | knn_dist() |
+------+------------+
| 2 | 0.81527930 |
+------+------------+
1 row in set (0.00 sec){
"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, либо по полнотекстовому совпадению, либо по фильтрам атрибутов, либо по обоим сразу.
- SQL
- JSON
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;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 } } }
]
}
}
}+------+------------+
| id | knn_dist() |
+------+------------+
| 2 | 0.81527930 |
+------+------------+
1 row in set (0.00 sec){
"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. Это обеспечивает корректность и хорошую производительность даже при экстремальной селективности.
- SQL
- JSON
-- 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:
- SQL
- JSON
-- 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
}
}Когда стоит отключить раннее завершение:
- Когда критически важна точность набора результатов и вы не можете позволить себе никакой аппроксимации сверх той, которую уже обеспечивает HNSW.
- Когда используются низкие значения
k(примерно 30 или меньше), при которых раннее завершение дает мало выигрыша в производительности, но может снизить точность.