2020package org .elasticsearch .index .analysis ;
2121
2222import com .carrotsearch .randomizedtesting .generators .RandomPicks ;
23+
2324import org .apache .lucene .analysis .Analyzer ;
2425import org .apache .lucene .analysis .MockTokenFilter ;
2526import org .apache .lucene .analysis .TokenStream ;
2627import org .apache .lucene .analysis .Tokenizer ;
2728import org .apache .lucene .analysis .en .EnglishAnalyzer ;
29+ import org .apache .lucene .analysis .reverse .ReverseStringFilter ;
2830import org .apache .lucene .analysis .standard .StandardAnalyzer ;
2931import org .apache .lucene .analysis .standard .StandardTokenizer ;
3032import org .apache .lucene .analysis .tokenattributes .CharTermAttribute ;
3941import org .elasticsearch .indices .analysis .AnalysisModule .AnalysisProvider ;
4042import org .elasticsearch .indices .analysis .PreBuiltAnalyzers ;
4143import org .elasticsearch .plugins .AnalysisPlugin ;
44+ import org .elasticsearch .plugins .Plugin ;
4245import org .elasticsearch .test .ESTestCase ;
4346import org .elasticsearch .test .IndexSettingsModule ;
4447import org .elasticsearch .test .VersionUtils ;
4548
4649import java .io .IOException ;
4750import java .util .Collections ;
4851import java .util .HashMap ;
52+ import java .util .List ;
4953import java .util .Map ;
5054
5155import static java .util .Collections .emptyMap ;
5862
5963public class AnalysisRegistryTests extends ESTestCase {
6064 private AnalysisRegistry emptyRegistry ;
65+ private AnalysisRegistry nonEmptyRegistry ;
6166
6267 private static AnalyzerProvider <?> analyzerProvider (final String name ) {
6368 return new PreBuiltAnalyzerProvider (name , AnalyzerScope .INDEX , new EnglishAnalyzer ());
@@ -68,6 +73,16 @@ private static AnalysisRegistry emptyAnalysisRegistry(Settings settings) {
6873 emptyMap (), emptyMap (), emptyMap (), emptyMap ());
6974 }
7075
76+ /**
77+ * Creates a reverse filter available for use in testNameClashNormalizer test
78+ */
79+ public static class MockAnalysisPlugin extends Plugin implements AnalysisPlugin {
80+ @ Override
81+ public List <PreConfiguredTokenFilter > getPreConfiguredTokenFilters () {
82+ return singletonList (PreConfiguredTokenFilter .singleton ("reverse" , true , ReverseStringFilter ::new ));
83+ }
84+ }
85+
7186 private static IndexSettings indexSettingsOfCurrentVersion (Settings .Builder settings ) {
7287 return IndexSettingsModule .newIndexSettings ("index" , settings
7388 .put (IndexMetadata .SETTING_VERSION_CREATED , Version .CURRENT )
@@ -77,9 +92,13 @@ private static IndexSettings indexSettingsOfCurrentVersion(Settings.Builder sett
7792 @ Override
7893 public void setUp () throws Exception {
7994 super .setUp ();
80- emptyRegistry = emptyAnalysisRegistry ( Settings .builder ()
95+ Settings settings = Settings .builder ()
8196 .put (Environment .PATH_HOME_SETTING .getKey (), createTempDir ().toString ())
82- .build ());
97+ .build ();
98+ emptyRegistry = emptyAnalysisRegistry (settings );
99+ // Module loaded to register in-built normalizers for testing
100+ AnalysisModule module = new AnalysisModule (TestEnvironment .newEnvironment (settings ), singletonList (new MockAnalysisPlugin ()));
101+ nonEmptyRegistry = module .getAnalysisRegistry ();
83102 }
84103
85104 public void testDefaultAnalyzers () throws IOException {
@@ -135,7 +154,29 @@ public Tokenizer create() {
135154 emptyMap (), emptyMap (), emptyMap ()));
136155 assertEquals ("analyzer [default] contains filters [my_filter] that are not allowed to run in all mode." , ex .getMessage ());
137156 }
157+
158+
159+ public void testNameClashNormalizer () throws IOException {
160+
161+ // Test out-of-the-box normalizer works OK.
162+ IndexAnalyzers indexAnalyzers = nonEmptyRegistry .build (IndexSettingsModule .newIndexSettings ("index" , Settings .EMPTY ));
163+ assertNotNull (indexAnalyzers .getNormalizer ("lowercase" ));
164+ assertThat (indexAnalyzers .getNormalizer ("lowercase" ).normalize ("field" , "AbC" ).utf8ToString (), equalTo ("abc" ));
165+
166+ // Test that a name clash with a custom normalizer will favour the index's normalizer rather than the out-of-the-box
167+ // one of the same name. (However this "feature" will be removed with https://github.com/elastic/elasticsearch/issues/22263 )
168+ Settings settings = Settings .builder ()
169+ // Deliberately bad choice of normalizer name for the job it does.
170+ .put ("index.analysis.normalizer.lowercase.type" , "custom" )
171+ .putList ("index.analysis.normalizer.lowercase.filter" , "reverse" )
172+ .build ();
173+
174+ indexAnalyzers = nonEmptyRegistry .build (IndexSettingsModule .newIndexSettings ("index" , settings ));
175+ assertNotNull (indexAnalyzers .getNormalizer ("lowercase" ));
176+ assertThat (indexAnalyzers .getNormalizer ("lowercase" ).normalize ("field" ,"AbC" ).utf8ToString (), equalTo ("CbA" ));
177+ }
138178
179+
139180 public void testOverrideDefaultIndexAnalyzerIsUnsupported () {
140181 Version version = VersionUtils .randomVersionBetween (random (), Version .V_6_0_0_alpha1 , Version .CURRENT );
141182 Settings settings = Settings .builder ().put (IndexMetadata .SETTING_VERSION_CREATED , version ).build ();
0 commit comments