1
0
Эх сурвалжийг харах

Upgrading analysis plugins fails

When an analysis plugins provides default index settings using `PreBuiltAnalyzerProviderFactory`,  `PreBuiltTokenFilterFactoryFactory` or `PreBuiltTokenizerFactoryFactory` it fails when upgrading it with elasticsearch superior or equal to 0.90.5.

Related issue: #4936

Fix is needed in core. But, in the meantime, analysis plugins developers can fix that issue by overloading default prebuilt factories.

For example:

```java
public class StempelAnalyzerProviderFactory extends PreBuiltAnalyzerProviderFactory {

    private final PreBuiltAnalyzerProvider analyzerProvider;

    public StempelAnalyzerProviderFactory(String name, AnalyzerScope scope, Analyzer analyzer) {
        super(name, scope, analyzer);
        analyzerProvider = new PreBuiltAnalyzerProvider(name, scope, analyzer);
    }

    @Override
    public AnalyzerProvider create(String name, Settings settings) {
        return analyzerProvider;
    }

    public Analyzer analyzer() {
        return analyzerProvider.get();
    }
}
```

And instead of:

```java
    @Inject
    public PolishIndicesAnalysis(Settings settings, IndicesAnalysisService indicesAnalysisService) {
        super(settings);
        indicesAnalysisService.analyzerProviderFactories().put("polish", new PreBuiltAnalyzerProviderFactory("polish", AnalyzerScope.INDICES, new PolishAnalyzer(Lucene.ANALYZER_VERSION)));
    }
```

do

```java
    @Inject
    public PolishIndicesAnalysis(Settings settings, IndicesAnalysisService indicesAnalysisService) {
        super(settings);
        indicesAnalysisService.analyzerProviderFactories().put("polish", new StempelAnalyzerProviderFactory("polish", AnalyzerScope.INDICES, new PolishAnalyzer(Lucene.ANALYZER_VERSION)));
    }
```

Closes #5030
David Pilato 11 жил өмнө
parent
commit
8b1c25e11f
18 өөрчлөгдсөн 478 нэмэгдсэн , 17 устгасан
  1. 5 4
      src/main/java/org/elasticsearch/index/analysis/PreBuiltAnalyzerProviderFactory.java
  2. 5 4
      src/main/java/org/elasticsearch/index/analysis/PreBuiltCharFilterFactoryFactory.java
  3. 5 4
      src/main/java/org/elasticsearch/index/analysis/PreBuiltTokenFilterFactoryFactory.java
  4. 5 5
      src/main/java/org/elasticsearch/index/analysis/PreBuiltTokenizerFactoryFactory.java
  5. 15 0
      src/main/java/org/elasticsearch/indices/analysis/PreBuiltAnalyzers.java
  6. 13 0
      src/main/java/org/elasticsearch/indices/analysis/PreBuiltCharFilters.java
  7. 12 0
      src/main/java/org/elasticsearch/indices/analysis/PreBuiltTokenFilters.java
  8. 12 0
      src/main/java/org/elasticsearch/indices/analysis/PreBuiltTokenizers.java
  9. 47 0
      src/test/java/org/elasticsearch/indices/analysis/DummyAnalysisBinderProcessor.java
  10. 55 0
      src/test/java/org/elasticsearch/indices/analysis/DummyAnalysisPlugin.java
  11. 37 0
      src/test/java/org/elasticsearch/indices/analysis/DummyAnalyzer.java
  12. 41 0
      src/test/java/org/elasticsearch/indices/analysis/DummyAnalyzerProvider.java
  13. 36 0
      src/test/java/org/elasticsearch/indices/analysis/DummyCharFilterFactory.java
  14. 43 0
      src/test/java/org/elasticsearch/indices/analysis/DummyIndicesAnalysis.java
  15. 30 0
      src/test/java/org/elasticsearch/indices/analysis/DummyIndicesAnalysisModule.java
  16. 33 0
      src/test/java/org/elasticsearch/indices/analysis/DummyTokenFilterFactory.java
  17. 37 0
      src/test/java/org/elasticsearch/indices/analysis/DummyTokenizerFactory.java
  18. 47 0
      src/test/java/org/elasticsearch/indices/analysis/PreBuiltAnalyzerIntegrationTests.java

+ 5 - 4
src/main/java/org/elasticsearch/index/analysis/PreBuiltAnalyzerProviderFactory.java

