AACsearch
Диагностика

Пустые результаты

Поиск возвращает `found: 0` для запросов, которые должны находить совпадения — диагностика отсутствующих документов, слишком узких фильтров, фильтров токенов с ограниченной областью и несоответствий `queryBy`.

Пустые результаты почти всегда вызваны одной из четырёх причин. Выполняйте проверки по порядку.

Симптом

{
  "hits": [],
  "found": 0,
  "page": 1,
  "perPage": 10,
  "facetCounts": []
}

200 с found: 0 — это не ошибка. Это означает «запрос был валиден, ни один документ не совпал».

Дерево решений

1. Заполнен ли индекс фактически?
   - Поиск → Индексы → посмотрите на количество "Documents"
   - Если 0 → см. [Ошибки индексации](/troubleshooting/ingest-failures)

2. Существует ли поле запроса в документах?
   - queryBy перечисляет поля для поиска
   - Если вы queryBy по полю, которого нет, ни один документ не может совпасть

3. Не слишком ли узкие фильтры?
   - Полностью удалите filterBy и повторите
   - Если результаты возвращаются, причиной был фильтр

4. Не комбинирует ли токен с ограниченной областью скрытый фильтр через И?
   - Токены с ограниченной областью всегда комбинируют через И свой scopedFilter
   - Декодируйте токен, чтобы увидеть, что добавляется

Проверка 1: в индексе есть документы

curl -X GET https://app.aacsearch.com/api/v1/projects/<projectId>/indexes \
  -H "Authorization: Bearer aa_admin_..."

Посмотрите на поле documentCount у соответствующего индекса. Если 0, индексация не производилась или завершилась сбоем.

Вы также можете проверить из дашборда: Поиск → Индексы → колонка «Documents».

→ Если 0, перейдите к Ошибки индексации.

Проверка 2: queryBy соответствует индексированным полям

queryBy — это разделённый запятыми список полей, которые сканирует поисковый движок. Поле должно существовать в схеме индекса и быть строкового типа.

// ❌ Это никогда ничего не найдёт, если поле называется `name`, а не `title`
client.search({ q: "shoes", queryBy: "title" });

// ✅ Совпадение с фактическим полем
client.search({ q: "shoes", queryBy: "name,description" });

Проверьте схему:

const indexes = await admin.listIndexes();
const products = indexes.find((i) => i.slug === "products");
console.log(products.fields);
// → посмотрите, какие поля имеют тип "string" или "string[]"

Проверка 3: фильтры сужают до нуля

Удалите filterBy и перезапустите:

// Исходный — возвращает 0
await client.search({
  q: "shoes",
  queryBy: "name",
  filterBy: "in_stock:=true && price:<50 && brand:=Nike",
});

// Удалите фильтры
await client.search({ q: "shoes", queryBy: "name" });
// → 247 результатов

// Добавляйте фильтры обратно по одному, чтобы найти проблемный

Частая причина — сравнение строкового фасета с числовым оператором (:<, :>) — движок возвращает 0, потому что сравнение не может быть вычислено.

Проверка 4: комбинированный через И фильтр токена с ограниченной областью

Если вы используете токен с ограниченной областью, scopedFilter токена молча комбинируется через И с тем, что передаёт вызывающий. Со стороны запроса это невидимо.

Декодируйте токен, чтобы увидеть, что добавляется:

const [, payloadB64] = scopedToken.replace("ss_scoped_", "").split(".");
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
console.log(payload.scopedFilter);
// → "organization_id:=org_abc && availability:=in_stock"

Если фильтр токена исключает документы, которые вы ожидаете, создайте новый токен с правильным фильтром (на серверной стороне; см. Токены поиска с ограниченной областью действия).

Токены с ограниченной областью могут только сужать доступ. Комбинация через И обеспечивается функцией combineFilters() в packages/api/modules/search/lib/scoped-token.ts — Жёсткий инвариант 4 в кодовой базе. Расширить токен с ограниченной областью с клиента невозможно.

Другие причины

Допуск опечаток установлен в 0

По умолчанию AACsearch допускает небольшие опечатки. Если на индексе или в запросе установлено numTypos: 0, "shose" не совпадёт с "shoes".

client.search({ q: "shose", queryBy: "name", numTypos: 2 });

Стоп-слова отфильтровали весь запрос

Частые слова ("the", "and") удаляются перед поиском. Запрос, состоящий только из стоп-слов, ничего не возвращает. Добавьте более специфичный термин.

Синонимы не загружены

Если вы ожидаете, что "sneaker" совпадёт с "shoe", проверьте, что набор синонимов опубликован:

const synonyms = await admin.listSynonyms(indexId);
console.log(synonyms);

→ См. Поисковый API → мульти-поиск и запросы для полной конфигурации синонимов.

Недавно проиндексировано, но ещё не видно

Документы проходят через SearchIngestBuffer, прежде чем попасть в живой индекс. Типичная задержка < 30 секунд; холодный старт может быть дольше. Если вы только что отправили, подождите и повторите.

# Проверьте глубину очереди буфера (admin API)
curl -X GET https://app.aacsearch.com/api/v1/projects/<projectId>/usage \
  -H "Authorization: Bearer aa_admin_..."

Матрица решений

ДиагнозРешение
Индекс пустОтправьте документы — см. Ошибки индексации
Поле queryBy не существуетИспользуйте реальное поле; проверьте схему
Фильтр слишком узкийОслабьте filterBy; удалите и добавляйте обратно по одному условию
Токен с ограниченной областью исключает целевые документыСоздайте новый токен с ограниченной областью на серверной стороне с правильным фильтром
Опечатка или необычное написаниеУстановите numTypos в 1 или 2
Недавняя индексация не виднаПодождите 30 секунд и повторите; проверьте глубину очереди буфера

Диагностический пакет

ПолеПримечания
ID организацииобязательно
Slug индексаобязательно
Полное тело запросавключая q, queryBy, filterBy, sortBy
Ожидаемое совпадениеодин ID документа или external_id, который вы ожидали увидеть
Количество документов в индексеиз listIndexes() или дашборда
Используется ли токен с ограниченной областьюда/нет — если да, декодированная нагрузка (без подписи)

Связанные страницы

On this page