in server/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java [1327:1659]
private SearchSourceBuilder parseXContent(
XContentParser parser,
boolean checkTrailingTokens,
Consumer<SearchUsage> searchUsageConsumer,
Predicate<NodeFeature> clusterSupportsFeature
) throws IOException {
XContentParser.Token token = parser.currentToken();
String currentFieldName = null;
if (token != XContentParser.Token.START_OBJECT && (token = parser.nextToken()) != XContentParser.Token.START_OBJECT) {
throw new ParsingException(
parser.getTokenLocation(),
"Expected [" + XContentParser.Token.START_OBJECT + "] but found [" + token + "]",
parser.getTokenLocation()
);
}
List<KnnSearchBuilder.Builder> knnBuilders = new ArrayList<>();
SearchUsage searchUsage = new SearchUsage();
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token.isValue()) {
if (FROM_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
from(parser.intValue());
} else if (SIZE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
size(parser.intValue());
} else if (TIMEOUT_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
timeout = TimeValue.parseTimeValue(parser.text(), null, TIMEOUT_FIELD.getPreferredName());
} else if (TERMINATE_AFTER_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
terminateAfter(parser.intValue());
searchUsage.trackSectionUsage(TERMINATE_AFTER_FIELD.getPreferredName());
} else if (MIN_SCORE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
minScore = parser.floatValue();
searchUsage.trackSectionUsage(MIN_SCORE_FIELD.getPreferredName());
} else if (VERSION_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
version = parser.booleanValue();
} else if (SEQ_NO_PRIMARY_TERM_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
seqNoAndPrimaryTerm = parser.booleanValue();
} else if (EXPLAIN_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
explain = parser.booleanValue();
} else if (TRACK_SCORES_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
trackScores = parser.booleanValue();
} else if (TRACK_TOTAL_HITS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
if (token == XContentParser.Token.VALUE_BOOLEAN
|| (token == XContentParser.Token.VALUE_STRING && Booleans.isBoolean(parser.text()))) {
trackTotalHits(parser.booleanValue());
} else {
trackTotalHitsUpTo(parser.intValue());
}
} else if (_SOURCE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
fetchSourceContext = FetchSourceContext.fromXContent(parser);
if (fetchSourceContext.includes().length > 0 || fetchSourceContext.fetchSource() == false) {
searchUsage.trackSectionUsage(_SOURCE_FIELD.getPreferredName());
}
} else if (STORED_FIELDS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
storedFieldsContext = StoredFieldsContext.fromXContent(
SearchSourceBuilder.STORED_FIELDS_FIELD.getPreferredName(),
parser
);
if (storedFieldsContext.fetchFields() == false
|| (storedFieldsContext.fieldNames() != null && storedFieldsContext.fieldNames().size() > 0)) {
searchUsage.trackSectionUsage(STORED_FIELDS_FIELD.getPreferredName());
}
} else if (SORT_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
sort(parser.text());
} else if (PROFILE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
profile = parser.booleanValue();
} else {
throw new ParsingException(
parser.getTokenLocation(),
"Unknown key for a " + token + " in [" + currentFieldName + "].",
parser.getTokenLocation()
);
}
} else if (token == XContentParser.Token.START_OBJECT) {
if (RETRIEVER.match(currentFieldName, parser.getDeprecationHandler())) {
retrieverBuilder = RetrieverBuilder.parseTopLevelRetrieverBuilder(
parser,
new RetrieverParserContext(searchUsage, clusterSupportsFeature)
);
searchUsage.trackSectionUsage(RETRIEVER.getPreferredName());
} else if (QUERY_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
if (subSearchSourceBuilders.isEmpty() == false) {
throw new IllegalArgumentException(
"cannot specify field [" + currentFieldName + "] and field [" + SUB_SEARCHES_FIELD.getPreferredName() + "]"
);
}
QueryBuilder queryBuilder = parseTopLevelQuery(parser, searchUsage::trackQueryUsage);
subSearchSourceBuilders.add(new SubSearchSourceBuilder(queryBuilder));
searchUsage.trackSectionUsage(QUERY_FIELD.getPreferredName());
} else if (POST_FILTER_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
postQueryBuilder = parseTopLevelQuery(parser, searchUsage::trackQueryUsage);
searchUsage.trackSectionUsage(POST_FILTER_FIELD.getPreferredName());
} else if (KNN_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
knnBuilders = List.of(KnnSearchBuilder.fromXContent(parser));
searchUsage.trackSectionUsage(KNN_FIELD.getPreferredName());
} else if (RANK_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
if (RANK_SUPPORTED == false) {
throwUnknownKey(parser, token, currentFieldName);
}
if (parser.nextToken() != XContentParser.Token.FIELD_NAME) {
throw new ParsingException(
parser.getTokenLocation(),
"expected a rank name, but found token [" + token + "] for [" + RANK_FIELD.getPreferredName() + "]"
);
}
rankBuilder = parser.namedObject(RankBuilder.class, parser.currentName(), null);
if (parser.currentToken() != XContentParser.Token.END_OBJECT) {
throw new ParsingException(
parser.getTokenLocation(),
"expected token '}', but found token [" + token + "] for [" + RANK_FIELD.getPreferredName() + "]"
);
}
parser.nextToken();
searchUsage.trackSectionUsage("rank_" + rankBuilder.getWriteableName());
} else if (_SOURCE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
fetchSourceContext = FetchSourceContext.fromXContent(parser);
if (fetchSourceContext.fetchSource() == false
|| fetchSourceContext.includes().length > 0
|| fetchSourceContext.excludes().length > 0) {
searchUsage.trackSectionUsage(_SOURCE_FIELD.getPreferredName());
}
} else if (SCRIPT_FIELDS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
scriptFields = new ArrayList<>();
while ((parser.nextToken()) != XContentParser.Token.END_OBJECT) {
scriptFields.add(new ScriptField(parser));
}
searchUsage.trackSectionUsage(SCRIPT_FIELDS_FIELD.getPreferredName());
} else if (AGGREGATIONS_FIELD.match(currentFieldName, parser.getDeprecationHandler())
|| AGGS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
aggregations = AggregatorFactories.parseAggregators(parser);
if (aggregations.count() > 0) {
searchUsage.trackSectionUsage(AGGS_FIELD.getPreferredName());
}
} else if (HIGHLIGHT_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
highlightBuilder = HighlightBuilder.fromXContent(parser);
if (highlightBuilder.fields().size() > 0) {
searchUsage.trackSectionUsage(HIGHLIGHT_FIELD.getPreferredName());
}
} else if (SUGGEST_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
suggestBuilder = SuggestBuilder.fromXContent(parser);
if (suggestBuilder.getSuggestions().size() > 0) {
searchUsage.trackSectionUsage(SUGGEST_FIELD.getPreferredName());
}
} else if (SORT_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
sorts = new ArrayList<>(SortBuilder.fromXContent(parser));
} else if (RESCORE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
rescoreBuilders = new ArrayList<>();
rescoreBuilders.add(RescorerBuilder.parseFromXContent(parser, searchUsage::trackRescorerUsage));
searchUsage.trackSectionUsage(RESCORE_FIELD.getPreferredName());
} else if (EXT_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
extBuilders = new ArrayList<>();
String extSectionName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
extSectionName = parser.currentName();
} else {
SearchExtBuilder searchExtBuilder = parser.namedObject(SearchExtBuilder.class, extSectionName, null);
if (searchExtBuilder.getWriteableName().equals(extSectionName) == false) {
throw new IllegalStateException(
"The parsed ["
+ searchExtBuilder.getClass().getName()
+ "] object has a different writeable name compared to the name of the section that "
+ " it was parsed from: found ["
+ searchExtBuilder.getWriteableName()
+ "] expected ["
+ extSectionName
+ "]"
);
}
extBuilders.add(searchExtBuilder);
}
}
if (extBuilders.size() > 0) {
searchUsage.trackSectionUsage(EXT_FIELD.getPreferredName());
}
} else if (SLICE.match(currentFieldName, parser.getDeprecationHandler())) {
sliceBuilder = SliceBuilder.fromXContent(parser);
if (sliceBuilder.getField() != null || sliceBuilder.getId() != -1 || sliceBuilder.getMax() != -1) {
searchUsage.trackSectionUsage(SLICE.getPreferredName());
}
} else if (COLLAPSE.match(currentFieldName, parser.getDeprecationHandler())) {
collapse = CollapseBuilder.fromXContent(parser);
if (collapse.getField() != null) {
searchUsage.trackSectionUsage(COLLAPSE.getPreferredName());
}
} else if (POINT_IN_TIME.match(currentFieldName, parser.getDeprecationHandler())) {
pointInTimeBuilder = PointInTimeBuilder.fromXContent(parser);
searchUsage.trackSectionUsage(POINT_IN_TIME.getPreferredName());
} else if (RUNTIME_MAPPINGS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
runtimeMappings = parser.map();
if (runtimeMappings.size() > 0) {
searchUsage.trackSectionUsage(RUNTIME_MAPPINGS_FIELD.getPreferredName());
}
} else {
throw new ParsingException(
parser.getTokenLocation(),
"Unknown key for a " + token + " in [" + currentFieldName + "].",
parser.getTokenLocation()
);
}
} else if (token == XContentParser.Token.START_ARRAY) {
if (STORED_FIELDS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
storedFieldsContext = StoredFieldsContext.fromXContent(STORED_FIELDS_FIELD.getPreferredName(), parser);
if (storedFieldsContext.fetchFields() == false
|| (storedFieldsContext.fieldNames() != null && storedFieldsContext.fieldNames().size() > 0)) {
searchUsage.trackSectionUsage(STORED_FIELDS_FIELD.getPreferredName());
}
} else if (DOCVALUE_FIELDS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
docValueFields = new ArrayList<>();
while ((parser.nextToken()) != XContentParser.Token.END_ARRAY) {
docValueFields.add(FieldAndFormat.fromXContent(parser));
}
if (docValueFields.size() > 0) {
searchUsage.trackSectionUsage(DOCVALUE_FIELDS_FIELD.getPreferredName());
}
} else if (FETCH_FIELDS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
fetchFields = new ArrayList<>();
while ((parser.nextToken()) != XContentParser.Token.END_ARRAY) {
fetchFields.add(FieldAndFormat.fromXContent(parser));
}
if (fetchFields.size() > 0) {
searchUsage.trackSectionUsage(FETCH_FIELDS_FIELD.getPreferredName());
}
} else if (INDICES_BOOST_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
while ((parser.nextToken()) != XContentParser.Token.END_ARRAY) {
indexBoosts.add(new IndexBoost(parser));
}
if (indexBoosts.size() > 0) {
searchUsage.trackSectionUsage(INDICES_BOOST_FIELD.getPreferredName());
}
} else if (SORT_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
sorts = new ArrayList<>(SortBuilder.fromXContent(parser));
} else if (RESCORE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
rescoreBuilders = new ArrayList<>();
while ((parser.nextToken()) != XContentParser.Token.END_ARRAY) {
rescoreBuilders.add(RescorerBuilder.parseFromXContent(parser, searchUsage::trackRescorerUsage));
}
searchUsage.trackSectionUsage(RESCORE_FIELD.getPreferredName());
} else if (STATS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
stats = new ArrayList<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token == XContentParser.Token.VALUE_STRING) {
stats.add(parser.text());
} else {
throw new ParsingException(
parser.getTokenLocation(),
"Expected ["
+ XContentParser.Token.VALUE_STRING
+ "] in ["
+ currentFieldName
+ "] but found ["
+ token
+ "]",
parser.getTokenLocation()
);
}
}
if (stats.size() > 0) {
searchUsage.trackSectionUsage(STATS_FIELD.getPreferredName());
}
} else if (_SOURCE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
fetchSourceContext = FetchSourceContext.fromXContent(parser);
if (fetchSourceContext.fetchSource() == false
|| fetchSourceContext.includes().length > 0
|| fetchSourceContext.excludes().length > 0) {
searchUsage.trackSectionUsage(_SOURCE_FIELD.getPreferredName());
}
} else if (SEARCH_AFTER.match(currentFieldName, parser.getDeprecationHandler())) {
searchAfterBuilder = SearchAfterBuilder.fromXContent(parser);
searchUsage.trackSectionUsage(SEARCH_AFTER.getPreferredName());
} else if (KNN_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token == XContentParser.Token.START_OBJECT) {
knnBuilders.add(KnnSearchBuilder.fromXContent(parser));
} else {
throw new XContentParseException(
parser.getTokenLocation(),
"malformed knn format, within the knn search array only objects are allowed; found " + token
);
}
}
searchUsage.trackSectionUsage(KNN_FIELD.getPreferredName());
} else if (SUB_SEARCHES_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
if (RANK_SUPPORTED == false) {
throwUnknownKey(parser, token, currentFieldName);
}
if (subSearchSourceBuilders.isEmpty() == false) {
throw new IllegalArgumentException(
"cannot specify field [" + currentFieldName + "] and field [" + QUERY_FIELD.getPreferredName() + "]"
);
}
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token == XContentParser.Token.START_OBJECT) {
subSearchSourceBuilders.add(SubSearchSourceBuilder.fromXContent(parser, searchUsage));
} else {
throw new XContentParseException(
parser.getTokenLocation(),
"malformed query within the [sub_searches] field; found " + token
);
}
}
searchUsage.trackSectionUsage(SUB_SEARCHES_FIELD.getPreferredName());
} else {
throwUnknownKey(parser, token, currentFieldName);
}
} else {
throwUnknownKey(parser, token, currentFieldName);
}
}
if (checkTrailingTokens) {
token = parser.nextToken();
if (token != null) {
throw new ParsingException(parser.getTokenLocation(), "Unexpected token [" + token + "] found after the main object.");
}
}
knnSearch = knnBuilders.stream().map(knnBuilder -> knnBuilder.build(size())).collect(Collectors.toList());
if (rankBuilder != null) {
if (retrieverBuilder != null) {
throw new IllegalArgumentException("Cannot specify both [rank] and [retriever].");
}
RetrieverBuilder transformedRetriever = rankBuilder.toRetriever(this, clusterSupportsFeature);
if (transformedRetriever != null) {
this.retriever(transformedRetriever);
rankBuilder = null;
subSearchSourceBuilders.clear();
knnSearch.clear();
}
}
searchUsageConsumer.accept(searchUsage);
return this;
}