@@ -25,8 +25,6 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.indices.analysis.PreBuiltAnalyzers;
 
-import java.util.Locale;
-
 /**
  *
  */
@@ -42,8 +40,11 @@ public class PreBuiltAnalyzerProviderFactory implements AnalyzerProviderFactory
     public AnalyzerProvider create(String name, Settings settings) {
         Version indexVersion = settings.getAsVersion(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT);
         if (!Version.CURRENT.equals(indexVersion)) {
-            Analyzer analyzer = PreBuiltAnalyzers.valueOf(name.toUpperCase(Locale.ROOT)).getAnalyzer(indexVersion);
-            return new PreBuiltAnalyzerProvider(name, AnalyzerScope.INDICES, analyzer);
+            PreBuiltAnalyzers preBuiltAnalyzers = PreBuiltAnalyzers.getOrDefault(name, null);
+            if (preBuiltAnalyzers != null) {
+                Analyzer analyzer = preBuiltAnalyzers.getAnalyzer(indexVersion);
+                return new PreBuiltAnalyzerProvider(name, AnalyzerScope.INDICES, analyzer);
+            }
         }
 
         return analyzerProvider;

+ 5 - 4
src/main/java/org/elasticsearch/index/analysis/PreBuiltCharFilterFactoryFactory.java

@@ -24,8 +24,6 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.indices.analysis.PreBuiltCharFilters;
 
-import java.util.Locale;
-
 public class PreBuiltCharFilterFactoryFactory implements CharFilterFactoryFactory {
 
     private final CharFilterFactory charFilterFactory;
@@ -38,9 +36,12 @@ public class PreBuiltCharFilterFactoryFactory implements CharFilterFactoryFactor
     public CharFilterFactory create(String name, Settings settings) {
         Version indexVersion = settings.getAsVersion(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT);
         if (!Version.CURRENT.equals(indexVersion)) {
-            return PreBuiltCharFilters.valueOf(name.toUpperCase(Locale.ROOT)).getCharFilterFactory(indexVersion);
+            PreBuiltCharFilters preBuiltCharFilters = PreBuiltCharFilters.getOrDefault(name, null);
+            if (preBuiltCharFilters != null) {
+                return preBuiltCharFilters.getCharFilterFactory(indexVersion);
+            }
         }
 
         return charFilterFactory;
     }
-}
+}

+ 5 - 4
src/main/java/org/elasticsearch/index/analysis/PreBuiltTokenFilterFactoryFactory.java

@@ -24,8 +24,6 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.indices.analysis.PreBuiltTokenFilters;
 
-import java.util.Locale;
-
 public class PreBuiltTokenFilterFactoryFactory implements TokenFilterFactoryFactory {
 
     private final TokenFilterFactory tokenFilterFactory;
@@ -38,8 +36,11 @@ public class PreBuiltTokenFilterFactoryFactory implements TokenFilterFactoryFact
     public TokenFilterFactory create(String name, Settings settings) {
         Version indexVersion = settings.getAsVersion(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT);
         if (!Version.CURRENT.equals(indexVersion)) {
-            return PreBuiltTokenFilters.valueOf(name.toUpperCase(Locale.ROOT)).getTokenFilterFactory(indexVersion);
+            PreBuiltTokenFilters preBuiltTokenFilters = PreBuiltTokenFilters.getOrDefault(name, null);
+            if (preBuiltTokenFilters != null) {
+                return preBuiltTokenFilters.getTokenFilterFactory(indexVersion);
+            }
         }
         return tokenFilterFactory;
     }
-}
+}

+ 5 - 5
src/main/java/org/elasticsearch/index/analysis/PreBuiltTokenizerFactoryFactory.java

@@ -24,8 +24,6 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.indices.analysis.PreBuiltTokenizers;
 
-import java.util.Locale;
-
 public class PreBuiltTokenizerFactoryFactory implements TokenizerFactoryFactory {
 
     private final TokenizerFactory tokenizerFactory;
@@ -38,10 +36,12 @@ public class PreBuiltTokenizerFactoryFactory implements TokenizerFactoryFactory
     public TokenizerFactory create(String name, Settings settings) {
         Version indexVersion = settings.getAsVersion(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT);
         if (!Version.CURRENT.equals(indexVersion)) {
-            TokenizerFactory versionedTokenizerFactory = PreBuiltTokenizers.valueOf(name.toUpperCase(Locale.ROOT)).getTokenizerFactory(indexVersion);
-            return versionedTokenizerFactory;
+            PreBuiltTokenizers preBuiltTokenizers = PreBuiltTokenizers.getOrDefault(name, null);
+            if (preBuiltTokenizers != null) {
+                return preBuiltTokenizers.getTokenizerFactory(indexVersion);
+            }
         }
 
         return tokenizerFactory;
     }
-}
+}

