如何在Elasticsearch中仅返回Should查询的最高分记录
Got it, let's tackle this problem. You want to return only the highest-scoring documents from your bool/should query without using any must clauses—here are a couple of solid approaches:
Method 1: Two-Step Query (Simple & Direct)
First, run your original query to grab the max_score value (you can set size: 0 to skip returning hits, since we only need the max score):
GET testindex1/_search { "query": { "bool": { "should": [ { "query_string": { "default_field": "name", "query": "xyz", "default_operator": "AND" } }, { "query_string": { "default_field": "description", "query": "*", "default_operator": "AND" } }, { "query_string": { "default_field": "place", "query": "*", "default_operator": "AND" } } ] } }, "size": 0 }
This will return the max_score (in your case, 2.287682) in the response.
Then, run a second query using a post_filter with a script to only keep documents where the score matches the max score:
GET testindex1/_search { "query": { "bool": { "should": [ { "query_string": { "default_field": "name", "query": "xyz", "default_operator": "AND" } }, { "query_string": { "default_field": "description", "query": "*", "default_operator": "AND" } }, { "query_string": { "default_field": "place", "query": "*", "default_operator": "AND" } } ] } }, "post_filter": { "script": { "source": "_score == params.max_score", "params": { "max_score": 2.287682 } } } }
This will return only the documents with the highest score, and we didn't use any must clauses—perfect for your requirement.
Method 2: Single Query with Aggregations (App Layer Filtering)
If you prefer a single round trip to Elasticsearch, use a top_hits aggregation to fetch all matching documents sorted by score, then filter for the highest-scoring entries in your application code:
GET testindex1/_search { "query": { "bool": { "should": [ { "query_string": { "default_field": "name", "query": "xyz", "default_operator": "AND" } }, { "query_string": { "default_field": "description", "query": "*", "default_operator": "AND" } }, { "query_string": { "default_field": "place", "query": "*", "default_operator": "AND" } } ] } }, "aggs": { "top_matching_docs": { "top_hits": { "sort": [{"_score": "desc"}], "size": 10000 // Set this to a value larger than your total matching docs } } }, "size": 0 // Skip the default hits array, we'll use the aggregation results }
In your app, take the first document's _score from aggregations.top_matching_docs.hits.hits as the maximum score, then filter the rest of the hits to keep only those with that score.
Notes
- For Method 1, make sure dynamic scripting is enabled in Elasticsearch (it's allowed by default unless you've modified security settings).
- For Method 2, set
sizein thetop_hitsaggregation to a number that's guaranteed to cover all matching documents in your index to avoid missing any high-scoring entries.
内容的提问来源于stack exchange,提问作者G2K

