AACsearch
Архитектура

Аналитический контур обратной связи

Как поисковый запрос становится SearchUsageEvent, как фиксируются клики и конверсии и как агрегация питает дашборд для настройки релевантности.

Каждое публичное поисковое взаимодействие пишет строку в единую таблицу SearchUsageEvent. Одна таблица с дискриминатором type (search_query, zero_results, click, conversion, widget_open, filter_applied, visit) держит схему компактной и делает агрегацию дешёвой.

Сквозной цикл

Описание

Диаграмма показывает, как поисковый запрос, клик по результату и конверсия попадают в единую таблицу SearchUsageEvent с корреляцией по queryId, а затем агрегируются по индексу × часу × типу в метрики CTR, CVR и zero-result-rate. Дашборд аналитики Studio выводит эти метрики, а действия редактора (синонимы, curations, веса полей, presets) возвращаются обратно через policy-cache в read-path — цикл замыкается без деплоя.

flowchart LR
    classDef http fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef db fill:#fef3c7,stroke:#b45309,color:#78350f
    classDef agg fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef ui fill:#ede9fe,stroke:#6d28d9,color:#4c1d95

    subgraph Stage1["1 · Query"]
        SDK1["Customer SDK / Widget"] --> Search["/api/search/public/multi"]:::http
        Search --> Hit["TS multi_search<br/>returns hits"]
        Hit --> Resp["Response sanitized<br/>queryId attached"]
        Resp --> Ev1["recordSearchUsageAsync<br/>type=search_query"]:::db
        Hit --> Zero{"hits.length == 0?"}
        Zero -- yes --> Ev2["type=zero_results"]:::db
    end

    subgraph Stage2["2 · Click"]
        SDK2["Widget / SDK click handler"] --> Track1["/api/events/track<br/>type=result_click"]:::http
        Track1 --> Ev3["type=click<br/>{ queryId, productId, position }"]:::db
    end

    subgraph Stage3["3 · Conversion"]
        SDK3["Checkout / add-to-cart"] --> Track2["/api/events/track<br/>type=conversion"]:::http
        Track2 --> Ev4["type=conversion<br/>{ queryId, productId, conversionType }"]:::db
    end

    subgraph Stage4["4 · Aggregation (async)"]
        Ev1 --> Agg["analytics aggregation<br/>group by indexId × hour × type"]:::agg
        Ev2 --> Agg
        Ev3 --> Agg
        Ev4 --> Agg
        Agg --> CTR["CTR = clicks / search_query"]
        Agg --> CVR["CVR = conversion / click"]
        Agg --> ZRR["zero-rate = zero_results / search_query"]
    end

    subgraph Stage5["5 · Dashboard refresh"]
        CTR --> Studio["apps/saas analytics dashboard"]:::ui
        CVR --> Studio
        ZRR --> Studio
        Studio --> Tune["relevance tuning:<br/>synonyms, curations,<br/>field weights, presets"]
    end

    Tune -. feeds .-> Search

Типы событий

ТипКто эмититНесёт
search_querypublic-handler.ts (fire-and-forget)query, filters, sort, locale, queryId, referrer, ua
zero_resultspublic-handler.ts при found == 0та же форма, что у search_query
result_clickclickwidget / SDK → /api/events/trackqueryId, productId, position, sessionId
widget_openхостинговый widget при mountsessionId, anonymousUserId
filter_usedfilter_appliedwidget при переключении facetfilters (выбранная facet/значение), queryId
conversionинтеграция checkout → /api/events/trackqueryId, productId, conversionType (purchase, add_to_cart, ...)
visitопциональный widget на page-viewsessionId, anonymousUserId, referrer
click (сырой)клик, не связанный с поискомproductId, position

Все события имеют одинаковую форму строки { indexId, organizationId, type, count, metadata, createdAt }. JSON-колонка metadata — единственное поле со свободной схемой; она ограничена 4 КБ.

Что связывает клик с поиском

Серверное событие search_query чеканит стабильный queryId и возвращает его в ответе. Widget эхом отправляет queryId в каждом последующем событии click / conversion. Агрегация джойнит по (organizationId, indexId, queryId), чтобы посчитать click-through и конверсию для каждого запроса и каждого слота ранжирования.

Контур настройки

Аналитический дашборд Studio показывает три ключевых соотношения (CTR, CVR, zero-rate) и drilldown по конкретным запросам. Редактор может реагировать:

  • добавлять правило синонима или stemming для запроса с высоким zero-result,
  • продвигать SKU через curation set для запроса с низким CTR,
  • настраивать веса полей или собирать preset для запроса с низкой конверсией.

Эти изменения попадают в путь чтения через policy-cache (LRU 60 с) — цикл замыкается без деплоя.

См. также

On this page