Поиск
GET и POST /api/v1/indexes/{slug}/search — все параметры запроса, тело ответа и сопутствующие заголовки.
GET /api/v1/indexes/{slug}/search
POST /api/v1/indexes/{slug}/searchОба метода выполняют один и тот же запрос: GET принимает параметры в строке запроса, POST — в теле JSON, что удобнее для длинных выражений filter_by, векторных запросов и текста не в ASCII. Требуется право search:read; запрос списывает одну единицу поисковой квоты.
Короткий пример
curl -sS -G "$AAC_API/indexes/documentation/search" \
-H "Authorization: Bearer $AAC_KEY" \
--data-urlencode "q=тарифы и планы" \
--data-urlencode "query_by=title,content" \
--data-urlencode "query_by_weights=4,2" \
--data-urlencode "filter_by=tags:=[billing]" \
--data-urlencode "facet_by=tags" \
--data-urlencode "sort_by=_text_match:desc,published_at:desc" \
--data-urlencode "per_page=5"curl -sS -X POST "$AAC_API/indexes/documentation/search" \
-H "Authorization: Bearer $AAC_KEY" \
-H "Content-Type: application/json" \
-d '{
"q": "тарифы и планы",
"query_by": "title,content",
"filter_by": "tags:=[billing]",
"facet_by": "tags",
"per_page": 5
}'Ответ
{
"index": "documentation",
"query": "тарифы и планы",
"language": "ru",
"found": 2,
"out_of": 137,
"page": 1,
"per_page": 5,
"took_ms": 18,
"engine_ms": 4,
"hits": [
{
"id": "pricing",
"score": 2711,
"document": {
"id": "pricing",
"external_id": "pricing",
"title": "Тарифы",
"content": "На бесплатном тарифе 10 000 поисков в месяц. Pro — 29 USD…",
"url": "https://example.com/pricing",
"source_type": "api",
"organization_id": "org_01h9",
"tags": ["billing"],
"indexed_at": 1761214364
},
"highlights": [
{ "field": "title", "snippet": "<mark>Тарифы</mark>", "matchedTokens": ["тарифы"] },
{
"field": "content",
"snippet": "…29 USD в <mark>месяц</mark>…",
"matchedTokens": ["месяц"]
}
]
}
],
"facets": [
{
"field": "tags",
"values": [
{ "value": "billing", "count": 2, "highlighted": "billing" },
{ "value": "api", "count": 1 }
]
}
],
"request_id": "req_9a7c3d1e5f0b2a4c6d8e0f1a"
}| Поле | Значение |
|---|---|
language | Язык, определённый по q, используется как подсказка для стеммера |
found | Число совпадений с учётом фильтров |
out_of | Сколько документов просмотрено в коллекции |
took_ms | Время платформы, включая квоту и логирование |
engine_ms | Время, которое сообщил поисковый сервис |
hits[].score | Оценка текстового совпадения, чем больше — тем лучше |
hits[].highlights | Фрагменты с тегами <mark>, расставленными движком |
grouped_by | Появляется только при group_by: { field, groups[] } |
Пустая выдача — это 200 с found: 0 и пустым массивом hits. Такой запрос записывается в журнал как запрос без результатов.
Параметры
Все параметры опциональны, кроме q для POST (по умолчанию пустая строка, которую движок трактует как «всё подряд»).
| Параметр | Тип | Комментарий |
|---|---|---|
q | string ≤ 1000 | Текст запроса. Пустой означает «показать всё» (внутри — *) |
profile | string ≤ 64 | Сохранённый профиль поиска, чьи настройки берутся как значения по умолчанию |
query_by | string | Поля через запятую, по умолчанию title,content,tags |
query_by_weights | string | По весу на каждое поле query_by, например 4,2,1; количество должно совпадать |
filter_by | string ≤ 2000 | Выражение фильтра; не может ссылаться на organization_id |
sort_by | string ≤ 200 | field:asc,field2:desc; допускается _text_match:desc |
facet_by | string | Поля фасетов через запятую |
max_facet_values | int 1–50 | По умолчанию 10, ограничено настройкой развёртывания |
facet_query | string | tags: frontend — поиск по фасетам с facet_query_num_typos (0–3) |
page | int | По умолчанию 1, максимум 100 (SEARCH_MAX_DEEP_PAGE); большее значение отклоняется с 422 VALIDATION_ERROR, а не обрезается. Для более глубокого обхода используйте offset |
per_page | int | По умолчанию 10; значение обрезается до лимита развёртывания (SEARCH_MAX_PER_PAGE, по умолчанию 250), а не отклоняется |
offset | int | Альтернатива page |
limit_hits | int | Ограничение на общее число рассматриваемых совпадений |
num_typos | int 0–3 | По умолчанию 2 |
min_len_1typo / min_len_2typo | int 1–20 | Минимальная длина слова для допуска опечатки |
typo_tokens_threshold / drop_tokens_threshold | int 0–10 | Поведение для длинных запросов |
prefix | boolean | По умолчанию true; false отключает поиск по префиксу (семантический поиск принудительно его выключает) |
prioritize_exact_match | boolean | Предпочитать точные токены совпадениям с опечатками |
exhaustive_search | boolean | Обмен задержки на полноту |
search_cutoff_ms | int 0–60000 | Прервать запрос к движку по истечении бюджета |
group_by / group_limit | string / int 1–50 | Одно поле, одна группа результатов на значение |
highlight_fields, highlight_full_fields | string | Поля для фрагментов |
highlight_start_tag, highlight_end_tag | string ≤ 20 | Заменить <mark> своими тегами |
snippet_threshold | int 1–500 | Длина фрагмента вокруг совпадения |
include_fields, exclude_fields | string | Проекция возвращаемого документа |
vector_query | string | embedding:([0.1,0.2], k:10, alpha:0.6) для явного kNN |
semantic | boolean | Гибридный поиск по полю автоэмбеддинга индекса |
alpha | float 0–1 | Вес вектора при semantic=true: 0 — только ключевые слова, 1 — только вектор |
acl | string[] ≤ 32 | Принципалы user:<id>, group:<id> или role:<id> для доступа к документам. Учитываются только для серверного ключа без allowedOrigins и запроса без заголовка Origin; иначе игнорируются, и поиск идёт как анонимный (только публичные документы) |
Булевы значения принимают true/false и 1/0. Некорректные значения дают 422 VALIDATION_ERROR со списком замечаний Zod; корректные, но превышающие лимит движка — обрезаются.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request payload is invalid",
"request_id": "req_3c7a1f5b9d2e4c6a8b0d2f4e",
"details": {
"issues": [
{
"code": "too_small",
"path": ["num_typos"],
"message": "Number must be greater than or equal to 0"
}
]
}
}
}Семантический и гибридный поиск
semantic=true перестраивает запрос для индекса с полем автоэмбеддинга: поле эмбеддинга добавляется в query_by, prefix принудительно становится false (удалённый эмбеддер не умеет искать по префиксу), а в vector_query подставляется k, равный размеру страницы. alpha задаёт пропорцию.
curl -sS -G "$AAC_API/indexes/documentation/search" \
-H "Authorization: Bearer $AAC_KEY" \
--data-urlencode "q=сколько стоит тариф pro" \
--data-urlencode "semantic=true" \
--data-urlencode "alpha=0.6" \
--data-urlencode "per_page=3"Если поля автоэмбеддинга в индексе нет, запрос падает с 400 INVALID_QUERY и сообщением Index "…" has no auto-embedding field. semantic также требует функцию тарифа hybridSearch, а явный vector_query — vectorSearch. См. Семантический поиск.
Сохранённые профили и A/B
profile=<slug> применяет сохранённый профиль (query_by, веса, фасеты, сортировку, размер страницы) как значения по умолчанию; явно переданные параметры побеждают. Неизвестный слаг — 404 PROFILE_NOT_FOUND. Если у индекса включён settings.abTest и profile не передан, платформа детерминированно выбирает профиль по ключу и индексу: один и тот же ключ всегда попадает в одну корзину, и именно это делает сравнение в /analytics/experiments осмысленным. См. A/B-эксперименты.
Заголовки ответа
x-aac-quota-limit: 500000
x-aac-quota-remaining: 499996
x-aac-index: documentation
x-aac-profile: default
x-aac-charged-cents: 0
x-ratelimit-limit: 600
x-ratelimit-remaining: 412
x-ratelimit-reset: 1761214424x-aac-charged-cents отличен от нуля только когда включённая в тариф квота исчерпана и блок оплатил кошелёк.
Смежные эндпоинты индекса
Они относятся к той же поверхности и используют ту же модель доступа:
| Эндпоинт | Право | Назначение |
|---|---|---|
GET /indexes/{slug}/stats | search:read | Число документов, поля, объём запросов и средняя задержка за 24 часа |
POST /indexes/{slug}/events | analytics:write | Записать клик или конверсию |
GET /indexes/{slug}/widget-config | search:read | Профили поиска, доступные индексу |
POST /indexes/multi_search | search:read | Федеративный поиск: индексы перечислены в теле запроса |
GET/PUT /indexes/{slug}/synonyms; DELETE /indexes/{slug}/synonyms/{id} | settings:write | Одно- и многосторонние синонимы |
GET/PUT /indexes/{slug}/curations; DELETE /indexes/{slug}/curations/{id} | settings:write | Закрепление, скрытие и переписывание запросов |
POST /indexes/{slug}/reindex | settings:write | Перестройка без простоя |
curl -sS "$AAC_API/indexes/documentation/stats" \
-H "Authorization: Bearer $AAC_KEY"{
"index": {
"slug": "documentation",
"collection": "aac_org_01h9_documentation",
"documents": 137,
"fields": [
{
"name": "title",
"type": "string",
"facet": false,
"optional": true,
"index": true,
"sort": false,
"infix": false
},
{
"name": "tags",
"type": "string[]",
"facet": true,
"optional": true,
"index": true,
"sort": false,
"infix": false
}
],
"created_at": "2026-10-01T08:20:11.000Z"
},
"queries_24h": 1841,
"avg_latency_24h_ms": 17.42,
"usage": {
"plan": "pro",
"period": "2026-10",
"resetsAt": "2026-11-01T00:00:00.000Z",
"searches": { "used": 4120, "limit": 500000 },
"documents": { "used": 137, "limit": 50000 }
},
"request_id": "req_6e1b8d0a2c4f6a8d0b2e4c6a"
}