private void processAnalyzerFactory(
      String name,
      AnalyzerProvider<?> analyzerFactory,
      Map<String, NamedAnalyzer> analyzerAliases,
      Map<String, NamedAnalyzer> analyzers) {
    /*
     * Lucene defaults positionIncrementGap to 0 in all analyzers but
     * Elasticsearch defaults them to 0 only before version 2.0
     * and 100 afterwards so we override the positionIncrementGap if it
     * doesn't match here.
     */
    int overridePositionIncrementGap = TextFieldMapper.Defaults.POSITION_INCREMENT_GAP;
    if (analyzerFactory instanceof CustomAnalyzerProvider) {
      ((CustomAnalyzerProvider) analyzerFactory).build(this);
      /*
       * Custom analyzers already default to the correct, version
       * dependent positionIncrementGap and the user is be able to
       * configure the positionIncrementGap directly on the analyzer so
       * we disable overriding the positionIncrementGap to preserve the
       * user's setting.
       */
      overridePositionIncrementGap = Integer.MIN_VALUE;
    }
    Analyzer analyzerF = analyzerFactory.get();
    if (analyzerF == null) {
      throw new IllegalArgumentException(
          "analyzer [" + analyzerFactory.name() + "] created null analyzer");
    }
    NamedAnalyzer analyzer;
    if (analyzerF instanceof NamedAnalyzer) {
      // if we got a named analyzer back, use it...
      analyzer = (NamedAnalyzer) analyzerF;
      if (overridePositionIncrementGap >= 0
          && analyzer.getPositionIncrementGap(analyzer.name()) != overridePositionIncrementGap) {
        // unless the positionIncrementGap needs to be overridden
        analyzer = new NamedAnalyzer(analyzer, overridePositionIncrementGap);
      }
    } else {
      analyzer =
          new NamedAnalyzer(name, analyzerFactory.scope(), analyzerF, overridePositionIncrementGap);
    }
    if (analyzers.containsKey(name)) {
      throw new IllegalStateException("already registered analyzer with name: " + name);
    }
    analyzers.put(name, analyzer);
    // TODO: remove alias support completely when we no longer support pre 5.0 indices
    final String analyzerAliasKey = "index.analysis.analyzer." + analyzerFactory.name() + ".alias";
    if (indexSettings.getSettings().get(analyzerAliasKey) != null) {
      if (indexSettings.getIndexVersionCreated().onOrAfter(Version.V_5_0_0_alpha6)) {
        // do not allow alias creation if the index was created on or after v5.0 alpha6
        throw new IllegalArgumentException("setting [" + analyzerAliasKey + "] is not supported");
      }

      // the setting is now removed but we only support it for loading indices created before v5.0
      deprecationLogger.deprecated(
          "setting [{}] is only allowed on index [{}] because it was created before 5.x; "
              + "analyzer aliases can no longer be created on new indices.",
          analyzerAliasKey,
          index().getName());
      Set<String> aliases =
          Sets.newHashSet(indexSettings.getSettings().getAsArray(analyzerAliasKey));
      for (String alias : aliases) {
        if (analyzerAliases.putIfAbsent(alias, analyzer) != null) {
          throw new IllegalStateException(
              "alias ["
                  + alias
                  + "] is already used by ["
                  + analyzerAliases.get(alias).name()
                  + "]");
        }
      }
    }
  }
  public AnalysisService(
      IndexSettings indexSettings,
      Map<String, AnalyzerProvider> analyzerProviders,
      Map<String, TokenizerFactory> tokenizerFactoryFactories,
      Map<String, CharFilterFactory> charFilterFactoryFactories,
      Map<String, TokenFilterFactory> tokenFilterFactoryFactories) {
    super(indexSettings);
    this.tokenizers = unmodifiableMap(tokenizerFactoryFactories);
    this.charFilters = unmodifiableMap(charFilterFactoryFactories);
    this.tokenFilters = unmodifiableMap(tokenFilterFactoryFactories);
    analyzerProviders = new HashMap<>(analyzerProviders);

    if (!analyzerProviders.containsKey("default")) {
      analyzerProviders.put(
          "default",
          new StandardAnalyzerProvider(
              indexSettings, null, "default", Settings.Builder.EMPTY_SETTINGS));
    }
    if (!analyzerProviders.containsKey("default_search")) {
      analyzerProviders.put("default_search", analyzerProviders.get("default"));
    }
    if (!analyzerProviders.containsKey("default_search_quoted")) {
      analyzerProviders.put("default_search_quoted", analyzerProviders.get("default_search"));
    }

    Map<String, NamedAnalyzer> analyzers = new HashMap<>();
    for (Map.Entry<String, AnalyzerProvider> entry : analyzerProviders.entrySet()) {
      AnalyzerProvider analyzerFactory = entry.getValue();
      String name = entry.getKey();
      /*
       * Lucene defaults positionIncrementGap to 0 in all analyzers but
       * Elasticsearch defaults them to 0 only before version 2.0
       * and 100 afterwards so we override the positionIncrementGap if it
       * doesn't match here.
       */
      int overridePositionIncrementGap = StringFieldMapper.Defaults.POSITION_INCREMENT_GAP;
      if (analyzerFactory instanceof CustomAnalyzerProvider) {
        ((CustomAnalyzerProvider) analyzerFactory).build(this);
        /*
         * Custom analyzers already default to the correct, version
         * dependent positionIncrementGap and the user is be able to
         * configure the positionIncrementGap directly on the analyzer so
         * we disable overriding the positionIncrementGap to preserve the
         * user's setting.
         */
        overridePositionIncrementGap = Integer.MIN_VALUE;
      }
      Analyzer analyzerF = analyzerFactory.get();
      if (analyzerF == null) {
        throw new IllegalArgumentException(
            "analyzer [" + analyzerFactory.name() + "] created null analyzer");
      }
      NamedAnalyzer analyzer;
      if (analyzerF instanceof NamedAnalyzer) {
        // if we got a named analyzer back, use it...
        analyzer = (NamedAnalyzer) analyzerF;
        if (overridePositionIncrementGap >= 0
            && analyzer.getPositionIncrementGap(analyzer.name()) != overridePositionIncrementGap) {
          // unless the positionIncrementGap needs to be overridden
          analyzer = new NamedAnalyzer(analyzer, overridePositionIncrementGap);
        }
      } else {
        analyzer =
            new NamedAnalyzer(
                name, analyzerFactory.scope(), analyzerF, overridePositionIncrementGap);
      }
      if (analyzers.containsKey(name)) {
        throw new IllegalStateException("already registered analyzer with name: " + name);
      }
      analyzers.put(name, analyzer);
      String strAliases =
          this.indexSettings
              .getSettings()
              .get("index.analysis.analyzer." + analyzerFactory.name() + ".alias");
      if (strAliases != null) {
        for (String alias : Strings.commaDelimitedListToStringArray(strAliases)) {
          analyzers.put(alias, analyzer);
        }
      }
      String[] aliases =
          this.indexSettings
              .getSettings()
              .getAsArray("index.analysis.analyzer." + analyzerFactory.name() + ".alias");
      for (String alias : aliases) {
        analyzers.put(alias, analyzer);
      }
    }

    NamedAnalyzer defaultAnalyzer = analyzers.get("default");
    if (defaultAnalyzer == null) {
      throw new IllegalArgumentException("no default analyzer configured");
    }
    if (analyzers.containsKey("default_index")) {
      final Version createdVersion = indexSettings.getIndexVersionCreated();
      if (createdVersion.onOrAfter(Version.V_3_0_0)) {
        throw new IllegalArgumentException(
            "setting [index.analysis.analyzer.default_index] is not supported anymore, use [index.analysis.analyzer.default] instead for index ["
                + index().getName()
                + "]");
      } else {
        deprecationLogger.deprecated(
            "setting [index.analysis.analyzer.default_index] is deprecated, use [index.analysis.analyzer.default] instead for index [{}]",
            index().getName());
      }
    }
    defaultIndexAnalyzer =
        analyzers.containsKey("default_index") ? analyzers.get("default_index") : defaultAnalyzer;
    defaultSearchAnalyzer =
        analyzers.containsKey("default_search") ? analyzers.get("default_search") : defaultAnalyzer;
    defaultSearchQuoteAnalyzer =
        analyzers.containsKey("default_search_quote")
            ? analyzers.get("default_search_quote")
            : defaultSearchAnalyzer;

    for (Map.Entry<String, NamedAnalyzer> analyzer : analyzers.entrySet()) {
      if (analyzer.getKey().startsWith("_")) {
        throw new IllegalArgumentException(
            "analyzer name must not start with '_'. got \"" + analyzer.getKey() + "\"");
      }
    }
    this.analyzers = unmodifiableMap(analyzers);
  }