AACsearch
Architecture

Boucle de feedback analytique

Comment une requête de recherche devient un SearchUsageEvent, comment les clics et conversions sont enregistrés, et comment l'agrégation alimente le tableau de bord pour l'ajustement de pertinence.

Chaque interaction publique de recherche émet une ligne dans la table unifiée SearchUsageEvent. Une seule table avec un discriminateur type (search_query, zero_results, click, conversion, widget_open, filter_applied, visit) garde le schéma petit et rend l'agrégation peu coûteuse.

Boucle de bout en bout

Description

Le diagramme montre comment une requête de recherche, un clic résultat et une conversion atterrissent tous dans la table unifiée SearchUsageEvent avec une corrélation queryId, puis sont agrégés par index × heure × type en métriques CTR, CVR et taux zéro-résultat. Le tableau de bord d'analytique Studio expose ces métriques, et les actions de l'éditeur (synonymes, curations, poids de champ, presets) refluent par policy-cache jusqu'au read path — la boucle se referme sans déploiement.

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

Les types d'événements

TypeÉmis parPorte
search_querypublic-handler.ts (fire-and-forget)query, filters, sort, locale, queryId, referrer, ua
zero_resultspublic-handler.ts quand found == 0même forme que search_query
result_clickclickwidget / SDK → /api/events/trackqueryId, productId, position, sessionId
widget_openwidget hébergé au montagesessionId, anonymousUserId
filter_usedfilter_appliedwidget au toggle de facetfilters (la facette/valeur choisies), queryId
conversionintégration checkout → /api/events/trackqueryId, productId, conversionType (purchase, add_to_cart, ...)
visitwidget optionnel au chargement de pagesessionId, anonymousUserId, referrer
click (brut)clic non lié à une rechercheproductId, position

Tous les événements partagent la forme de ligne { indexId, organizationId, type, count, metadata, createdAt }. La colonne JSON metadata est le seul champ schéma-flexible ; elle est plafonnée à 4 Ko.

Ce qui relie un clic à une recherche

L'événement search_query côté serveur frappe un queryId stable et le renvoie dans la réponse. Le widget renvoie le queryId dans chaque événement click / conversion ultérieur. L'agrégation joint sur (organizationId, indexId, queryId) pour calculer le click-through et la conversion par requête, par slot de ranking.

Boucle d'ajustement

Le tableau de bord analytique du Studio expose les trois ratios clés (CTR, CVR, taux de zéro-résultat) plus des drilldowns par requête. Un éditeur peut agir dessus en :

  • ajoutant une règle de synonyme ou de stemming pour une requête à fort taux de zéro,
  • promouvant une SKU via un curation set pour une requête peu cliquée,
  • ajustant les poids de champs ou construisant un preset pour une requête à conversion lente.

Ces éditions arrivent dans le chemin de lecture via policy-cache (LRU 60 s) — la boucle se ferme sans déploiement.

Liens associés

On this page