@Override
    public Mapper.Builder<?, ?> parse(
        String name, Map<String, Object> node, ParserContext parserContext)
        throws MapperParsingException {
      CompletionFieldMapper.Builder builder = new CompletionFieldMapper.Builder(name);
      for (Map.Entry<String, Object> entry : node.entrySet()) {
        String fieldName = entry.getKey();
        Object fieldNode = entry.getValue();
        if (fieldName.equals("type")) {
          continue;
        }
        if (fieldName.equals("analyzer")) {
          builder.indexAnalyzer(parserContext.analysisService().analyzer(fieldNode.toString()));
          builder.searchAnalyzer(parserContext.analysisService().analyzer(fieldNode.toString()));
        } else if (fieldName.equals(Fields.INDEX_ANALYZER) || fieldName.equals("indexAnalyzer")) {
          builder.indexAnalyzer(parserContext.analysisService().analyzer(fieldNode.toString()));
        } else if (fieldName.equals(Fields.SEARCH_ANALYZER) || fieldName.equals("searchAnalyzer")) {
          builder.searchAnalyzer(parserContext.analysisService().analyzer(fieldNode.toString()));
        } else if (fieldName.equals(Fields.PAYLOADS)) {
          builder.payloads(Boolean.parseBoolean(fieldNode.toString()));
        } else if (fieldName.equals(Fields.PRESERVE_SEPARATORS)
            || fieldName.equals("preserveSeparators")) {
          builder.preserveSeparators(Boolean.parseBoolean(fieldNode.toString()));
        } else if (fieldName.equals(Fields.PRESERVE_POSITION_INCREMENTS)
            || fieldName.equals("preservePositionIncrements")) {
          builder.preservePositionIncrements(Boolean.parseBoolean(fieldNode.toString()));
        }
      }

      if (builder.searchAnalyzer == null) {
        builder.searchAnalyzer(parserContext.analysisService().analyzer("simple"));
      }

      if (builder.indexAnalyzer == null) {
        builder.indexAnalyzer(parserContext.analysisService().analyzer("simple"));
      }
      // we are just using this as the default to be wrapped by the CompletionPostingsFormatProvider
      // in the SuggesteFieldMapper ctor
      builder.postingsFormat(parserContext.postingFormatService().get("default"));
      return builder;
    }
    @Override
    public Mapper.Builder<?, ?> parse(
        String name, Map<String, Object> node, ParserContext parserContext)
        throws MapperParsingException {
      CompletionFieldMapper.Builder builder = completionField(name);
      NamedAnalyzer indexAnalyzer = null;
      NamedAnalyzer searchAnalyzer = null;
      for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator();
          iterator.hasNext(); ) {
        Map.Entry<String, Object> entry = iterator.next();
        String fieldName = entry.getKey();
        Object fieldNode = entry.getValue();
        if (fieldName.equals("type")) {
          continue;
        }
        if (Fields.ANALYZER.equals(fieldName)
            || // index_analyzer is for backcompat, remove for v3.0
            fieldName.equals("index_analyzer")
                && parserContext.indexVersionCreated().before(Version.V_2_0_0)) {

          indexAnalyzer = getNamedAnalyzer(parserContext, fieldNode.toString());
          iterator.remove();
        } else if (parserContext.parseFieldMatcher().match(fieldName, Fields.SEARCH_ANALYZER)) {
          searchAnalyzer = getNamedAnalyzer(parserContext, fieldNode.toString());
          iterator.remove();
        } else if (fieldName.equals(Fields.PAYLOADS)) {
          builder.payloads(Boolean.parseBoolean(fieldNode.toString()));
          iterator.remove();
        } else if (parserContext.parseFieldMatcher().match(fieldName, Fields.PRESERVE_SEPARATORS)) {
          builder.preserveSeparators(Boolean.parseBoolean(fieldNode.toString()));
          iterator.remove();
        } else if (parserContext
            .parseFieldMatcher()
            .match(fieldName, Fields.PRESERVE_POSITION_INCREMENTS)) {
          builder.preservePositionIncrements(Boolean.parseBoolean(fieldNode.toString()));
          iterator.remove();
        } else if (parserContext.parseFieldMatcher().match(fieldName, Fields.MAX_INPUT_LENGTH)) {
          builder.maxInputLength(Integer.parseInt(fieldNode.toString()));
          iterator.remove();
        } else if (parseMultiField(builder, name, parserContext, fieldName, fieldNode)) {
          iterator.remove();
        } else if (fieldName.equals(Fields.CONTEXT)) {
          builder.contextMapping(
              ContextBuilder.loadMappings(fieldNode, parserContext.indexVersionCreated()));
          iterator.remove();
        }
      }

      if (indexAnalyzer == null) {
        if (searchAnalyzer != null) {
          throw new MapperParsingException(
              "analyzer on completion field ["
                  + name
                  + "] must be set when search_analyzer is set");
        }
        indexAnalyzer = searchAnalyzer = parserContext.analysisService().analyzer("simple");
      } else if (searchAnalyzer == null) {
        searchAnalyzer = indexAnalyzer;
      }
      builder.indexAnalyzer(indexAnalyzer);
      builder.searchAnalyzer(searchAnalyzer);

      return builder;
    }
    @Override
    public Mapper.Builder<?, ?> parse(
        String name, Map<String, Object> node, ParserContext parserContext)
        throws MapperParsingException {
      CompletionFieldMapper.Builder builder = completionField(name);
      for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator();
          iterator.hasNext(); ) {
        Map.Entry<String, Object> entry = iterator.next();
        String fieldName = entry.getKey();
        Object fieldNode = entry.getValue();
        if (fieldName.equals("type")) {
          continue;
        }
        if (fieldName.equals("analyzer")) {
          NamedAnalyzer analyzer = getNamedAnalyzer(parserContext, fieldNode.toString());
          builder.indexAnalyzer(analyzer);
          builder.searchAnalyzer(analyzer);
          iterator.remove();
        } else if (Fields.INDEX_ANALYZER.match(fieldName)) {
          builder.indexAnalyzer(getNamedAnalyzer(parserContext, fieldNode.toString()));
          iterator.remove();
        } else if (Fields.SEARCH_ANALYZER.match(fieldName)) {
          builder.searchAnalyzer(getNamedAnalyzer(parserContext, fieldNode.toString()));
          iterator.remove();
        } else if (fieldName.equals(Fields.PAYLOADS)) {
          builder.payloads(Boolean.parseBoolean(fieldNode.toString()));
          iterator.remove();
        } else if (Fields.PRESERVE_SEPARATORS.match(fieldName)) {
          builder.preserveSeparators(Boolean.parseBoolean(fieldNode.toString()));
          iterator.remove();
        } else if (Fields.PRESERVE_POSITION_INCREMENTS.match(fieldName)) {
          builder.preservePositionIncrements(Boolean.parseBoolean(fieldNode.toString()));
          iterator.remove();
        } else if (Fields.MAX_INPUT_LENGTH.match(fieldName)) {
          builder.maxInputLength(Integer.parseInt(fieldNode.toString()));
          iterator.remove();
        } else if ("fields".equals(fieldName) || "path".equals(fieldName)) {
          if (parseMultiField(builder, name, parserContext, fieldName, fieldNode)) {
            iterator.remove();
          }
        } else if (fieldName.equals(Fields.CONTEXT)) {
          builder.contextMapping(
              ContextBuilder.loadMappings(fieldNode, parserContext.indexVersionCreated()));
          iterator.remove();
        }
      }

      if (builder.searchAnalyzer == null) {
        builder.searchAnalyzer(parserContext.analysisService().analyzer("simple"));
      }

      if (builder.indexAnalyzer == null) {
        builder.indexAnalyzer(parserContext.analysisService().analyzer("simple"));
      }
      // we are just using this as the default to be wrapped by the CompletionPostingsFormatProvider
      // in the SuggesteFieldMapper ctor
      builder.postingsFormat(parserContext.postingFormatService().get("default"));
      return builder;
    }