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

Медленный поиск

Задержка поиска выше ожидаемой — диагностика холодных стартов, завышенного `perPage`, сложного `filterBy`, отсутствующих фасетов и давления вышестоящего поискового движка.

Здоровая медианная задержка поиска в AACsearch составляет < 50 мс внутри региона кластера, < 150 мс через публичный интернет. Если вы видите > 500 мс или спорадические тайм-ауты, пройдите по этим проверкам.

Симптомы

Что вы видитеПервая проверка
Первый запрос медленный, последующие быстрыеХолодный старт — прогрейте холостым запросом
Все запросы медленные, даже второйФорма запроса (perPage, filterBy)
Медленно только в пиковые часыПоключевая конкурентность или давление вышестоящего кластера
Случайные всплескиСетевой путь; проверьте из второго местоположения клиента
Тайм-ауты, 502, 503См. ошибки и лимиты запросов для стратегии повторов

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

Первый запрос после деплоя / перезапуска медленный?
  └─ да → холодный старт, прогрейте холостым запросом:
            client.search({ q: "*", perPage: 1 })

Все запросы медленные?
  ├─ perPage > 100      → уменьшить
  ├─ filterBy сложный   → упростить или предвычислить
  ├─ фасетов > 10 полей → уменьшить или перенести на отдельные запросы
  └─ всё минимально     → проверить страницу статуса; открыть тикет

Проверка 1: холодный старт

Первый запрос к только что развёрнутому воркеру может занимать на 200–500 мс дольше, чем в установившемся режиме, потому что ему нужно установить соединения и скомпилировать план запроса. Это нормально.

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

Смягчение: прогрейте воркер до запроса пользователя:

// При запуске приложения или через cron/edge prewarm
await client.search({ q: "*", perPage: 1 });

Для Vercel / Cloudflare Workers / аналогичных сред используйте запланированный вызов прогрева.

Проверка 2: завышенный perPage

perPage напрямую влияет на стоимость сериализации. Сервер масштабируется линейно после ~100; после ~250 доминирует кодирование JSON.

// ❌ Медленно даже на здоровом кластере
client.search({ q: "shoes", perPage: 1000 });

// ✅ Используйте пагинацию вместо этого
client.search({ q: "shoes", perPage: 50, page: 1 });

Если вам действительно нужны все совпадения, используйте documents/export с административным ключом — он потоковый и пагинируется на серверной стороне.

Проверка 3: сложный filterBy

Фильтры с многими условиями || (ИЛИ) или глубокими скобками медленны, потому что каждая ветка вычисляется.

// ❌ Одно большое ИЛИ по множеству id
filterBy: "id:=[id1,id2,...,id500]";

// ✅ Используйте anyOf, который работает напрямую с инвертированным индексом
filterBy: "id:[id1,id2,...,id500]";

// ❌ Вложенные группы
filterBy: "(brand:=Nike && price:<100) || (brand:=Adidas && price:<150) || ...";

// ✅ Предвычислите поле тега на этапе индексации
filterBy: "discount_tier:=tier_a";

Когда сомневаетесь, упростите фильтр и замерьте с помощью /search?stats=true (ответ включает searchTimeMs).

Проверка 4: слишком много фасетов

Каждое фасетное поле требует сортировки и агрегации по корзинам. После ~10 фасетов на запрос задержка заметно возрастает.

// ❌
facetBy: "brand,category,subcategory,size,color,material,season,fit,collection,store,warehouse";

// ✅ Показывайте только основные фасеты на первой странице; подгружайте вторичные лениво
facetBy: "brand,category,price";

Остальные можно отрисовать отдельными вызовами multi-search только когда пользователь открывает эту группу фильтров.

Проверка 5: логирование запросов

Ответ включает поле searchTimeMs, если вы включите его. Сравните его с вашей сквозной задержкой, чтобы понять, где теряется время.

const result = await client.search({ q: "shoes", debug: true });
console.log("сервер:", result.searchTimeMs, "мс");
console.log("сквозная:", endTime - startTime, "мс");
// Разница > 100 мс предполагает сетевые или прокси-накладные расходы, а не движок

Проверка 6: давление вышестоящего кластера

Если само значение searchTimeMs > 500 мс, проблема на вышестоящем уровне. Проверьте:

  • https://status.aacsearch.com на наличие текущих инцидентов
  • Поиск → Аналитика → график «p95 latency» (последние 24ч)
  • Если вы self-hosted: память и CPU инстанса AACSearch

Если статус зелёный, а ваши метрики аномальны, откройте тикет — см. диагностический пакет ниже.

Проверка 7: исчерпание пула соединений (только сервер)

Для серверных высококонкурентных вызывающих (10k+ qps с одного Node-процесса) стандартный пул соединений fetch может троттлиться под нагрузкой. Настройте:

import { Agent } from "undici";

const agent = new Agent({
  connections: 256, // по умолчанию 50
  pipelining: 10,
});

const client = new SearchClient({
  baseUrl: "...",
  apiKey: "...",
  indexSlug: "products",
  dispatcher: agent,
});

Для браузеров и Workers это не применимо.

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

ДиагнозИсправление
Холодный стартПрогреть холостым запросом q: "*"
perPage слишком высокУменьшить до ≤ 50, пагинировать
Сложный фильтрУпростить; предвычислить поля тегов на этапе индексации
Слишком много фасетовОграничить основными при первой отрисовке, остальные лениво
Сервер действительно медленныйПроверить страницу статуса; сообщить searchTimeMs в поддержку
Сетевые накладные расходыИспользовать регион ближе к кластеру; переиспользовать keep-alive соединения
Пул соединенийНастроить undici Agent для серверных вызывающих

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

ПолеПримечания
ID организацииобязательно
Slug индексаобязательно
Временное окно (UTC)начало и конец медленного периода
searchTimeMs из примера ответаобязательно
Медианная сквозная задержкаиз вашего собственного мониторинга
Пример тела запросаминимальный падающий случай
Регион вызывающегодатацентр / город / облачный регион
Конкурентностьзапросов в секунду от этого вызывающего

Если вы можете воспроизвести медленность одним curl, вставьте его. Воспроизводимые случаи решаются примерно в 4× быстрее, чем «иногда кажется медленным».

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

On this page