Skip to content

Commit abb6523

Browse files
author
Christoph Büscher
committed
More tests
1 parent 9aa1f28 commit abb6523

File tree

5 files changed

+143
-19
lines changed

5 files changed

+143
-19
lines changed

server/src/main/java/org/elasticsearch/index/analysis/AnalysisRegistry.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,8 @@ private void processNormalizerFactory(
539539
* the same instance of {@link IndexAnalyzers} is returned. Otherwise, analyzers that are in {@link AnalysisMode#SEARCH_TIME} are tried
540540
* to be reloaded. All other analyzers are reused from the old {@link IndexAnalyzers} instance.
541541
*/
542-
public IndexAnalyzers reloadIndexAnalyzers(IndexAnalyzers indexAnalyzers, IndexSettings indexSettings) throws IOException {
542+
public IndexAnalyzers reloadIndexAnalyzers(IndexAnalyzers indexAnalyzers) throws IOException {
543+
IndexSettings indexSettings = indexAnalyzers.getIndexSettings();
543544
// scan analyzers to collect token filters that we need to reload
544545
Map<String, NamedAnalyzer> oldAnalyzers = indexAnalyzers.getAnalyzers();
545546
List<NamedAnalyzer> analyzers = new ArrayList<>(oldAnalyzers.values());
@@ -578,9 +579,7 @@ public IndexAnalyzers reloadIndexAnalyzers(IndexAnalyzers indexAnalyzers, IndexS
578579

579580
IndexAnalysisProviders analysisProviders = new IndexAnalysisProviders(currentTokenizerFactories, currentCharFilterFactories,
580581
newTokenFilterFactories);
581-
return new IndexAnalyzers(indexSettings, indexAnalyzers.getDefaultIndexAnalyzer(), newDefaultSearchAnalyzer,
582-
newDefaultSearchQuoteAnalyzer, newAnalyzers, indexAnalyzers.getNormalizers(), indexAnalyzers.getWhitespaceNormalizers(),
583-
analysisProviders);
582+
return new IndexAnalyzers(indexAnalyzers, newDefaultSearchAnalyzer, newDefaultSearchQuoteAnalyzer, newAnalyzers, analysisProviders);
584583
}
585584

586585
static Set<String> filtersThatNeedReloading(List<NamedAnalyzer> analyzers) {

server/src/main/java/org/elasticsearch/index/analysis/IndexAnalyzers.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,22 @@ public IndexAnalyzers(IndexSettings indexSettings, NamedAnalyzer defaultIndexAna
7171
this.analysisProviders = analysisProviders;
7272
}
7373

74+
/**
75+
* Partial copy-constructor that keeps references to settings, default index analyzer and normalizers from original
76+
* {@link IndexAnalyzers} passed in but takes other search time analyzers as inputs.
77+
*/
78+
IndexAnalyzers(IndexAnalyzers original, NamedAnalyzer defaultSearchAnalyzer, NamedAnalyzer defaultSearchQuoteAnalyzer,
79+
Map<String, NamedAnalyzer> analyzers, IndexAnalysisProviders analysisProviders) {
80+
super(original.getIndexSettings());
81+
this.defaultIndexAnalyzer = original.defaultIndexAnalyzer;
82+
this.defaultSearchAnalyzer = defaultSearchAnalyzer;
83+
this.defaultSearchQuoteAnalyzer = defaultSearchQuoteAnalyzer;
84+
this.analyzers = unmodifiableMap(new HashMap<>(analyzers));
85+
this.normalizers = original.normalizers;
86+
this.whitespaceNormalizers = original.whitespaceNormalizers;
87+
this.analysisProviders = analysisProviders;
88+
}
89+
7490
/**
7591
* Returns an analyzer mapped to the given name or <code>null</code> if not present
7692
*/
@@ -134,15 +150,15 @@ public NamedAnalyzer getDefaultSearchQuoteAnalyzer() {
134150
return defaultSearchQuoteAnalyzer;
135151
}
136152

137-
public Map<String, TokenizerFactory> getTokenizerFactoryFactories() {
153+
Map<String, TokenizerFactory> getTokenizerFactoryFactories() {
138154
return analysisProviders.tokenizerFactoryFactories;
139155
}
140156

141-
public Map<String, CharFilterFactory> getCharFilterFactoryFactories() {
157+
Map<String, CharFilterFactory> getCharFilterFactoryFactories() {
142158
return analysisProviders.charFilterFactoryFactories;
143159
}
144160

145-
public Map<String, TokenFilterFactory> getTokenFilterFactoryFactories() {
161+
Map<String, TokenFilterFactory> getTokenFilterFactoryFactories() {
146162
return analysisProviders.tokenFilterFactoryFactories;
147163
}
148164

server/src/main/java/org/elasticsearch/index/mapper/MapperService.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -850,14 +850,17 @@ protected Analyzer getWrappedAnalyzer(String fieldName) {
850850

851851
public synchronized void reloadSearchAnalyzers(AnalysisRegistry registry) throws IOException {
852852
logger.info("reloading search analyzers");
853-
854853
// refresh indexAnalyzers and search analyzers
855-
this.indexAnalyzers = registry.reloadIndexAnalyzers(this.indexAnalyzers, indexSettings);
854+
IndexAnalyzers reloadedIndexAnalyzers = registry.reloadIndexAnalyzers(this.indexAnalyzers);
855+
if (indexAnalyzers == reloadedIndexAnalyzers) {
856+
// nothing changed, so we can simply return;
857+
return;
858+
}
859+
this.indexAnalyzers = reloadedIndexAnalyzers;
856860
this.searchAnalyzer = new MapperAnalyzerWrapper(this.indexAnalyzers.getDefaultSearchAnalyzer(), p -> p.searchAnalyzer());
857861
this.searchQuoteAnalyzer = new MapperAnalyzerWrapper(this.indexAnalyzers.getDefaultSearchQuoteAnalyzer(),
858862
p -> p.searchQuoteAnalyzer());
859863

860-
// also reload search time analyzers in MappedFieldTypes
861864
// refresh search time analyzers in MappedFieldTypes
862865
List<MappedFieldType> mftsToRefresh = StreamSupport.stream(fieldTypes.spliterator(), false)
863866
.filter(mft -> (mft.searchAnalyzer() != null && mft.searchAnalyzer().getAnalysisMode() == AnalysisMode.SEARCH_TIME)

server/src/test/java/org/elasticsearch/index/analysis/AnalysisRegistryTests.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -352,14 +352,16 @@ public TokenFilterFactory get(IndexSettings indexSettings, Environment environme
352352
.putList("index.analysis.analyzer.reloadableAnalyzer.filter", "myReloadableFilter").build();
353353
IndexSettings indexSettings = new IndexSettings(IndexMetaData.builder("testIndex").settings(settings).build(), settings);
354354

355+
int initialFilterCreationCount = MyReloadableFilter.constructorCounter.get();
355356
NamedAnalyzer rebuilt = AnalysisRegistry.rebuildIfNecessary(reloadableAnalyzer, indexSettings, testAnalysis.charFilter,
356357
testAnalysis.tokenizer, testAnalysis.tokenFilter);
357358
assertEquals(reloadableAnalyzer.name(), rebuilt.name());
358359
assertNotSame(reloadableAnalyzer, rebuilt);
359360
assertEquals(2, factoryCounter.get()); // once on intialization, once again for reloading
360361
TokenFilterFactory reloadedFactory = ((CustomAnalyzer) rebuilt.analyzer()).tokenFilters()[0];
361362
assertThat(reloadedFactory, instanceOf(MyReloadableFilter.class));
362-
assertEquals(2, MyReloadableFilter.constructorCounter);
363+
// the filter factories should not be used at this poing since the function only re-creates the analyzer
364+
assertEquals(initialFilterCreationCount, MyReloadableFilter.constructorCounter.get());
363365
}
364366

365367
public void testRebuildIndexAnalyzers() throws IOException {
@@ -393,31 +395,33 @@ public TokenFilterFactory get(IndexSettings indexSettings, Environment environme
393395
IndexAnalyzers oldIndexAnalyzers = registry.build(indexSettings);
394396
assertEquals(1, factoryCounter.get());
395397

396-
IndexAnalyzers rebuildAnalyzers = registry.reloadIndexAnalyzers(oldIndexAnalyzers, indexSettings);
398+
IndexAnalyzers rebuildAnalyzers = registry.reloadIndexAnalyzers(oldIndexAnalyzers);
397399
assertNotSame(oldIndexAnalyzers, rebuildAnalyzers);
398400
assertEquals(2, factoryCounter.get());
399401
assertSame(oldIndexAnalyzers.getDefaultIndexAnalyzer(), rebuildAnalyzers.getDefaultIndexAnalyzer());
400402
assertSame(oldIndexAnalyzers.getDefaultSearchAnalyzer(), rebuildAnalyzers.getDefaultSearchAnalyzer());
401403
assertSame(oldIndexAnalyzers.getDefaultSearchQuoteAnalyzer(), rebuildAnalyzers.getDefaultSearchQuoteAnalyzer());
404+
assertSame(oldIndexAnalyzers.getNormalizers(), rebuildAnalyzers.getNormalizers());
405+
assertSame(oldIndexAnalyzers.getWhitespaceNormalizers(), rebuildAnalyzers.getWhitespaceNormalizers());
402406
assertNotSame(oldIndexAnalyzers.getAnalyzers(), rebuildAnalyzers.getAnalyzers());
403407
assertEquals(oldIndexAnalyzers.getAnalyzers().size(), rebuildAnalyzers.getAnalyzers().size());
404408
NamedAnalyzer oldVersion = oldIndexAnalyzers.get("reloadableAnalyzer");
405409
NamedAnalyzer newVersion = rebuildAnalyzers.get("reloadableAnalyzer");
406410
assertNotSame(oldVersion, newVersion);
407411
assertThat(((CustomAnalyzer) oldVersion.analyzer()).tokenFilters()[0], instanceOf(MyReloadableFilter.class));
408-
assertEquals(1, ((MyReloadableFilter) ((CustomAnalyzer) oldVersion.analyzer()).tokenFilters()[0]).generation);
412+
int oldGeneration = ((MyReloadableFilter) ((CustomAnalyzer) oldVersion.analyzer()).tokenFilters()[0]).generation.get();
409413
assertThat(((CustomAnalyzer) newVersion.analyzer()).tokenFilters()[0], instanceOf(MyReloadableFilter.class));
410-
assertEquals(2, ((MyReloadableFilter) ((CustomAnalyzer) newVersion.analyzer()).tokenFilters()[0]).generation);
414+
assertEquals(oldGeneration + 1, ((MyReloadableFilter) ((CustomAnalyzer) newVersion.analyzer()).tokenFilters()[0]).generation.get());
411415
}
412416

413417
static class MyReloadableFilter implements TokenFilterFactory {
414418

415-
static int constructorCounter = 0;
416-
private final int generation;
419+
private static AtomicInteger constructorCounter = new AtomicInteger();
420+
private final AtomicInteger generation;
417421

418422
MyReloadableFilter() {
419-
constructorCounter++;
420-
generation = constructorCounter;
423+
constructorCounter.getAndIncrement();
424+
generation = new AtomicInteger(constructorCounter.get());
421425
}
422426

423427
@Override

server/src/test/java/org/elasticsearch/index/mapper/MapperServiceTests.java

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,39 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22+
import org.apache.lucene.analysis.TokenStream;
2223
import org.elasticsearch.ExceptionsHelper;
24+
import org.elasticsearch.cluster.metadata.IndexMetaData;
2325
import org.elasticsearch.common.Strings;
2426
import org.elasticsearch.common.bytes.BytesReference;
2527
import org.elasticsearch.common.compress.CompressedXContent;
2628
import org.elasticsearch.common.settings.Settings;
2729
import org.elasticsearch.common.xcontent.XContentBuilder;
2830
import org.elasticsearch.common.xcontent.XContentFactory;
2931
import org.elasticsearch.common.xcontent.XContentType;
32+
import org.elasticsearch.env.Environment;
3033
import 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;
3140
import org.elasticsearch.index.mapper.KeywordFieldMapper.KeywordFieldType;
3241
import org.elasticsearch.index.mapper.MapperService.MergeReason;
3342
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType;
3443
import org.elasticsearch.indices.InvalidTypeNameException;
44+
import org.elasticsearch.indices.analysis.AnalysisModule.AnalysisProvider;
45+
import org.elasticsearch.plugins.AnalysisPlugin;
3546
import org.elasticsearch.plugins.Plugin;
3647
import org.elasticsearch.test.ESSingleNodeTestCase;
3748
import org.elasticsearch.test.InternalSettingsPlugin;
3849

3950
import java.io.IOException;
4051
import java.util.Collection;
4152
import java.util.Collections;
53+
import java.util.List;
54+
import java.util.Map;
4255
import java.util.concurrent.ExecutionException;
4356

4457
import 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

Comments
 (0)