diff --git a/_query-dsl/compound/function-score.md b/_query-dsl/compound/function-score.md
index 70331d2709f..4ac4a544ab5 100644
--- a/_query-dsl/compound/function-score.md
+++ b/_query-dsl/compound/function-score.md
@@ -12,9 +12,15 @@ redirect_from:
Use a `function_score` query if you need to alter the relevance scores of documents returned in the results. A `function_score` query defines a query and one or more functions that can be applied to all results or subsets of the results to recalculate their relevance scores.
+## Default query behavior
+
+If you omit the top-level `query` parameter, `function_score` defaults to `match_all`. Every document in the index is considered a match and receives a base query score of `1`.
+
+`function_score` changes how documents are **ranked**, not which documents are returned (unless you use `min_score`). To limit which documents are returned, provide an explicit top-level `query` or wrap `function_score` in a `bool` query.
+
## Using one scoring function
-The most basic example of a `function_score` query uses one function to recalculate the score. The following query uses a `weight` function to double all relevance scores. This function applies to all documents in the results because there is no `query` parameter specified within `function_score`:
+The most basic example of a `function_score` query uses one function to recalculate the score. The following query uses a `weight` function to double all relevance scores. This function applies to all documents in the results because there is no top-level `query` parameter specified, so `function_score` runs on `match_all`:
```json
GET shakespeare/_search
@@ -28,9 +34,13 @@ GET shakespeare/_search
```
{% include copy-curl.html %}
-## Applying the scoring function to a subset of documents
+## Limiting which documents are scored
+
+Use the top-level `query` parameter to define which documents `function_score` runs on. Only documents matching this query are returned.
-To apply the scoring function to a subset of documents, provide a query within the function:
+To apply a scoring function only to a subset of those documents, use a `filter` inside a function in the `functions` array. A function `filter` controls whether that function contributes to the score; it does **not** exclude documents from the result set.
+
+The following query limits results to documents matching `Hamlet` and then doubles their relevance scores:
```json
GET shakespeare/_search
@@ -49,6 +59,60 @@ GET shakespeare/_search
```
{% include copy-curl.html %}
+## Using filters in the functions array
+
+Each entry in `functions` can include an optional `filter`. The function runs only for documents that match that filter.
+
+**Important:** Function filters affect scoring, not document inclusion. Documents that match the top-level query (or implicit `match_all`) but match **no** function filters are still returned.
+
+When no function matches a document, the combined function score uses a neutral factor of `1` for most `score_mode` values (including `sum` and the default `multiply`). With the default `boost_mode` of `multiply`, the final score is typically:
+
+$$ \text{final score} = \text{query score} \times \text{function factor} = 1 \times 1 = 1 $$
+
+Use `explain: true` to see this as `No function matched` in the explanation.
+
+### Example: Weighted filters without a top-level query
+
+The following query assigns weights when `genre` is `detective` or `author` is `Conan Doyle`. Because no top-level `query` is specified, `function_score` runs on `match_all` and returns every document in the index:
+
+```json
+GET books/_search
+{
+ "query": {
+ "function_score": {
+ "score_mode": "sum",
+ "functions": [
+ {
+ "filter": {
+ "term": {
+ "genre": "detective"
+ }
+ },
+ "weight": 0.5
+ },
+ {
+ "filter": {
+ "term": {
+ "author": "Conan Doyle"
+ }
+ },
+ "weight": 1
+ }
+ ]
+ }
+ }
+}
+```
+{% include copy-curl.html %}
+
+In the results:
+
+- A document matching both filters receives `_score: 1.5` (function factor `0.5 + 1.0`, multiplied by the `match_all` query score of `1`).
+- A document matching only the `author` filter receives `_score: 1.0`.
+- A document matching **no** filters still receives `_score: 1.0`. This is expected: the implicit `match_all` query contributes `1`, and the neutral function factor is also `1`.
+
+To return only documents that match at least one filter, use a `bool` query with `minimum_should_match` instead of relying on `function_score` alone. You can then nest `function_score` inside the `bool` query to re-rank the matching documents.
+
## Supported functions
The `function_score` query type supports the following functions:
@@ -686,6 +750,8 @@ The scores given by each function are combined using the `score_mode` parameter,
- `max`: The maximum score is taken.
- `min`: The minimum score is taken.
+If a document matches none of the function filters, the function score remains at the neutral value `1` (for `multiply`, `sum`, `avg`, `max`, and `min`). For `first`, no function score is applied and the factor also remains `1`.
+
### Specifying an upper limit for a score
You can specify an upper limit for a function score in the `max_boost` parameter. The default upper limit is the maximum magnitude for a `float` value: (2 − 2−23) · 2127.
@@ -701,10 +767,34 @@ You can specify how the score computed using all functions is combined with the
- `max`: Take the greater of the query score and the function score.
- `min`: Take the lesser of the query score and the function score.
+With default settings (`boost_mode: multiply`, implicit `match_all` query), documents that match no functions typically receive `_score: 1`.
+
### Filtering documents that don't meet a threshold
Changing the relevance score does not change the list of matching documents. To exclude some documents that don't meet a threshold, specify the threshold value in the `min_score` parameter. All documents returned by the query are then scored and filtered using the threshold value.
+`min_score` filters by score after scoring; it does not replace function filters as inclusion criteria.
+
+To return only documents that match at least one function filter, use a `bool` query:
+
+```json
+GET books/_search
+{
+ "query": {
+ "bool": {
+ "should": [
+ { "term": { "genre": "detective" } },
+ { "term": { "author": "Conan Doyle" } }
+ ],
+ "minimum_should_match": 1
+ }
+ }
+}
+```
+{% include copy-curl.html %}
+
+To re-rank those documents by filter weights, nest `function_score` inside the `bool` query or use the `bool` query as the top-level `query` inside `function_score`.
+
### Example
The following request searches for blog posts that include the words "OpenSearch Data Prepper", preferring the posts published around 04/24/2022. Additionally, the number of views and likes are taken into consideration. Finally, the cutoff threshold is set at the score of 10:
@@ -880,7 +970,7 @@ GET blogs/_search
```
{% include copy-curl.html %}
-The response explains the scoring process. For each function, the explanation contains the function `_name` in its `description`:
+The response explains the scoring process. For each function, the explanation contains the function `_name` in its `description`. The `*:*` entry with value `1` is the implicit `match_all` query score when no top-level `query` is specified.