Skip to content

Commit f82d74b

Browse files
authored
Move merge compatibility logic from MappedFieldType to FieldMapper (#56915)
Merging logic is currently split between FieldMapper, with its merge() method, and MappedFieldType, which checks for merging compatibility. The compatibility checks are called from a third class, MappingMergeValidator. This makes it difficult to reason about what is or is not compatible in updates, and even what is in fact updateable - we have a number of tests that check compatibility on changes in mapping configuration that are not in fact possible. This commit refactors the compatibility logic so that it all sits on FieldMapper, and makes it called at merge time. It adds a new FieldMapperTestCase base class that FieldMapper tests can extend, and moves the compatibility testing machinery from FieldTypeTestCase to here. Relates to #56814
1 parent 8a086ba commit f82d74b

File tree

117 files changed

+1105
-1282
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+1105
-1282
lines changed

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/RankFeatureFieldMapper.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,6 @@ public int hashCode() {
134134
return h;
135135
}
136136

137-
@Override
138-
public void checkCompatibility(MappedFieldType other, List<String> conflicts) {
139-
super.checkCompatibility(other, conflicts);
140-
if (positiveScoreImpact != ((RankFeatureFieldType) other).positiveScoreImpact()) {
141-
conflicts.add("mapper [" + name() + "] has different [positive_score_impact] values");
142-
}
143-
}
144-
145137
@Override
146138
public String typeName() {
147139
return CONTENT_TYPE;
@@ -230,4 +222,12 @@ protected void doXContentBody(XContentBuilder builder, boolean includeDefaults,
230222
builder.field("positive_score_impact", fieldType().positiveScoreImpact());
231223
}
232224
}
225+
226+
@Override
227+
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
228+
RankFeatureFieldType ft = (RankFeatureFieldType) other.fieldType();
229+
if (fieldType().positiveScoreImpact != ft.positiveScoreImpact()) {
230+
conflicts.add("mapper [" + name() + "] has different [positive_score_impact] values");
231+
}
232+
}
233233
}

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/RankFeaturesFieldMapper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.elasticsearch.index.query.QueryShardContext;
3030

3131
import java.io.IOException;
32+
import java.util.List;
3233
import java.util.Map;
3334

