1919
2020package org .elasticsearch .index .mapper ;
2121
22+ import org .apache .lucene .analysis .TokenStream ;
2223import org .elasticsearch .ExceptionsHelper ;
24+ import org .elasticsearch .cluster .metadata .IndexMetaData ;
2325import org .elasticsearch .common .Strings ;
2426import org .elasticsearch .common .bytes .BytesReference ;
2527import org .elasticsearch .common .compress .CompressedXContent ;
2628import org .elasticsearch .common .settings .Settings ;
2729import org .elasticsearch .common .xcontent .XContentBuilder ;
2830import org .elasticsearch .common .xcontent .XContentFactory ;
2931import org .elasticsearch .common .xcontent .XContentType ;
32+ import org .elasticsearch .env .Environment ;
3033import org .elasticsearch .index .IndexService ;
34+ import org .elasticsearch .index .IndexSettings ;
35+ import org .elasticsearch .index .analysis .AnalysisMode ;
36+ import org .elasticsearch .index .analysis .AnalysisRegistry ;
37+ import org .elasticsearch .index .analysis .IndexAnalyzers ;
38+ import org .elasticsearch .index .analysis .NamedAnalyzer ;
39+ import org .elasticsearch .index .analysis .TokenFilterFactory ;
3140import org .elasticsearch .index .mapper .KeywordFieldMapper .KeywordFieldType ;
3241import org .elasticsearch .index .mapper .MapperService .MergeReason ;
3342import org .elasticsearch .index .mapper .NumberFieldMapper .NumberFieldType ;
3443import org .elasticsearch .indices .InvalidTypeNameException ;
44+ import org .elasticsearch .indices .analysis .AnalysisModule .AnalysisProvider ;
45+ import org .elasticsearch .plugins .AnalysisPlugin ;
3546import org .elasticsearch .plugins .Plugin ;
3647import org .elasticsearch .test .ESSingleNodeTestCase ;
3748import org .elasticsearch .test .InternalSettingsPlugin ;
3849
3950import java .io .IOException ;
4051import java .util .Collection ;
4152import java .util .Collections ;
53+ import java .util .List ;
54+ import java .util .Map ;
4255import java .util .concurrent .ExecutionException ;
4356
4457import static org .hamcrest .CoreMatchers .containsString ;
@@ -49,7 +62,7 @@ public class MapperServiceTests extends ESSingleNodeTestCase {
4962
5063 @ Override
5164 protected Collection <Class <? extends Plugin >> getPlugins () {
52- return Collections . singleton (InternalSettingsPlugin .class );
65+ return List . of (InternalSettingsPlugin . class , ReloadableFilterPlugin .class );
5366 }
5467
5568 public void testTypeNameStartsWithIllegalDot () {
@@ -434,4 +447,93 @@ public void testMappingRecoverySkipFieldNameLengthLimit() throws Throwable {
434447 assertEquals (testString , documentMapper .mappers ().getMapper (testString ).simpleName ());
435448 }
436449
450+ public void testReloadSearchAnalyzersNoReload () throws IOException {
451+ MapperService mapperService = createIndex ("no_reload_index" , Settings .EMPTY ).mapperService ();
452+ IndexAnalyzers current = mapperService .getIndexAnalyzers ();
453+ mapperService .reloadSearchAnalyzers (getInstanceFromNode (AnalysisRegistry .class ));
454+ assertSame (current , mapperService .getIndexAnalyzers ());
455+ }
456+
457+ public void testReloadSearchAnalyzers () throws IOException {
458+ Settings settings = Settings .builder ().put (IndexMetaData .SETTING_NUMBER_OF_SHARDS , 1 )
459+ .put (IndexMetaData .SETTING_NUMBER_OF_REPLICAS , 1 )
460+ .put ("index.analysis.analyzer.reloadableAnalyzer.type" , "custom" )
461+ .put ("index.analysis.analyzer.reloadableAnalyzer.tokenizer" , "standard" )
462+ .putList ("index.analysis.analyzer.reloadableAnalyzer.filter" , "myReloadableFilter" ).build ();
463+
464+ MapperService mapperService = createIndex ("test_index" , settings ).mapperService ();
465+ CompressedXContent mapping = new CompressedXContent (BytesReference .bytes (
466+ XContentFactory .jsonBuilder ().startObject ().startObject ("_doc" )
467+ .startObject ("properties" )
468+ .startObject ("field" )
469+ .field ("type" , "text" )
470+ .field ("analyzer" , "simple" )
471+ .field ("search_analyzer" , "reloadableAnalyzer" )
472+ .field ("search_quote_analyzer" , "stop" )
473+ .endObject ()
474+ .startObject ("otherField" )
475+ .field ("type" , "text" )
476+ .field ("analyzer" , "standard" )
477+ .field ("search_analyzer" , "simple" )
478+ .field ("search_quote_analyzer" , "reloadableAnalyzer" )
479+ .endObject ()
480+ .endObject ()
481+ .endObject ().endObject ()));
482+
483+ mapperService .merge ("_doc" , mapping , MergeReason .MAPPING_UPDATE );
484+ IndexAnalyzers current = mapperService .getIndexAnalyzers ();
485+ MappedFieldType fieldType = mapperService .fullName ("field" );
486+ NamedAnalyzer originalFieldsearchAnalyzer = fieldType .searchAnalyzer ();
487+ NamedAnalyzer originalFieldsearchQuoteAnalyzer = fieldType .searchQuoteAnalyzer ();
488+
489+ MappedFieldType otherFieldType = mapperService .fullName ("otherField" );
490+ NamedAnalyzer originalOtherFieldsearchAnalyzer = otherFieldType .searchAnalyzer ();
491+ NamedAnalyzer originalOtherFieldsearchQuoteAnalyzer = otherFieldType .searchQuoteAnalyzer ();
492+
493+ mapperService .reloadSearchAnalyzers (getInstanceFromNode (AnalysisRegistry .class ));
494+ IndexAnalyzers updatedAnalyzers = mapperService .getIndexAnalyzers ();
495+ assertNotSame (current , updatedAnalyzers );
496+ assertSame (current .getDefaultIndexAnalyzer (), updatedAnalyzers .getDefaultIndexAnalyzer ());
497+ assertSame (current .getDefaultSearchAnalyzer (), updatedAnalyzers .getDefaultSearchAnalyzer ());
498+ assertSame (current .getDefaultSearchQuoteAnalyzer (), updatedAnalyzers .getDefaultSearchQuoteAnalyzer ());
499+
500+ assertNotSame (originalFieldsearchAnalyzer , mapperService .fullName ("field" ).searchAnalyzer ());
501+ assertSame (originalOtherFieldsearchAnalyzer , mapperService .fullName ("otherField" ).searchAnalyzer ());
502+
503+ assertSame (originalFieldsearchQuoteAnalyzer , mapperService .fullName ("field" ).searchQuoteAnalyzer ());
504+ assertNotSame (originalOtherFieldsearchQuoteAnalyzer , mapperService .fullName ("otherField" ).searchQuoteAnalyzer ());
505+
506+ }
507+
508+ public static final class ReloadableFilterPlugin extends Plugin implements AnalysisPlugin {
509+
510+ @ Override
511+ public Map <String , AnalysisProvider <TokenFilterFactory >> getTokenFilters () {
512+ return Collections .singletonMap ("myReloadableFilter" , new AnalysisProvider <TokenFilterFactory >() {
513+
514+ @ Override
515+ public TokenFilterFactory get (IndexSettings indexSettings , Environment environment , String name , Settings settings )
516+ throws IOException {
517+ return new TokenFilterFactory () {
518+
519+ @ Override
520+ public String name () {
521+ return "myReloadableFilter" ;
522+ }
523+
524+ @ Override
525+ public TokenStream create (TokenStream tokenStream ) {
526+ return tokenStream ;
527+ }
528+
529+ @ Override
530+ public AnalysisMode getAnalysisMode () {
531+ return AnalysisMode .SEARCH_TIME ;
532+ }
533+ };
534+ }
535+ });
536+ }
537+ }
538+
437539}
0 commit comments