Compound queries
Compound queries wrap or combine other queries to change their logic or score — bool, dis_max, function_score, boosting, and constant_score.
Why it matters
Real relevance tuning lives here. Beyond AND/OR, you often need to take the single best field instead of summing (cross-field search), boost by recency or popularity, demote (not exclude) certain docs, or strip scoring entirely. Each compound query is a precise tool for one of those shapes.
How it works
Each compound type composes child queries with different score arithmetic.
| Query | Combines via | Use case |
|---|---|---|
bool | AND/OR/NOT, additive | general logic |
dis_max | max of child scores + tie_breaker | best single field wins |
function_score | query × functions | boost by field value/decay/script |
boosting | positive − negative_boost | demote without removing |
constant_score | fixed score | turn a query into a filter |
dis_max— takes the highest child score so a strong title match isn’t diluted by weak body matches;tie_breaker(e.g. 0.3) adds a fraction of the others.function_score— multiply_scorebyfield_value_factor,gauss/linear/expdecay (recency, geo distance), or a Painlessscript_score; combine withboost_mode/score_mode.boosting—positivematches normally,negativematches get multiplied bynegative_boost(0–1) to sink them.constant_scorewraps a filter, yielding filter context with a flat score.
Example
{ "function_score": {
"query": { "match": { "title": "smartphone" } },
"functions": [
{ "gauss": { "released": { "origin": "now", "scale": "30d", "decay": 0.5 } } },
{ "field_value_factor": { "field": "rating", "modifier": "log1p" } } ],
"score_mode": "sum", "boost_mode": "multiply" } }
Newer, higher-rated phones rise: text relevance is multiplied by a recency decay and a dampened rating factor.
Pitfalls
function_scoreorder —boost_mode(query vs functions) vsscore_mode(between functions) are distinct; confusing them flattens or explodes scores.script_scorecost — runs per matching doc per shard; cache-unfriendly and slow on large result sets.dis_maxwithouttie_breakerignores secondary matches entirely — sometimes intended, often not.- Decay
scaleunits —scale:"30d"means score halves (atdecay) 30 days out; mis-sizing it makes recency dominate or vanish.