private SearchSourceBuilder parseXContent()

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;
    }