Fix inaccurate total hit count in _search template api (#53155)

When 'rest_track_total_hits_as_int' is set to true, the total hits count in the response should be accurate. So we should set trackTotalHits to true if need when parsing the inline script of a search template request.

Closes #52801
This commit is contained in:
bellengao 2020-03-13 22:35:02 +08:00 committed by jimczi
parent 3b9545848f
commit e2effa9fab
4 changed files with 42 additions and 1 deletions

View File

@ -77,7 +77,6 @@ public class RestSearchTemplateAction extends BaseRestHandler {
searchTemplateRequest = SearchTemplateRequest.fromXContent(parser); searchTemplateRequest = SearchTemplateRequest.fromXContent(parser);
} }
searchTemplateRequest.setRequest(searchRequest); searchTemplateRequest.setRequest(searchRequest);
RestSearchAction.checkRestTotalHits(request, searchRequest);
return channel -> client.execute(SearchTemplateAction.INSTANCE, searchTemplateRequest, new RestStatusToXContentListener<>(channel)); return channel -> client.execute(SearchTemplateAction.INSTANCE, searchTemplateRequest, new RestStatusToXContentListener<>(channel));
} }

View File

@ -32,11 +32,13 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptType; import org.elasticsearch.script.ScriptType;
import org.elasticsearch.script.TemplateScript; import org.elasticsearch.script.TemplateScript;
import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.Task;
import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.TransportService;
@ -110,8 +112,27 @@ public class TransportSearchTemplateAction extends HandledTransportAction<Search
builder.parseXContent(parser, false); builder.parseXContent(parser, false);
builder.explain(searchTemplateRequest.isExplain()); builder.explain(searchTemplateRequest.isExplain());
builder.profile(searchTemplateRequest.isProfile()); builder.profile(searchTemplateRequest.isProfile());
checkRestTotalHitsAsInt(searchRequest, builder);
searchRequest.source(builder); searchRequest.source(builder);
} }
return searchRequest; return searchRequest;
} }
private static void checkRestTotalHitsAsInt(SearchRequest searchRequest, SearchSourceBuilder searchSourceBuilder) {
if (searchRequest.source() == null) {
searchRequest.source(new SearchSourceBuilder());
}
Integer trackTotalHitsUpTo = searchRequest.source().trackTotalHitsUpTo();
// trackTotalHitsUpTo is set to Integer.MAX_VALUE when `rest_total_hits_as_int` is true
if (trackTotalHitsUpTo != null) {
if (searchSourceBuilder.trackTotalHitsUpTo() == null) {
// trackTotalHitsUpTo should be set here, ensure that we can get an accurate total hits count
searchSourceBuilder.trackTotalHitsUpTo(trackTotalHitsUpTo);
} else if (searchSourceBuilder.trackTotalHitsUpTo() != SearchContext.TRACK_TOTAL_HITS_ACCURATE
&& searchSourceBuilder.trackTotalHitsUpTo() != SearchContext.TRACK_TOTAL_HITS_DISABLED) {
throw new IllegalArgumentException("[" + RestSearchAction.TOTAL_HITS_AS_INT_PARAM + "] cannot be used " +
"if the tracking of total hits is not accurate, got " + searchSourceBuilder.trackTotalHitsUpTo());
}
}
}
} }

View File

@ -40,6 +40,19 @@
- match: { hits.total: 2 } - match: { hits.total: 2 }
---
"Test with invalid track_total_hits":
- do:
catch: bad_request
search_template:
rest_total_hits_as_int: true
body: { "source" : { "query": { "match_{{template}}": {} }, "track_total_hits": "{{trackTotalHits}}" }, "params" : { "template" : "all", "trackTotalHits" : 1 } }
- match: { status: 400 }
- match: { error.type: illegal_argument_exception }
- match: { error.reason: "[rest_total_hits_as_int] cannot be used if the tracking of total hits is not accurate, got 1" }
--- ---
"Missing template search request": "Missing template search request":

View File

@ -94,6 +94,11 @@ setup:
- source: '{"query": {"{{query_type}}": {} }' # Unknown query type - source: '{"query": {"{{query_type}}": {} }' # Unknown query type
params: params:
query_type: "unknown" query_type: "unknown"
# Search 4 has an unsupported track_total_hits
- index: index_*
- source: '{"query": {"match_all": {} }, "track_total_hits": "{{trackTotalHits}}" }'
params:
trackTotalHits: 1
- match: { responses.0.hits.total: 2 } - match: { responses.0.hits.total: 2 }
- match: { responses.1.error.root_cause.0.type: json_e_o_f_exception } - match: { responses.1.error.root_cause.0.type: json_e_o_f_exception }
@ -101,6 +106,9 @@ setup:
- match: { responses.2.hits.total: 1 } - match: { responses.2.hits.total: 1 }
- match: { responses.3.error.root_cause.0.type: parsing_exception } - match: { responses.3.error.root_cause.0.type: parsing_exception }
- match: { responses.3.error.root_cause.0.reason: "/unknown.query.\\[unknown\\]/" } - match: { responses.3.error.root_cause.0.reason: "/unknown.query.\\[unknown\\]/" }
- match: { responses.4.error.root_cause.0.type: illegal_argument_exception }
- match: { responses.4.error.root_cause.0.reason: "[rest_total_hits_as_int] cannot be used if the tracking of total hits is not accurate, got 1" }
--- ---
"Multi-search template with invalid request": "Multi-search template with invalid request":