4949 * This class exists per node and allows to create per-index {@link AnalysisService} via {@link #build(IndexSettings)}
5050 */
5151public final class AnalysisRegistry implements Closeable {
52+ public static final String INDEX_ANALYSIS_CHAR_FILTER = "index.analysis.char_filter" ;
53+ public static final String INDEX_ANALYSIS_FILTER = "index.analysis.filter" ;
54+ public static final String INDEX_ANALYSIS_TOKENIZER = "index.analysis.tokenizer" ;
5255 private final PrebuiltAnalysis prebuiltAnalysis = new PrebuiltAnalysis ();
5356 private final Map <String , Analyzer > cachedAnalyzer = new ConcurrentHashMap <>();
5457
@@ -70,6 +73,14 @@ public AnalysisRegistry(Environment environment,
7073 this .analyzers = unmodifiableMap (analyzers );
7174 }
7275
76+ public static Settings getSettingsFromIndexSettings (IndexSettings indexSettings , String groupName ) {
77+ Settings settings = indexSettings .getSettings ().getAsSettings (groupName );
78+ if (settings .isEmpty ()) {
79+ settings = Settings .builder ().put (IndexMetaData .SETTING_VERSION_CREATED , indexSettings .getIndexVersionCreated ()).build ();
80+ }
81+ return settings ;
82+ }
83+
7384 /**
7485 * Returns a registered {@link TokenizerFactory} provider by name or <code>null</code> if the tokenizer was not registered
7586 */
@@ -122,9 +133,9 @@ public void close() throws IOException {
122133 * Creates an index-level {@link AnalysisService} from this registry using the given index settings
123134 */
124135 public AnalysisService build (IndexSettings indexSettings ) throws IOException {
125- final Map <String , Settings > charFiltersSettings = indexSettings .getSettings ().getGroups ("index.analysis.char_filter" );
126- final Map <String , Settings > tokenFiltersSettings = indexSettings .getSettings ().getGroups ("index.analysis.filter" );
127- final Map <String , Settings > tokenizersSettings = indexSettings .getSettings ().getGroups ("index.analysis.tokenizer" );
136+ final Map <String , Settings > charFiltersSettings = indexSettings .getSettings ().getGroups (INDEX_ANALYSIS_CHAR_FILTER );
137+ final Map <String , Settings > tokenFiltersSettings = indexSettings .getSettings ().getGroups (INDEX_ANALYSIS_FILTER );
138+ final Map <String , Settings > tokenizersSettings = indexSettings .getSettings ().getGroups (INDEX_ANALYSIS_TOKENIZER );
128139 final Map <String , Settings > analyzersSettings = indexSettings .getSettings ().getGroups ("index.analysis.analyzer" );
129140
130141 final Map <String , CharFilterFactory > charFilterFactories = buildMapping (false , "charfilter" , indexSettings , charFiltersSettings , charFilters , prebuiltAnalysis .charFilterFactories );
@@ -136,14 +147,54 @@ public AnalysisService build(IndexSettings indexSettings) throws IOException {
136147 * instead of building the infrastructure for plugins we rather make it a real exception to not pollute the general interface and
137148 * hide internal data-structures as much as possible.
138149 */
139- tokenFilters .put ("synonym" , requriesAnalysisSettings ((is , env , name , settings ) -> new SynonymTokenFilterFactory (is , env , tokenizerFactories , name , settings )));
150+ tokenFilters .put ("synonym" , requriesAnalysisSettings ((is , env , name , settings ) -> new SynonymTokenFilterFactory (is , env , this , name , settings )));
140151 final Map <String , TokenFilterFactory > tokenFilterFactories = buildMapping (false , "tokenfilter" , indexSettings , tokenFiltersSettings , Collections .unmodifiableMap (tokenFilters ), prebuiltAnalysis .tokenFilterFactories );
141152 final Map <String , AnalyzerProvider <?>> analyzierFactories = buildMapping (true , "analyzer" , indexSettings , analyzersSettings ,
142153 analyzers , prebuiltAnalysis .analyzerProviderFactories );
143154 return new AnalysisService (indexSettings , analyzierFactories , tokenizerFactories , charFilterFactories , tokenFilterFactories );
144155 }
145156
146157
158+ public AnalysisProvider <TokenizerFactory > getTokenizerProvider (String tokenizer , IndexSettings indexSettings ) {
159+ final Map <String , Settings > tokenizerSettings = indexSettings .getSettings ().getGroups ("index.analysis.tokenizer" );
160+ if (tokenizerSettings .containsKey (tokenizer )) {
161+ Settings currentSettings = tokenizerSettings .get (tokenizer );
162+ return getAnalysisProvider ("tokenizer" , tokenizers , tokenizer , currentSettings .get ("type" ));
163+ } else {
164+ return prebuiltAnalysis .tokenizerFactories .get (tokenizer );
165+ }
166+ }
167+
168+ public AnalysisProvider <TokenFilterFactory > getTokenFilterProvider (String tokenFilter , IndexSettings indexSettings ) {
169+ final Map <String , Settings > tokenFilterSettings = indexSettings .getSettings ().getGroups ("index.analysis.filter" );
170+ if (tokenFilterSettings .containsKey (tokenFilter )) {
171+ Settings currentSettings = tokenFilterSettings .get (tokenFilter );
172+ String typeName = currentSettings .get ("type" );
173+ /*
174+ * synonym is different than everything else since it needs access to the tokenizer factories for this index.
175+ * instead of building the infrastructure for plugins we rather make it a real exception to not pollute the general interface and
176+ * hide internal data-structures as much as possible.
177+ */
178+ if ("synonym" .equals (typeName )) {
179+ return requriesAnalysisSettings ((is , env , name , settings ) -> new SynonymTokenFilterFactory (is , env , this , name , settings ));
180+ } else {
181+ return getAnalysisProvider ("tokenfilter" , tokenFilters , tokenFilter , typeName );
182+ }
183+ } else {
184+ return prebuiltAnalysis .tokenFilterFactories .get (tokenFilter );
185+ }
186+ }
187+
188+ public AnalysisProvider <CharFilterFactory > getCharFilterProvider (String charFilter , IndexSettings indexSettings ) {
189+ final Map <String , Settings > tokenFilterSettings = indexSettings .getSettings ().getGroups ("index.analysis.char_filter" );
190+ if (tokenFilterSettings .containsKey (charFilter )) {
191+ Settings currentSettings = tokenFilterSettings .get (charFilter );
192+ return getAnalysisProvider ("charfilter" , charFilters , charFilter , currentSettings .get ("type" ));
193+ } else {
194+ return prebuiltAnalysis .charFilterFactories .get (charFilter );
195+ }
196+ }
197+
147198 private static <T > AnalysisModule .AnalysisProvider <T > requriesAnalysisSettings (AnalysisModule .AnalysisProvider <T > provider ) {
148199 return new AnalysisModule .AnalysisProvider <T >() {
149200 @ Override
@@ -185,13 +236,7 @@ private <T> Map<String, T> buildMapping(boolean analyzer, String toBuild, IndexS
185236 }
186237 factories .put (name , factory );
187238 } else {
188- if (typeName == null ) {
189- throw new IllegalArgumentException (toBuild + " [" + name + "] must specify either an analyzer type, or a tokenizer" );
190- }
191- AnalysisModule .AnalysisProvider <T > type = providerMap .get (typeName );
192- if (type == null ) {
193- throw new IllegalArgumentException ("Unknown " + toBuild + " type [" + typeName + "] for [" + name + "]" );
194- }
239+ AnalysisProvider <T > type = getAnalysisProvider (toBuild , providerMap , name , typeName );
195240 final T factory = type .get (settings , environment , name , currentSettings );
196241 factories .put (name , factory );
197242 }
@@ -232,6 +277,17 @@ private <T> Map<String, T> buildMapping(boolean analyzer, String toBuild, IndexS
232277 return factories ;
233278 }
234279
280+ private <T > AnalysisProvider <T > getAnalysisProvider (String toBuild , Map <String , AnalysisProvider <T >> providerMap , String name , String typeName ) {
281+ if (typeName == null ) {
282+ throw new IllegalArgumentException (toBuild + " [" + name + "] must specify either an analyzer type, or a tokenizer" );
283+ }
284+ AnalysisProvider <T > type = providerMap .get (typeName );
285+ if (type == null ) {
286+ throw new IllegalArgumentException ("Unknown " + toBuild + " type [" + typeName + "] for [" + name + "]" );
287+ }
288+ return type ;
289+ }
290+
235291 private static class PrebuiltAnalysis implements Closeable {
236292
237293 final Map <String , AnalysisModule .AnalysisProvider <AnalyzerProvider <?>>> analyzerProviderFactories ;
0 commit comments