3435
/**
@@ -127,6 +128,11 @@ protected RankFeaturesFieldMapper clone() {
127128
return (RankFeaturesFieldMapper) super.clone();
128129
}
129130

131+
@Override
132+
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
133+
134+
}
135+
130136
@Override
131137
public RankFeaturesFieldType fieldType() {
132138
return (RankFeaturesFieldType) super.fieldType();

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,6 @@ public String typeName() {
213213
return CONTENT_TYPE;
214214
}
215215

216-
@Override
217-
public void checkCompatibility(MappedFieldType other, List<String> conflicts) {
218-
super.checkCompatibility(other, conflicts);
219-
if (scalingFactor != ((ScaledFloatFieldType) other).getScalingFactor()) {
220-
conflicts.add("mapper [" + name() + "] has different [scaling_factor] values");
221-
}
222-
}
223-
224216
@Override
225217
public Query existsQuery(QueryShardContext context) {
226218
if (hasDocValues()) {
@@ -450,14 +442,17 @@ protected void parseCreateField(ParseContext context) throws IOException {
450442
}
451443

452444
@Override
453-
protected void doMerge(Mapper mergeWith) {
454-
super.doMerge(mergeWith);
455-
ScaledFloatFieldMapper other = (ScaledFloatFieldMapper) mergeWith;
456-
if (other.ignoreMalformed.explicit()) {
457-
this.ignoreMalformed = other.ignoreMalformed;
458-
}
459-
if (other.coerce.explicit()) {
460-
this.coerce = other.coerce;
445+
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
446+
ScaledFloatFieldMapper mergeWith = (ScaledFloatFieldMapper) other;
447+
ScaledFloatFieldType ft = (ScaledFloatFieldType) other.fieldType();
448+
if (fieldType().scalingFactor != ft.getScalingFactor()) {
449+
conflicts.add("mapper [" + name() + "] has different [scaling_factor] values");
450+
}
451+
if (mergeWith.ignoreMalformed.explicit()) {
452+
this.ignoreMalformed = mergeWith.ignoreMalformed;
453+
}
454+
if (mergeWith.coerce.explicit()) {
455+
this.coerce = mergeWith.coerce;
461456
}
462457
}
463458

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/SearchAsYouTypeFieldMapper.java

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -343,21 +343,6 @@ public SpanQuery spanPrefixQuery(String value, SpanMultiTermQueryWrapper.SpanRew
343343
}
344344
}
345345

346-
@Override
347-
public void checkCompatibility(MappedFieldType other, List<String> conflicts) {
348-
super.checkCompatibility(other, conflicts);
349-
final SearchAsYouTypeFieldType otherFieldType = (SearchAsYouTypeFieldType) other;
350-
if (this.shingleFields.length != otherFieldType.shingleFields.length) {
351-
conflicts.add("mapper [" + name() + "] has a different [max_shingle_size]");
352-
} else if (Arrays.equals(this.shingleFields, otherFieldType.shingleFields) == false) {
353-
conflicts.add("mapper [" + name() + "] has shingle subfields that are configured differently");
354-
}
355-
356-
if (Objects.equals(this.prefixField, otherFieldType.prefixField) == false) {
357-
conflicts.add("mapper [" + name() + "] has different [index_prefixes] settings");
358-
}
359-
}
360-
361346
@Override
362347
public boolean equals(Object otherObject) {
363348
if (this == otherObject) {
@@ -488,6 +473,11 @@ protected void parseCreateField(ParseContext context) {
488473
throw new UnsupportedOperationException();
489474
}
490475

476+
@Override
477+
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
478+
479+
}
480+
491481
@Override
492482
protected String contentType() {
493483
return "prefix";
@@ -515,6 +505,11 @@ protected void parseCreateField(ParseContext context) {
515505
throw new UnsupportedOperationException();
516506
}
517507

508+
@Override
509+
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
510+
511+
}
512+
518513
@Override
519514
protected String contentType() {
520515
return "shingle";
@@ -613,18 +608,6 @@ public SpanQuery spanPrefixQuery(String value, SpanMultiTermQueryWrapper.SpanRew
613608
}
614609
}
615610

616-
@Override
617-
public void checkCompatibility(MappedFieldType other, List<String> conflicts) {
618-
super.checkCompatibility(other, conflicts);
619-
ShingleFieldType ft = (ShingleFieldType) other;
620-
if (ft.shingleSize != this.shingleSize) {
621-
conflicts.add("mapper [" + name() + "] has different [shingle_size] values");
622-
}
623-
if (Objects.equals(this.prefixFieldType, ft.prefixFieldType) == false) {
624-
conflicts.add("mapper [" + name() + "] has different [index_prefixes] settings");
625-
}
626-
}
627-
628611
@Override
629612
public boolean equals(Object otherObject) {
630613
if (this == otherObject) {
@@ -698,18 +681,15 @@ protected String contentType() {
698681
}
699682

700683
@Override
701-
protected void doMerge(Mapper mergeWith) {
702-
super.doMerge(mergeWith);
703-
SearchAsYouTypeFieldMapper mw = (SearchAsYouTypeFieldMapper) mergeWith;
704-
if (mw.maxShingleSize != maxShingleSize) {
705-
throw new IllegalArgumentException("mapper [" + name() + "] has different [max_shingle_size] setting, current ["
706-
+ this.maxShingleSize + "], merged [" + mw.maxShingleSize + "]");
707-
}
708-
this.prefixField = (PrefixFieldMapper) this.prefixField.merge(mw.prefixField);
709-
710-
ShingleFieldMapper[] shingleFieldMappers = new ShingleFieldMapper[mw.shingleFields.length];
711-
for (int i = 0; i < shingleFieldMappers.length; i++) {
712-
this.shingleFields[i] = (ShingleFieldMapper) this.shingleFields[i].merge(mw.shingleFields[i]);
684+
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
685+
final SearchAsYouTypeFieldMapper m = (SearchAsYouTypeFieldMapper) other;
686+
if (this.shingleFields.length != m.shingleFields.length) {
687+
conflicts.add("mapper [" + name() + "] has a different [max_shingle_size]");
688+
} else {
689+
this.prefixField = (PrefixFieldMapper) this.prefixField.merge(m.prefixField);
690+
for (int i = 0; i < m.shingleFields.length; i++) {
691+
this.shingleFields[i] = (ShingleFieldMapper) this.shingleFields[i].merge(m.shingleFields[i]);
692+
}
713693
}
714694
}
715695

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/TokenCountFieldMapper.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import java.io.IOException;
3131
import java.util.Iterator;
32+
import java.util.List;
3233
import java.util.Map;
3334

3435
import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue;
@@ -200,10 +201,9 @@ protected String contentType() {
200201
}
201202

202203
@Override
203-
protected void doMerge(Mapper mergeWith) {
204-
super.doMerge(mergeWith);
205-
this.analyzer = ((TokenCountFieldMapper) mergeWith).analyzer;
206-
this.enablePositionIncrements = ((TokenCountFieldMapper) mergeWith).enablePositionIncrements;
204+
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
205+
this.analyzer = ((TokenCountFieldMapper) other).analyzer;
206+
this.enablePositionIncrements = ((TokenCountFieldMapper) other).enablePositionIncrements;
207207
}
208208

209209
@Override

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeatureFieldMapperTests.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@
3030
import org.elasticsearch.common.xcontent.XContentType;
3131
import org.elasticsearch.index.IndexService;
3232
import org.elasticsearch.plugins.Plugin;
33-
import org.elasticsearch.test.ESSingleNodeTestCase;
3433
import org.hamcrest.Matchers;
3534
import org.junit.Before;
3635

3736
import java.io.IOException;
3837
import java.util.Arrays;
3938
import java.util.Collection;
4039

41-
public class RankFeatureFieldMapperTests extends ESSingleNodeTestCase {
40+
public class RankFeatureFieldMapperTests extends FieldMapperTestCase<RankFeatureFieldMapper.Builder> {
4241

4342
IndexService indexService;
4443
DocumentMapperParser parser;
@@ -47,6 +46,10 @@ public class RankFeatureFieldMapperTests extends ESSingleNodeTestCase {
4746
public void setup() {
4847
indexService = createIndex("test");
4948
parser = indexService.mapperService().documentMapperParser();
49+
addModifier("positive_score_impact", false, (a, b) -> {
50+
a.fieldType().setPositiveScoreImpact(true);
51+
b.fieldType().setPositiveScoreImpact(false);
52+
});
5053
}
5154

5255
@Override
@@ -63,6 +66,11 @@ static int getFrequency(TokenStream tk) throws IOException {
6366
return freq;
6467
}
6568

69+
@Override
70+
protected RankFeatureFieldMapper.Builder newBuilder() {
71+
return new RankFeatureFieldMapper.Builder("rank-feature");
72+
}
73+
6674
public void testDefaults() throws Exception {
6775
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
6876
.startObject("properties").startObject("field").field("type", "rank_feature").endObject().endObject()
@@ -171,4 +179,5 @@ public void testRejectMultiValuedFields() throws MapperParsingException, IOExcep
171179
assertEquals("[rank_feature] fields do not support indexing multiple values for the same field [foo.field] in the same document",
172180
e.getCause().getMessage());
173181
}
182+
174183
}

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeatureFieldTypeTests.java

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,13 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22-
import org.junit.Before;
23-
24-
public class RankFeatureFieldTypeTests extends FieldTypeTestCase {
22+
public class RankFeatureFieldTypeTests extends FieldTypeTestCase<MappedFieldType> {
2523

2624
@Override
2725
protected MappedFieldType createDefaultFieldType() {
2826
return new RankFeatureFieldMapper.RankFeatureFieldType();
2927
}
3028

31-
@Before
32-
public void setupProperties() {
33-
addModifier(new Modifier("positive_score_impact", false) {
34-
@Override
35-
public void modify(MappedFieldType ft) {
36-
RankFeatureFieldMapper.RankFeatureFieldType tft = (RankFeatureFieldMapper.RankFeatureFieldType)ft;
37-
tft.setPositiveScoreImpact(tft.positiveScoreImpact() == false);
38-
}
39-
@Override
40-
public void normalizeOther(MappedFieldType other) {
41-
super.normalizeOther(other);
42-
((RankFeatureFieldMapper.RankFeatureFieldType) other).setPositiveScoreImpact(true);
43-
}
44-
});
45-
}
46-
4729
public void testIsAggregatable() {
4830
MappedFieldType fieldType = createDefaultFieldType();
4931
assertFalse(fieldType.isAggregatable());

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeatureMetaFieldTypeTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22-
public class RankFeatureMetaFieldTypeTests extends FieldTypeTestCase {
22+
public class RankFeatureMetaFieldTypeTests extends FieldTypeTestCase<MappedFieldType> {
2323

2424
@Override
2525
protected MappedFieldType createDefaultFieldType() {

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeaturesFieldTypeTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22-
public class RankFeaturesFieldTypeTests extends FieldTypeTestCase {
22+
public class RankFeaturesFieldTypeTests extends FieldTypeTestCase<MappedFieldType> {
2323

2424
@Override
2525
protected MappedFieldType createDefaultFieldType() {

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapperTests.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.elasticsearch.index.IndexService;
3030
import org.elasticsearch.index.mapper.MapperService.MergeReason;
3131
import org.elasticsearch.plugins.Plugin;
32-
import org.elasticsearch.test.ESSingleNodeTestCase;
3332
import org.elasticsearch.test.InternalSettingsPlugin;
3433
import org.junit.Before;
3534

@@ -41,7 +40,7 @@
4140

4241
import static org.hamcrest.Matchers.containsString;
4342

44-
public class ScaledFloatFieldMapperTests extends ESSingleNodeTestCase {
43+
public class ScaledFloatFieldMapperTests extends FieldMapperTestCase<ScaledFloatFieldMapper.Builder> {
4544

4645
IndexService indexService;
4746
DocumentMapperParser parser;
@@ -50,13 +49,22 @@ public class ScaledFloatFieldMapperTests extends ESSingleNodeTestCase {
5049
public void setup() {
5150
indexService = createIndex("test");
5251
parser = indexService.mapperService().documentMapperParser();
52+
addModifier("scaling_factor", false, (a, b) -> {
53+
a.scalingFactor(10);
54+
b.scalingFactor(100);
55+
});
5356
}
5457

5558
@Override
5659
protected Collection<Class<? extends Plugin>> getPlugins() {
5760
return pluginList(InternalSettingsPlugin.class, MapperExtrasPlugin.class);
5861
}
5962

63+
@Override
64+
protected ScaledFloatFieldMapper.Builder newBuilder() {
65+
return new ScaledFloatFieldMapper.Builder("scaled-float").scalingFactor(1);
66+
}
67+
6068
public void testDefaults() throws Exception {
6169
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
6270
.startObject("properties").startObject("field").field("type", "scaled_float")

modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/ScaledFloatFieldTypeTests.java

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,19 @@
2929
import org.apache.lucene.search.IndexSearcher;
3030
import org.apache.lucene.search.Query;
3131
import org.apache.lucene.store.Directory;
32-
import org.elasticsearch.core.internal.io.IOUtils;
3332
import org.elasticsearch.Version;
3433
import org.elasticsearch.cluster.metadata.IndexMetadata;
3534
import org.elasticsearch.common.settings.Settings;
35+
import org.elasticsearch.core.internal.io.IOUtils;
3636
import org.elasticsearch.index.IndexSettings;
37-
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
3837
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
38+
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
3939
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
40-
import org.junit.Before;
4140

4241
import java.io.IOException;
4342
import java.util.Arrays;
4443

45-
public class ScaledFloatFieldTypeTests extends FieldTypeTestCase {
44+
public class ScaledFloatFieldTypeTests extends FieldTypeTestCase<MappedFieldType> {
4645

4746
@Override
4847
protected MappedFieldType createDefaultFieldType() {
@@ -51,22 +50,6 @@ protected MappedFieldType createDefaultFieldType() {
5150
return ft;
5251
}
5352

54-
@Before
55-
public void setupProperties() {
56-
addModifier(new Modifier("scaling_factor", false) {
57-
@Override
58-
public void modify(MappedFieldType ft) {
59-
ScaledFloatFieldMapper.ScaledFloatFieldType tft = (ScaledFloatFieldMapper.ScaledFloatFieldType)ft;
60-
tft.setScalingFactor(10);
61-
}
62-
@Override
63-
public void normalizeOther(MappedFieldType other) {
64-
super.normalizeOther(other);
65-
((ScaledFloatFieldMapper.ScaledFloatFieldType) other).setScalingFactor(100);
66-
}
67-
});
68-
}
69-
7053
public void testTermQuery() {
7154
ScaledFloatFieldMapper.ScaledFloatFieldType ft = new ScaledFloatFieldMapper.ScaledFloatFieldType();
7255
ft.setName("scaled_float");

0 commit comments

Comments
 (0)