+ 15 - 0
src/main/java/org/elasticsearch/indices/analysis/PreBuiltAnalyzers.java

@@ -65,6 +65,8 @@ import org.elasticsearch.common.regex.Regex;
 import org.elasticsearch.index.analysis.StandardHtmlStripAnalyzer;
 import org.elasticsearch.indices.analysis.PreBuiltCacheFactory.CachingStrategy;
 
+import java.util.Locale;
+
 /**
  *
  */
@@ -401,4 +403,17 @@ public enum PreBuiltAnalyzers {
         return analyzer;
     }
 
+    /**
+     * Get a pre built Analyzer by its name or fallback to the default one
+     * @param name Analyzer name
+     * @param defaultAnalyzer default Analyzer if name not found
+     */
+    public static PreBuiltAnalyzers getOrDefault(String name, PreBuiltAnalyzers defaultAnalyzer) {
+        try {
+            return valueOf(name.toUpperCase(Locale.ROOT));
+        } catch (IllegalArgumentException e) {
+            return defaultAnalyzer;
+        }
+    }
+
 }

+ 13 - 0
src/main/java/org/elasticsearch/indices/analysis/PreBuiltCharFilters.java

@@ -67,4 +67,17 @@ public enum PreBuiltCharFilters {
 
         return charFilterFactory;
     }
+
+    /**
+     * Get a pre built CharFilter by its name or fallback to the default one
+     * @param name CharFilter name
+     * @param defaultCharFilter default CharFilter if name not found
+     */
+    public static PreBuiltCharFilters getOrDefault(String name, PreBuiltCharFilters defaultCharFilter) {
+        try {
+            return valueOf(name.toUpperCase(Locale.ROOT));
+        } catch (IllegalArgumentException e) {
+            return defaultCharFilter;
+        }
+    }
 }

+ 12 - 0
src/main/java/org/elasticsearch/indices/analysis/PreBuiltTokenFilters.java

@@ -309,4 +309,16 @@ public enum PreBuiltTokenFilters {
         return factory;
     }
 
+    /**
+     * Get a pre built TokenFilter by its name or fallback to the default one
+     * @param name TokenFilter name
+     * @param defaultTokenFilter default TokenFilter if name not found
+     */
+    public static PreBuiltTokenFilters getOrDefault(String name, PreBuiltTokenFilters defaultTokenFilter) {
+        try {
+            return valueOf(name.toUpperCase(Locale.ROOT));
+        } catch (IllegalArgumentException e) {
+            return defaultTokenFilter;
+        }
+    }
 }

+ 12 - 0
src/main/java/org/elasticsearch/indices/analysis/PreBuiltTokenizers.java

@@ -151,4 +151,16 @@ public enum PreBuiltTokenizers {
         return tokenizerFactory;
     }
 
+    /**
+     * Get a pre built Tokenizer by its name or fallback to the default one
+     * @param name Tokenizer name
+     * @param defaultTokenizer default Tokenizer if name not found
+     */
+    public static PreBuiltTokenizers getOrDefault(String name, PreBuiltTokenizers defaultTokenizer) {
+        try {
+            return valueOf(name.toUpperCase(Locale.ROOT));
+        } catch (IllegalArgumentException e) {
+            return defaultTokenizer;
+        }
+    }
 }

+ 47 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyAnalysisBinderProcessor.java

@@ -0,0 +1,47 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import org.elasticsearch.index.analysis.AnalysisModule;
+
+/**
+ */
+public class DummyAnalysisBinderProcessor extends AnalysisModule.AnalysisBinderProcessor {
+
+    @Override
+    public void processAnalyzers(AnalyzersBindings analyzersBindings) {
+        analyzersBindings.processAnalyzer("dummy", DummyAnalyzerProvider.class);
+    }
+
+    @Override
+    public void processTokenFilters(TokenFiltersBindings tokenFiltersBindings) {
+        tokenFiltersBindings.processTokenFilter("dummy_token_filter", DummyTokenFilterFactory.class);
+    }
+
+    @Override
+    public void processTokenizers(TokenizersBindings tokenizersBindings) {
+        tokenizersBindings.processTokenizer("dummy_tokenizer", DummyTokenizerFactory.class);
+    }
+
+    @Override
+    public void processCharFilters(CharFiltersBindings charFiltersBindings) {
+        charFiltersBindings.processCharFilter("dummy_char_filter", DummyCharFilterFactory.class);
+    }
+}

