public static IncludeExclude parseInclude(XContentParser parser, QueryParseContext context)
     throws IOException {
   XContentParser.Token token = parser.currentToken();
   if (token == XContentParser.Token.VALUE_STRING) {
     return new IncludeExclude(parser.text(), null);
   } else if (token == XContentParser.Token.START_ARRAY) {
     return new IncludeExclude(new TreeSet<>(parseArrayToSet(parser)), null);
   } else if (token == XContentParser.Token.START_OBJECT) {
     ParseFieldMatcher parseFieldMatcher = context.getParseFieldMatcher();
     String currentFieldName = null;
     Integer partition = null, numPartitions = null;
     while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
       if (token == XContentParser.Token.FIELD_NAME) {
         currentFieldName = parser.currentName();
       } else
       // This "include":{"pattern":"foo.*"} syntax is undocumented since 2.0
       // Regexes should be "include":"foo.*"
       if (parseFieldMatcher.match(currentFieldName, PATTERN_FIELD)) {
         return new IncludeExclude(parser.text(), null);
       } else if (parseFieldMatcher.match(currentFieldName, NUM_PARTITIONS_FIELD)) {
         numPartitions = parser.intValue();
       } else if (parseFieldMatcher.match(currentFieldName, PARTITION_FIELD)) {
         partition = parser.intValue();
       } else {
         throw new ElasticsearchParseException(
             "Unknown parameter in Include/Exclude clause: " + currentFieldName);
       }
     }
     if (partition == null) {
       throw new IllegalArgumentException(
           "Missing ["
               + PARTITION_FIELD.getPreferredName()
               + "] parameter for partition-based include");
     }
     if (numPartitions == null) {
       throw new IllegalArgumentException(
           "Missing ["
               + NUM_PARTITIONS_FIELD.getPreferredName()
               + "] parameter for partition-based include");
     }
     return new IncludeExclude(partition, numPartitions);
   } else {
     throw new IllegalArgumentException("Unrecognized token for an include [" + token + "]");
   }
 }
 public static ExecutionMode fromString(String value, ParseFieldMatcher parseFieldMatcher) {
   for (ExecutionMode mode : values()) {
     if (parseFieldMatcher.match(value, mode.parseField)) {
       return mode;
     }
   }
   throw new IllegalArgumentException(
       "Unknown `execution_hint`: [" + value + "], expected any of " + values());
 }
  static TermSuggestionBuilder innerFromXContent(QueryParseContext parseContext)
      throws IOException {
    XContentParser parser = parseContext.parser();
    TermSuggestionBuilder tmpSuggestion = new TermSuggestionBuilder("_na_");
    ParseFieldMatcher parseFieldMatcher = parseContext.getParseFieldMatcher();
    XContentParser.Token token;
    String currentFieldName = null;
    String fieldname = null;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token.isValue()) {
        if (parseFieldMatcher.match(currentFieldName, SuggestionBuilder.ANALYZER_FIELD)) {
          tmpSuggestion.analyzer(parser.text());
        } else if (parseFieldMatcher.match(currentFieldName, SuggestionBuilder.FIELDNAME_FIELD)) {
          fieldname = parser.text();
        } else if (parseFieldMatcher.match(currentFieldName, SuggestionBuilder.SIZE_FIELD)) {
          tmpSuggestion.size(parser.intValue());
        } else if (parseFieldMatcher.match(currentFieldName, SuggestionBuilder.SHARDSIZE_FIELD)) {
          tmpSuggestion.shardSize(parser.intValue());
        } else if (parseFieldMatcher.match(currentFieldName, SUGGESTMODE_FIELD)) {
          tmpSuggestion.suggestMode(SuggestMode.resolve(parser.text()));
        } else if (parseFieldMatcher.match(currentFieldName, ACCURACY_FIELD)) {
          tmpSuggestion.accuracy(parser.floatValue());
        } else if (parseFieldMatcher.match(currentFieldName, SORT_FIELD)) {
          tmpSuggestion.sort(SortBy.resolve(parser.text()));
        } else if (parseFieldMatcher.match(currentFieldName, STRING_DISTANCE_FIELD)) {
          tmpSuggestion.stringDistance(StringDistanceImpl.resolve(parser.text()));
        } else if (parseFieldMatcher.match(currentFieldName, MAX_EDITS_FIELD)) {
          tmpSuggestion.maxEdits(parser.intValue());
        } else if (parseFieldMatcher.match(currentFieldName, MAX_INSPECTIONS_FIELD)) {
          tmpSuggestion.maxInspections(parser.intValue());
        } else if (parseFieldMatcher.match(currentFieldName, MAX_TERM_FREQ_FIELD)) {
          tmpSuggestion.maxTermFreq(parser.floatValue());
        } else if (parseFieldMatcher.match(currentFieldName, PREFIX_LENGTH_FIELD)) {
          tmpSuggestion.prefixLength(parser.intValue());
        } else if (parseFieldMatcher.match(currentFieldName, MIN_WORD_LENGTH_FIELD)) {
          tmpSuggestion.minWordLength(parser.intValue());
        } else if (parseFieldMatcher.match(currentFieldName, MIN_DOC_FREQ_FIELD)) {
          tmpSuggestion.minDocFreq(parser.floatValue());
        } else if (parseFieldMatcher.match(currentFieldName, EXACT_MATCH_FIELD)) {
          tmpSuggestion.exactMatch(parser.booleanValue());
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "suggester[term] doesn't support field [" + currentFieldName + "]");
        }
      } else {
        throw new ParsingException(
            parser.getTokenLocation(),
            "suggester[term] parsing failed on [" + currentFieldName + "]");
      }
    }

    // now we should have field name, check and copy fields over to the suggestion builder we return
    if (fieldname == null) {
      throw new ElasticsearchParseException(
          "the required field option [" + FIELDNAME_FIELD.getPreferredName() + "] is missing");
    }
    return new TermSuggestionBuilder(fieldname, tmpSuggestion);
  }
  @Override
  public final MultiValuesSourceAggregationBuilder<VS, ?> parse(
      String aggregationName, QueryParseContext context) throws IOException {

    XContentParser parser = context.parser();
    List<String> fields = null;
    ValueType valueType = null;
    String format = null;
    Map<String, Object> missingMap = null;
    Map<ParseField, Object> otherOptions = new HashMap<>();
    final ParseFieldMatcher parseFieldMatcher = context.getParseFieldMatcher();

    XContentParser.Token token;
    String currentFieldName = null;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.VALUE_STRING) {
        if (parseFieldMatcher.match(currentFieldName, CommonFields.FIELDS)) {
          fields = Collections.singletonList(parser.text());
        } else if (formattable && parseFieldMatcher.match(currentFieldName, CommonFields.FORMAT)) {
          format = parser.text();
        } else if (parseFieldMatcher.match(currentFieldName, CommonFields.VALUE_TYPE)) {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unexpected token "
                  + token
                  + " ["
                  + currentFieldName
                  + "] in ["
                  + aggregationName
                  + "]. "
                  + "Multi-field aggregations do not support scripts.");
        } else if (!token(
            aggregationName,
            currentFieldName,
            token,
            parser,
            context.getParseFieldMatcher(),
            otherOptions)) {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unexpected token "
                  + token
                  + " ["
                  + currentFieldName
                  + "] in ["
                  + aggregationName
                  + "].");
        }
      } else if (token == XContentParser.Token.START_OBJECT) {
        if (parseFieldMatcher.match(currentFieldName, CommonFields.MISSING)) {
          missingMap = new HashMap<>();
          while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
            parseMissingAndAdd(aggregationName, currentFieldName, parser, missingMap);
          }
        } else if (context.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unexpected token "
                  + token
                  + " ["
                  + currentFieldName
                  + "] in ["
                  + aggregationName
                  + "]. "
                  + "Multi-field aggregations do not support scripts.");

        } else if (!token(
            aggregationName,
            currentFieldName,
            token,
            parser,
            context.getParseFieldMatcher(),
            otherOptions)) {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unexpected token "
                  + token
                  + " ["
                  + currentFieldName
                  + "] in ["
                  + aggregationName
                  + "].");
        }
      } else if (token == XContentParser.Token.START_ARRAY) {
        if (context.getParseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unexpected token "
                  + token
                  + " ["
                  + currentFieldName
                  + "] in ["
                  + aggregationName
                  + "]. "
                  + "Multi-field aggregations do not support scripts.");
        } else if (parseFieldMatcher.match(currentFieldName, CommonFields.FIELDS)) {
          fields = new ArrayList<>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            if (token == XContentParser.Token.VALUE_STRING) {
              fields.add(parser.text());
            } else {
              throw new ParsingException(
                  parser.getTokenLocation(),
                  "Unexpected token "
                      + token
                      + " ["
                      + currentFieldName
                      + "] in ["
                      + aggregationName
                      + "].");
            }
          }
        } else if (!token(
            aggregationName,
            currentFieldName,
            token,
            parser,
            context.getParseFieldMatcher(),
            otherOptions)) {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unexpected token "
                  + token
                  + " ["
                  + currentFieldName
                  + "] in ["
                  + aggregationName
                  + "].");
        }
      } else if (!token(
          aggregationName,
          currentFieldName,
          token,
          parser,
          context.getParseFieldMatcher(),
          otherOptions)) {
        throw new ParsingException(
            parser.getTokenLocation(),
            "Unexpected token "
                + token
                + " ["
                + currentFieldName
                + "] in ["
                + aggregationName
                + "].");
      }
    }

    MultiValuesSourceAggregationBuilder<VS, ?> factory =
        createFactory(aggregationName, this.valuesSourceType, this.targetValueType, otherOptions);
    if (fields != null) {
      factory.fields(fields);
    }
    if (valueType != null) {
      factory.valueType(valueType);
    }
    if (format != null) {
      factory.format(format);
    }
    if (missingMap != null) {
      factory.missingMap(missingMap);
    }
    return factory;
  }