RecomNext

Pipeline & scenarios

Request stages, nextQL, constraints, auto-relax.

04 - Request pipeline & scenarios

Related: Logic & algorithms · Playbook

Stages of a recommendation request

Every recommendation request runs roughly this pipeline. Order matters when explaining “why isn’t item X showing?”

Stage notes

StageWhat it doesTunable in Admin?
1 ResolveLoad scenario by slug; pick algorithm (or default for logic)Scenario editor
2 CandidatesCH / Qdrant / factors / category fallbackAlgorithm + Qdrant/hybrid settings
3 AvailabilityDrop available: falseCatalog / feeds
4 FiltersRemove non-matching itemsfilter, rules type=filter
5 BoostersMultiply scoresboosters, rules type=booster
6 ConstraintsDiversity, freshness ×1.5, long-tail injectconstraints, rules type=constraint
7 SegmentsBalance across segmentssegmentationId, itemsPerSegment
8 Purchase capCap already purchased (90d)purchasedItemsMaxPercent (default 10); needs userId
9 Min/maxEnsure enough resultsminItems, maxItems, autoRelax*

Implementation detail: filters/boosters run inside applyScenario; constraints + segments + purchase cap run in postRankPipeline / ensureMinItems.


Scenario fields that matter

FieldPurpose
slugPlacement key (pdp-similar-products)
logicTypeuser-to-item / item-to-item / items-to-items / similar-products / recently-viewed
algorithmOverride default algo for that logic
filternextQL remove predicate
boosters[]nextQL boost expressions
constraintsmaxPerCategory, freshnessBoostDays, injectLongTail, longTailPercentage, purchasedItemsMaxPercent
qdrantSettingshnsw_ef, score_threshold, filter_categories, quantization_* (vector logics)
hybridSettingsmulti-seed-hybrid: strategy, rrfK, coTopK, vectorTopK, categoryBoost, …
rulesSlugs[]Attach shared filter/booster/constraint rules
minItems / maxItemsFloor / ceiling on result count
autoRelaxConstraintsIf under-filled, loosen constraints and retry
segmentationId / itemsPerSegmentDiversity across segments

Request-time post-process overrides

Recommendation APIs can replace selected post-process fields on a single request without editing the saved scenario:

FieldMeaning
filterReplace scenario nextQL filter (null / "" clears)
boostersReplace booster list (null / [] clears)
rulesSlugsReplace linked rules (missing slugs ignored)
segmentationIdReplace segmentation for balancing
itemsPerSegmentCompanion to segmentation (null1)

Semantics: omit a field → keep scenario (or none); send a value → replace that field only. Constraints stay scenario-only (no request override in v1).

Supported on:

  • POST /recommendations (JSON body)
  • Legacy GETs (user-to-item, item-to-item, recently-viewed, similar-products) — lists as comma-separated query params
  • POST /recommendations/items-to-items (JSON body)

Works with or without scenario. Browser / Node SDKs expose the same fields on recommend options. Admin Try it / Scenario Preview can exercise overrides without mutating the saved scenario.

When any override field is present, the Redis recommendation cache key includes a hash of the effective post-process config.


nextQL - filters & boosters

Filter examples

'price' < 50 and 'stock' > 0
'category' in ['games', 'software']
'platform' = 'Steam'

Matching items stay; others are removed from the scored list.

Booster examples

boost by 1.5 where 'featured' = true
boost by 1.2 where 'category' = 'premium'

If an item matches, score := score × factor. Multiple boosters can stack (sequential multiply).

Shared rules

Rules are reusable:

  • type: filter → expression added to filter list
  • type: booster → expression added to booster list
  • type: constraint → merges into constraints config

Scenario-local filter/boosters are applied in addition to rules.


Constraints (post-rank)

Applied in order:

  1. Diversity (maxPerCategory) - keep at most N items per category.
  2. Freshness (freshnessBoostDays) - items fresh within N days get ×1.5 score (date from tenant freshness config or createdAt).
  3. Long-tail (injectLongTail + longTailPercentage) - reserve ~P% of slots for low-interaction items.
  4. Re-sort by score and truncate.

Purchase cap (separate)

After ranking, if userId is provided:

  • Load distinct purchased item_ids for that user in 90 days.
  • Allow at most purchasedItemsMaxPercent (default 10%) of the result list to be already purchased (minimum 1 slot if percent>0 and list non-empty).

Without userId, purchase cap is skipped.


Auto-relax & min fill

If after the pipeline results.length < minItems and autoRelaxConstraints is on:

  • Round 1: double maxPerCategory, increase long-tail %, double freshness window, force long-tail on; re-run constraints.
  • Round 2: remove diversity cap, push long-tail higher, widen freshness further.

Also may expand itemsPerSegment if segment balancing is enabled.

Results are always capped by maxItems (and the requested count).


Sequence: scenario-shaped request


PM checklist when editing a scenario

  1. Confirm logic matches the placement (PDP → similar-products; cart → items-to-items).
  2. Confirm algorithm is intentional (default vs ML).
  3. Keep filters selective but not empty-set (pair with auto-relax / minItems).
  4. Use boosters for soft preference; filters for hard policy (geo, stock, brand exclusion).
  5. Set purchase cap thoughtfully for logged-in personalization.
  6. After changes, validate with Admin funnel and spot-check a few seed items in UI - metrics lag ingestion slightly.