+ 55 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyAnalysisPlugin.java

@@ -0,0 +1,55 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import com.google.common.collect.ImmutableList;
+import org.elasticsearch.common.inject.Module;
+import org.elasticsearch.index.analysis.AnalysisModule;
+import org.elasticsearch.plugins.AbstractPlugin;
+
+import java.util.Collection;
+
+public class DummyAnalysisPlugin extends AbstractPlugin {
+    /**
+     * The name of the plugin.
+     */
+    @Override
+    public String name() {
+        return "analysis-dummy";
+    }
+
+    /**
+     * The description of the plugin.
+     */
+    @Override
+    public String description() {
+        return "Analysis Dummy Plugin";
+    }
+
+    @Override
+    public Collection<Class<? extends Module>> modules() {
+        return ImmutableList.<Class<? extends Module>>of(DummyIndicesAnalysisModule.class);
+    }
+
+    public void onModule(AnalysisModule module) {
+        module.addProcessor(new DummyAnalysisBinderProcessor());
+    }
+
+}

+ 37 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyAnalyzer.java

@@ -0,0 +1,37 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import org.apache.lucene.analysis.util.StopwordAnalyzerBase;
+import org.apache.lucene.util.Version;
+
+import java.io.Reader;
+
+public class DummyAnalyzer extends StopwordAnalyzerBase {
+
+    protected DummyAnalyzer(Version version) {
+        super(version);
+    }
+
+    @Override
+    protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
+        return null;
+    }
+}

+ 41 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyAnalyzerProvider.java

@@ -0,0 +1,41 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import org.elasticsearch.common.lucene.Lucene;
+import org.elasticsearch.index.analysis.AnalyzerProvider;
+import org.elasticsearch.index.analysis.AnalyzerScope;
+
+public class DummyAnalyzerProvider implements AnalyzerProvider<DummyAnalyzer> {
+    @Override
+    public String name() {
+        return "dummy";
+    }
+
+    @Override
+    public AnalyzerScope scope() {
+        return AnalyzerScope.INDICES;
+    }
+
+    @Override
+    public DummyAnalyzer get() {
+        return new DummyAnalyzer(Lucene.ANALYZER_VERSION);
+    }
+}

+ 36 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyCharFilterFactory.java

@@ -0,0 +1,36 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import org.elasticsearch.index.analysis.CharFilterFactory;
+
+import java.io.Reader;
+
+public class DummyCharFilterFactory implements CharFilterFactory {
+    @Override
+    public String name() {
+        return "dummy_char_filter";
+    }
+
+    @Override
+    public Reader create(Reader reader) {
+        return null;
+    }
+}

+ 43 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyIndicesAnalysis.java

@@ -0,0 +1,43 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import org.elasticsearch.common.component.AbstractComponent;
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.lucene.Lucene;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.analysis.*;
+
+public class DummyIndicesAnalysis extends AbstractComponent {
+
+    @Inject
+    public DummyIndicesAnalysis(Settings settings, IndicesAnalysisService indicesAnalysisService) {
+        super(settings);
+        indicesAnalysisService.analyzerProviderFactories().put("dummy",
+                new PreBuiltAnalyzerProviderFactory("dummy", AnalyzerScope.INDICES,
+                        new DummyAnalyzer(Lucene.ANALYZER_VERSION)));
+        indicesAnalysisService.tokenFilterFactories().put("dummy_token_filter",
+                new PreBuiltTokenFilterFactoryFactory(new DummyTokenFilterFactory()));
+        indicesAnalysisService.charFilterFactories().put("dummy_char_filter",
+                new PreBuiltCharFilterFactoryFactory(new DummyCharFilterFactory()));
+        indicesAnalysisService.tokenizerFactories().put("dummy_tokenizer",
+                new PreBuiltTokenizerFactoryFactory(new DummyTokenizerFactory()));
+    }
+}

+ 30 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyIndicesAnalysisModule.java

@@ -0,0 +1,30 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import org.elasticsearch.common.inject.AbstractModule;
+
+public class DummyIndicesAnalysisModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        bind(DummyIndicesAnalysis.class).asEagerSingleton();
+    }
+}

