NEW

Pulse 2025 Product Roundup: From Monitoring to AI-Native Control Plane

Elasticsearch Function Score Query: Syntax, Functions, and Examples - Syntax, Example, and Tips

The Elasticsearch function_score query wraps another query and modifies each matching document's _score using one or more scoring functions. It works on any indexed field referenced by a function, and is the standard tool for boosting by recency, popularity, geo-distance, or custom logic without rewriting the inner query. Use it when sorting by _score no longer reflects business relevance.

Syntax

{
  "query": {
    "function_score": {
      "query":      { "match_all": {} },
      "functions":  [ /* one or more function clauses */ ],
      "score_mode": "multiply",
      "boost_mode": "multiply",
      "max_boost":  3.4028235e38,
      "min_score":  0.0,
      "boost":      1.0
    }
  }
}

If a single function is used, the functions array can be omitted and the function placed directly under function_score.

Parameters

Parameter Type Default Description
query query object match_all Inner query that produces the base _score.
functions array - One or more function clauses, each optionally with a filter.
score_mode string multiply How function scores combine: multiply, sum, avg, first, max, min.
boost_mode string multiply How combined function score combines with query _score: multiply, sum, avg, replace, max, min.
max_boost float FLT_MAX Caps the final function-score contribution.
min_score float - Excludes documents below this final score.
boost float 1.0 Query-level boost on the wrapped query.

The five available function types are: script_score, weight, random_score, field_value_factor, and the decay functions (linear, exp, gauss).

Examples

Boost by document popularity using field_value_factor:

{
  "query": {
    "function_score": {
      "query": { "match": { "title": "elasticsearch" } },
      "field_value_factor": {
        "field": "popularity",
        "factor": 1.2,
        "modifier": "log1p",
        "missing": 1
      },
      "boost_mode": "multiply"
    }
  }
}

Recency decay on a date field:

{
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "exp": {
        "published_at": { "origin": "now", "scale": "30d", "decay": 0.5 }
      }
    }
  }
}

Combine multiple functions with per-function filters:

{
  "query": {
    "function_score": {
      "query": { "match": { "title": "phone" } },
      "functions": [
        { "filter": { "term": { "in_stock": true } }, "weight": 2 },
        { "field_value_factor": { "field": "rating", "modifier": "sqrt", "missing": 1 } },
        { "gauss": { "price": { "origin": "500", "scale": "100" } } }
      ],
      "score_mode": "sum",
      "boost_mode": "multiply",
      "min_score": 0.1
    }
  }
}

Reproducible random scoring (good for A/B sampling):

{
  "query": {
    "function_score": {
      "random_score": { "seed": 42, "field": "_seq_no" }
    }
  }
}

Performance and Use Notes

Each function executes per matching document, so function_score scales with the size of the result set produced by the inner query. Filter aggressively before applying expensive functions: narrow the inner query with bool.filter clauses, then let function_score rerank what survives. Decay and field_value_factor use doc values and are cheap; script_score is by far the most expensive option and triggers script compilation if params is not used to keep the source stable.

Poorly tuned scoring functions often manifest as slow shard queries and rising CPU. The manual loop - profile the slow log, identify which function_score clause is dominating, check each function's filter scope, decide which script_score could be replaced by a native function - is exactly what Pulse automates.

Common Mistakes

  1. Using boost_mode: replace and then wondering why the inner query's relevance signal disappeared.
  2. Applying field_value_factor to a field without doc values (e.g. text without keyword subfield), causing failures or high heap.
  3. Forgetting missing on field_value_factor; documents lacking the field throw an error by default.
  4. Stacking many functions with score_mode: sum and producing scores dominated by one feature.
  5. Using random_score without a seed, producing non-reproducible result orders between requests.

Find Slow function_score Queries with Pulse

Pulse is an AI DBA for Elasticsearch and OpenSearch that continuously profiles production query traffic. For function_score queries specifically, Pulse:

  • Identifies function_score queries whose inner clause matches too many documents, so each function runs per-doc on an inflated set
  • Flags field_value_factor clauses on fields without doc values (often a text field missing a .keyword sub-field) and field_value_factor without missing, which throws on documents lacking the field
  • Detects nested script_score functions that are not parameterized, so per-request source strings thrash the script compilation cache
  • Traces each slow function_score back to the calling service via slow-log and APM correlation
  • Recommends concrete rewrites: pre-filter the inner query with bool.filter, replace script_score functions with field_value_factor or decay (linear / exp / gauss) where possible, parameterize remaining scripts, switch boost_mode away from replace if the inner relevance signal still matters, and cap with max_boost or min_score
  • Tracks latency improvement after the change

This converts the manual scoring-debug loop into a continuous optimization workflow.

Try Pulse on your cluster.

Frequently Asked Questions

Q: What is the difference between score_mode and boost_mode in function_score?
A: score_mode controls how multiple function clauses combine into a single function score. boost_mode controls how that combined function score then combines with the inner query's _score. Both default to multiply.

Q: What are the five function types available in Elasticsearch function_score?
A: The function_score query supports script_score, weight, random_score, field_value_factor, and decay functions (linear, exp, gauss). Decay functions are typically used for numeric, date, or geo fields.

Q: When should I use function_score vs script_score query?
A: Use function_score when standard functions (decay, popularity boost, weighted filters) cover the requirement. Use the standalone script_score query when scoring is pure custom math and you do not need to combine multiple functions or per-function filters.

Q: Does function_score work with filter context?
A: No. The function_score query runs in query context because it computes scores. Filters that do not affect scoring should live in a bool.filter inside the wrapped query.

Q: How do I debug a function_score query in Elasticsearch?
A: Add "explain": true to the search request or call the _explain API for a specific document. Elasticsearch returns a tree showing each function's contribution and how score_mode / boost_mode combined them.

Q: Why is my function_score query slow?
A: Most slow function_score queries either match too many documents in the inner query or use a script_score function whose source changes per request. Narrow the inner query with filters, parameterize scripts so they cache, and prefer decay or field_value_factor over scripts when possible.

Q: What is the best tool to find slow function_score queries in production?
A: Pulse profiles Elasticsearch and OpenSearch slow logs, isolates function_score queries with bloated inner clauses or non-parameterized nested scripts, attributes each to the calling service, and recommends pre-filtering, native-function replacements for script_score, and proper missing handling on field_value_factor.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.