Запросы без результатов
Петля восстановления — детект нулевых запросов, закрытие gap-а синонимами / curations / контентом, измерение улучшения.
No-result-запрос — поиск, вернувший 0 хитов. Самое сигнальное событие в вашей аналитике: пользователь сказал точно, чего хотел, а вы сказали «у меня этого нет». Каждый такой запрос — либо relevance-промах (ответ есть, не нашли), либо content gap (нет ответа).
Это playbook по триажу.
Как фиксируются
Публичный поисковый handler пишет type: "zero_results" в SearchUsageEvent, когда found === 0. Top Queries показывает отдельный срез, дашборд — KPI-плитку no-results-rate.
Событие несёт:
- Сырой
query. - Активный
filterBy(часто — причина нуля). indexSlug.locale.searchTimeMs, чтобы отличать таймауты от настоящих пусто.
Чтение no-results-панели
const zr = await orpc.search.topQueries.call({
organizationId,
period: "30d",
filter: { zeroResults: true },
limit: 50,
});Сортируйте по объёму. Топ-10–20 — это работы на эту неделю; хвост — backlog для контент-команды.
Три колонки вместе:
| Колонка | Сигнал |
|---|---|
query | Литеральная фраза пользователя. |
searches | Сколько разных сессий попали в пусто. |
withFilter | Был ли активен filterBy — «ноль с фильтром» часто из-за фильтра, а не каталога. |
iphone 15 с 200 zero-result-searches без фильтра — content gap. Тот же запрос с 200 zero и filterBy: "brand:=Samsung" — UX фильтров.
Триаж по шагам
По каждому топ-no-result, по порядку:
Шаг 1 — Опечатка или известный синоним?
Прогон в Search Preview. Если fuzzy сработал бы, но не сработал (typo-tolerance off, или запрос слишком длинный):
- Проверьте typo-tolerance — Filters, sorting & pagination.
- Добавьте синоним для региона или бренда.
Шаг 2 — Реальный продукт/статья с vocabulary mismatch?
Ищите в каталоге напрямую (без запроса пользователя). Если нужный документ нашёлся — ответ был в индексе, слова пользователя его не дотянули:
- Synonym mapping (например,
"airpods" → "wireless earbuds"). - Добавить альтернативный термин в
tags/descriptionдокумента. - Поднять вес соответствующего поля в
queryBy.
Шаг 3 — Filter-induced ноль?
Если withFilter = true и базовый запрос матчится без фильтра:
- Это UX. В клиенте детектите filter-induced-zero и показывайте «Clear filters to see X more results».
- Долгосрочно: в виджете дизейблить фильтр-значения, дающие ноль при текущем запросе (graceful filter pruning).
Шаг 4 — Content gap?
Если ни synonym, ни filter-фикс не подошёл — у вас правда нет ответа. Это контент-команда:
- Добавить недостающий продукт / статью.
- Re-ingest.
- Пометить запрос как «watched», чтобы измерять восстановление.
Измерение восстановления
После фикса смотрим тот же запрос в двух периодах:
const before = await orpc.search.topQueries.call({
organizationId,
period: "30d",
offsetDays: 30,
filter: { zeroResults: true },
});
const after = await orpc.search.topQueries.call({
organizationId,
period: "30d",
filter: { zeroResults: true },
});Успех — запрос уходит из zero-result-списка в «after». Не ушёл — фикс не прилетел: обычно reindex ещё не отработал или синоним был добавлен не в тот индекс.
KPI no-results-rate
Плитка в дашборде:
no-results rate = zero-result searches / total searchesЦель здорового storefront-а — < 5 %. > 10 % — серьёзный vocabulary mismatch. > 20 % — почти всегда баг в роутинге индекса.
Трекайте недельно. Резкий скачок обычно коррелирует с деплоем (новое поле схемы, новая локаль, новый коннектор) — bisect-те через Activity.
Bulk-паттерны
Для очень высокой кардинальности — построчно не разобраться. Два bulk-паттерна:
Кластер по токенам
Берёте топ-500 no-result, lowercase / tokenize, считаете самые частые общие токены. Кластер запросов с одним токеном ("airpods" в "airpods", "airpods pro", "new airpods") — один фикс (добавить термин) гасит кластер.
Кластер по brand / категории
Та же идея, но по фасетам. Если 200 zero-result-ов парсятся в «Brand: Acme, Category: phones» — у вас отсутствует продуктовая линейка.
Export отдаёт сырые строки; оба кластера — 20 строк скрипта.
Восстановление через AI fallback
Когда всё остальное не сработало — no-result-UX это естественная поверхность для fallback-а:
- Гибридный semantic search, когда keyword вернул ноль.
- Или AI answer поверх ближайших связанных товаров.
Не делайте дефолтом — оба добавляют латентность и стоимость — но на zero-ветке это оправдано, потому что альтернатива — ничего не показать.
Телеметрия по fallback-у
Если включаете AI fallback — инструментируйте:
trackEvent({
type: "search_query",
query,
metadata: { fallback: "ai_answer", originalFound: 0 },
});Тогда можно посчитать «AI fallback effectiveness» — как часто zero-result-сессия с fallback заканчивается кликом — и решить, оправдывает ли fallback себя.