+ 33 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyTokenFilterFactory.java

@@ -0,0 +1,33 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import org.apache.lucene.analysis.TokenStream;
+import org.elasticsearch.index.analysis.TokenFilterFactory;
+
+public class DummyTokenFilterFactory implements TokenFilterFactory {
+    @Override public String name() {
+        return "dummy_token_filter";
+    }
+
+    @Override public TokenStream create(TokenStream tokenStream) {
+        return null;
+    }
+}

+ 37 - 0
src/test/java/org/elasticsearch/indices/analysis/DummyTokenizerFactory.java

@@ -0,0 +1,37 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.indices.analysis;
+
+import org.apache.lucene.analysis.Tokenizer;
+import org.elasticsearch.index.analysis.TokenizerFactory;
+
+import java.io.Reader;
+
+public class DummyTokenizerFactory implements TokenizerFactory {
+    @Override
+    public String name() {
+        return "dummy_tokenizer";
+    }
+
+    @Override
+    public Tokenizer create(Reader reader) {
+        return null;
+    }
+}

+ 47 - 0
src/test/java/org/elasticsearch/indices/analysis/PreBuiltAnalyzerIntegrationTests.java

@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.elasticsearch.indices.analysis;
 
 import com.google.common.collect.Lists;
@@ -41,8 +42,17 @@ import static org.hamcrest.Matchers.notNullValue;
 /**
  *
  */
+@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE)
 public class PreBuiltAnalyzerIntegrationTests extends ElasticsearchIntegrationTest {
 
+    @Override
+    protected Settings nodeSettings(int nodeOrdinal) {
+        return ImmutableSettings.settingsBuilder()
+                .put("plugin.types", DummyAnalysisPlugin.class.getName())
+                .put(super.nodeSettings(nodeOrdinal))
+            .build();
+    }
+
     @Test
     public void testThatPreBuiltAnalyzersAreNotClosedOnIndexClose() throws Exception {
         Map<PreBuiltAnalyzers, List<Version>> loadedAnalyzers = Maps.newHashMap();
@@ -108,6 +118,43 @@ public class PreBuiltAnalyzerIntegrationTests extends ElasticsearchIntegrationTe
         assertLuceneAnalyzersAreNotClosed(loadedAnalyzers);
     }
 
+    /**
+     * Test case for #5030: Upgrading analysis plugins fails
+     * See https://github.com/elasticsearch/elasticsearch/issues/5030
+     */
+    @Test
+    public void testThatPluginAnalyzersCanBeUpdated() throws Exception {
+        final XContentBuilder mapping = jsonBuilder().startObject()
+            .startObject("type")
+                .startObject("properties")
+                    .startObject("foo")
+                        .field("type", "string")
+                        .field("analyzer", "dummy")
+                    .endObject()
+                    .startObject("bar")
+                        .field("type", "string")
+                        .field("analyzer", "my_dummy")
+                    .endObject()
+                .endObject()
+            .endObject()
+            .endObject();
+
+        Settings versionSettings = ImmutableSettings.builder()
+                .put(IndexMetaData.SETTING_VERSION_CREATED, randomVersion())
+                .put("index.analysis.analyzer.my_dummy.type", "custom")
+                .put("index.analysis.analyzer.my_dummy.filter", "my_dummy_token_filter")
+                .put("index.analysis.analyzer.my_dummy.char_filter", "my_dummy_char_filter")
+                .put("index.analysis.analyzer.my_dummy.tokenizer", "my_dummy_tokenizer")
+                .put("index.analysis.tokenizer.my_dummy_tokenizer.type", "dummy_tokenizer")
+                .put("index.analysis.filter.my_dummy_token_filter.type", "dummy_token_filter")
+                .put("index.analysis.char_filter.my_dummy_char_filter.type", "dummy_char_filter")
+                .build();
+
+        client().admin().indices().prepareCreate("test-analysis-dummy").addMapping("type", mapping).setSettings(versionSettings).get();
+
+        ensureGreen();
+    }
+
     private void assertThatAnalyzersHaveBeenLoaded(Map<PreBuiltAnalyzers, List<Version>> expectedLoadedAnalyzers) {
         for (Map.Entry<PreBuiltAnalyzers, List<Version>> entry : expectedLoadedAnalyzers.entrySet()) {
             for (Version version : entry.getValue()) {