AACsearch
Recommendations

Recommendations

Overview of AACsearch recommendation engines — similar items, also-viewed, frequently-bought-together, trending, personalized, and GraphRAG. Which engine to pick for which surface.

AACsearch ships seven recommendation engines built on the same indexed corpus that powers search. They are designed to be dropped onto a product page, cart, homepage, or empty-result fallback without standing up a separate ML stack.

EngineInput you supplyBest surfaceCode path
Similar itemsOne product/document IDProduct detail pageGET /recommendations/similar
Also viewedOne product ID"Customers also viewed" railGET /recommendations/also-viewed
Frequently bought togetherOne product IDCart, PDP "Complete the look"GET /recommendations/frequently-bought-together
TrendingOptional category/segment filterHomepage, empty resultsGET /recommendations/trending
PersonalizeduserId (session or signed-in)Homepage logged-in, push emailGET /recommendations/personalized
GraphRAG recommendationsOne node + KnowledgeSpaceKnowledge graph navigationGET /knowledge/graphrag/recommendations
User segmentsSegment definition (rules)Cohort targetingGET /recommendations/user-segments

Picking an engine

Use this decision flow:

  1. You know the current item the user is looking atSimilar for taste-match, Frequently bought together for cart attach, Also viewed for navigation.
  2. You know who the user is (logged in or session id) → Personalized.
  3. You don't know either (anonymous, empty cart, blank homepage) → Trending.
  4. You're inside a knowledge graph (RAG/agentic flow, not commerce) → GraphRAG recommendations.

The engines compose — the dashboard's "Recommended for you" rail typically chains Personalized → Trending so a brand-new visitor with no history still gets something.

Tenancy & scope

Every recommendation request requires:

  • A bearer token scoped to one organization (same auth as POST /search).
  • An indexId or collectionName so the engine knows which corpus to score against.

Recommendations never cross indexes or organizations. The tenant filter is compiled at the SQL WHERE level (Invariant 4), not just at the API gate.

Latency profile

EngineRead p95 (Pro tier)Notes
Similar80 msVector search on item embedding; fast.
Also viewed50 msCo-occurrence lookup, precomputed.
Frequently bought together60 msCo-cart-occurrence, precomputed.
Trending40 msRead from precomputed daily/hourly bucket.
Personalized120 msVector + filter; slower because of the per-user re-ranking.
Personalized from analytics200 msWalks recent events for the user, more I/O.
GraphRAG150 msGraph traversal + LLM step (cached).

These are budgeted under the read-path SLO described in Performance & scaling. Stay within them and recommendations slot into the same multi_search round-trip as the rest of the page.

Quota cost

Each call to a recommendation endpoint counts as one Search Unit against the monthly quota (maxSearchesPerMonth). Same cost as a POST /search. See Plans & Limits → Search Units.

Configuration surface

For engines that have tunables (model choice, decay window, segment membership), the config lives in:

  • GET /recommendations/personalization-config / PATCH …config
  • Dashboard → Search → Recommendations → Settings

Defaults are sensible. Touch the config only when you know exactly which lever you are pulling — every option has an inline doc-link.

Cold start. Personalized engines need ≥ 5 events for a given user before they outperform Trending. If you see uniform-looking results for a brand-new user, that is correct behaviour — the engine is in cold-start mode. Trending is the fallback, and the dashboard surfaces this explicitly.

Telemetry

Every recommendation surface logs:

  • recommendation_shown — engine, request id, returned IDs
  • recommendation_clicked — which ID the user clicked (drives "uplift" charts)
  • recommendation_converted — purchase / conversion attributed back

These events feed the Recommendations card in Dashboard → Analytics, plus the per-engine CTR/conversion rollup. They use the same analytics event bus as search (SearchUsageEvent), so historic data follows the same retention as search analytics.

Further reading

On this page