Skip to content

Formula scoring

Formula queries reshape a candidate score with Qdrant score-builder expressions. Use them after a retrieval stage when business signals such as freshness, popularity, distance, or a payload tier should influence ranking.

$score represents the upstream score. DEFAULTS makes missing payload values predictable instead of leaving their behavior implicit.

QQLBlend relevance and citation countTry in playground
WITH candidates AS (
QUERY TEXT 'distributed systems'
USING dense
LIMIT 100
)
QUERY FORMULA
$score * 0.8 + LOG(citation_count + 1) * 0.2
DEFAULTS (
score = 0.0,
citation_count = 0
)
FROM papers
PREFETCH (candidates)
LIMIT 10;

Decay functions take a payload field followed by named (TARGET =, SCALE =, MIDPOINT =, DECAY =) or positional arguments. scale and midpoint/decay are numeric constants.

FunctionChoose it when
EXP_DECAYThe effect should drop quickly near the target and then taper
GAUSS_DECAYValues near the target should receive the smoothest peak
LIN_DECAYA simple, linear reduction is easiest to reason about
QQLFreshness and popularity signalsTry in playground
QUERY FORMULA
$score
+ EXP_DECAY(age_days, TARGET = 0, SCALE = 30, MIDPOINT = 0.5)
+ GAUSS_DECAY(popularity, TARGET = 100, SCALE = 25)
DEFAULTS (
score = 0.0,
age_days = 365,
popularity = 0
)
FROM articles
LIMIT 10;

Function names are case-insensitive. $score (or score) holds the upstream candidate score when no DEFAULTS entry overrides it.

FunctionSignature
ABS, SQRT, LOG, LN, EXPNAME(expr)
POWPOW(base, exponent)
GEO_DISTANCEGEO_DISTANCE(lat, lon, field) or GEO_DISTANCE({lat: ..., lon: ...}, field)
MATCH / MATCH_ANYMATCH(field, value) or MATCH_ANY(field, list)
EXP_DECAY, GAUSS_DECAY, LIN_DECAYNAME(field, TARGET = n, SCALE = n, ...) or positional
datetimedatetime('2026-01-01') — literal timestamp
datetime_keydatetime_key('published_at') — payload timestamp field

Formula precedence, highest to lowest, is unary -, multiplication/division, then addition/subtraction; operators are left-associative. A division may carry an explicit by-zero default with [DEFAULT = number]:

QQLDivision with a by-zero defaultTry in playground
WITH candidates AS (
QUERY TEXT 'distributed systems' USING dense LIMIT 10
)
QUERY FORMULA $score / (views + 1) [DEFAULT = 0]
DEFAULTS (score = 0.0, views = 0)
FROM docs
PREFETCH (candidates)
LIMIT 10;

Use CASE WHEN for a discrete condition. Keep the fallback explicit so a missing or non-matching value remains easy to audit.

QQLBoost a premium tierTry in playground
QUERY FORMULA
CASE WHEN tier MATCH ANY ('premium')
THEN $score * 1.5
ELSE $score
END
DEFAULTS (score = 0.0)
FROM docs
LIMIT 10;

Keep formula inputs indexed and measurable before adding them to a production ranking path.