diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java index 2d657205ad4..20e934aa6f0 100644 --- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java +++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java @@ -282,6 +282,14 @@ public class ScaledFloatFieldMapper extends ParametrizedFieldMapper { this.coerceByDefault = builder.coerce.getDefaultValue().value(); } + boolean coerce() { + return coerce.value(); + } + + boolean ignoreMalformed() { + return ignoreMalformed.value(); + } + @Override public ScaledFloatFieldType fieldType() { return (ScaledFloatFieldType) super.fieldType(); diff --git a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeatureFieldMapperTests.java b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeatureFieldMapperTests.java index bb564e6f04d..7f7f71c0067 100644 --- a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeatureFieldMapperTests.java +++ b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeatureFieldMapperTests.java @@ -33,7 +33,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.plugins.Plugin; import org.hamcrest.Matchers; -import org.junit.Before; import java.io.IOException; import java.util.Arrays; @@ -54,12 +53,9 @@ public class RankFeatureFieldMapperTests extends FieldMapperTestCase2 { - a.positiveScoreImpact(true); - b.positiveScoreImpact(false); - }); + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("positive_score_impact", b -> b.field("positive_score_impact", false)); } @Override diff --git a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeaturesFieldMapperTests.java b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeaturesFieldMapperTests.java index 3d1ef2d699f..c0b71cc921b 100644 --- a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeaturesFieldMapperTests.java +++ b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/RankFeaturesFieldMapperTests.java @@ -59,6 +59,11 @@ public class RankFeaturesFieldMapperTests extends FieldMapperTestCase2 { + b.field("type", "scaled_float"); + b.field("scaling_factor", 5.0); + })); + checker.registerConflictCheck("doc_values", b -> b.field("doc_values", false)); + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerConflictCheck("null_value", b -> b.field("null_value", 1)); + checker.registerUpdateCheck(b -> b.field("coerce", false), + m -> assertFalse(((ScaledFloatFieldMapper) m).coerce())); + checker.registerUpdateCheck(b -> b.field("ignore_malformed", true), + m -> assertTrue(((ScaledFloatFieldMapper) m).ignoreMalformed())); + } + public void testExistsQueryDocValuesDisabled() throws IOException { MapperService mapperService = createMapperService(fieldMapping(b -> { minimalMapping(b); diff --git a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/SearchAsYouTypeFieldMapperTests.java b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/SearchAsYouTypeFieldMapperTests.java index ddf4aa01e2d..50a72232355 100644 --- a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/SearchAsYouTypeFieldMapperTests.java +++ b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/SearchAsYouTypeFieldMapperTests.java @@ -34,8 +34,6 @@ import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.SynonymQuery; import org.apache.lucene.search.TermQuery; -import org.apache.lucene.search.similarities.BM25Similarity; -import org.apache.lucene.search.similarities.BooleanSimilarity; import org.apache.lucene.search.spans.FieldMaskingSpanQuery; import org.apache.lucene.search.spans.SpanNearQuery; import org.apache.lucene.search.spans.SpanTermQuery; @@ -55,9 +53,7 @@ import org.elasticsearch.index.query.MatchPhrasePrefixQueryBuilder; import org.elasticsearch.index.query.MatchPhraseQueryBuilder; import org.elasticsearch.index.query.MultiMatchQueryBuilder; import org.elasticsearch.index.query.QueryShardContext; -import org.elasticsearch.index.similarity.SimilarityProvider; import org.elasticsearch.plugins.Plugin; -import org.junit.Before; import java.io.IOException; import java.util.ArrayList; @@ -80,20 +76,53 @@ import static org.hamcrest.core.IsInstanceOf.instanceOf; public class SearchAsYouTypeFieldMapperTests extends FieldMapperTestCase2 { @Override - protected void writeFieldValue(XContentBuilder builder) throws IOException { - builder.value("new york city"); + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("max_shingle_size", b -> b.field("max_shingle_size", 4)); + checker.registerConflictCheck("similarity", b -> b.field("similarity", "boolean")); + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerConflictCheck("analyzer", b -> b.field("analyzer", "keyword")); + checker.registerConflictCheck("index_options", b -> b.field("index_options", "docs")); + checker.registerConflictCheck("term_vector", b -> b.field("term_vector", "yes")); + + // norms can be set from true to false, but not vice versa + checker.registerConflictCheck("norms", + fieldMapping(b -> { + b.field("type", "text"); + b.field("norms", false); + }), + fieldMapping(b -> { + b.field("type", "text"); + b.field("norms", true); + })); + checker.registerUpdateCheck( + b -> { + b.field("type", "search_as_you_type"); + b.field("norms", true); + }, + b -> { + b.field("type", "search_as_you_type"); + b.field("norms", false); + }, + m -> assertFalse(m.fieldType().getTextSearchInfo().hasNorms()) + ); + + checker.registerUpdateCheck(b -> { + b.field("analyzer", "default"); + b.field("search_analyzer", "keyword"); + }, + m -> assertEquals("keyword", m.fieldType().getTextSearchInfo().getSearchAnalyzer().name())); + checker.registerUpdateCheck(b -> { + b.field("analyzer", "default"); + b.field("search_analyzer", "keyword"); + b.field("search_quote_analyzer", "keyword"); + }, + m -> assertEquals("keyword", m.fieldType().getTextSearchInfo().getSearchQuoteAnalyzer().name())); + } - @Before - public void addModifiers() { - addModifier("max_shingle_size", false, (a, b) -> { - a.maxShingleSize(3); - b.maxShingleSize(2); - }); - addModifier("similarity", false, (a, b) -> { - a.similarity(new SimilarityProvider("BM25", new BM25Similarity())); - b.similarity(new SimilarityProvider("boolean", new BooleanSimilarity())); - }); + protected void writeFieldValue(XContentBuilder builder) throws IOException { + builder.value("new york city"); } @Override diff --git a/plugins/analysis-icu/src/main/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapper.java b/plugins/analysis-icu/src/main/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapper.java index 3f54018cef8..7166aa62b5e 100644 --- a/plugins/analysis-icu/src/main/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapper.java +++ b/plugins/analysis-icu/src/main/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapper.java @@ -578,51 +578,51 @@ public class ICUCollationKeywordFieldMapper extends FieldMapper { conflicts.add("mapper [" + name() + "] has different [collator]"); } if (!Objects.equals(rules, icuMergeWith.rules)) { - conflicts.add("Cannot update rules setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [rules] for [" + CONTENT_TYPE + "]"); } if (!Objects.equals(language, icuMergeWith.language)) { - conflicts.add("Cannot update language setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [language] for [" + CONTENT_TYPE + "]"); } if (!Objects.equals(country, icuMergeWith.country)) { - conflicts.add("Cannot update country setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [country] for [" + CONTENT_TYPE + "]"); } if (!Objects.equals(variant, icuMergeWith.variant)) { - conflicts.add("Cannot update variant setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [variant] for [" + CONTENT_TYPE + "]"); } if (!Objects.equals(strength, icuMergeWith.strength)) { - conflicts.add("Cannot update strength setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [strength] for [" + CONTENT_TYPE + "]"); } if (!Objects.equals(decomposition, icuMergeWith.decomposition)) { - conflicts.add("Cannot update decomposition setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [decomposition] for [" + CONTENT_TYPE + "]"); } if (!Objects.equals(alternate, icuMergeWith.alternate)) { - conflicts.add("Cannot update alternate setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [alternate] for [" + CONTENT_TYPE + "]"); } if (caseLevel != icuMergeWith.caseLevel) { - conflicts.add("Cannot update case_level setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [case_level] for [" + CONTENT_TYPE + "]"); } if (!Objects.equals(caseFirst, icuMergeWith.caseFirst)) { - conflicts.add("Cannot update case_first setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [case_first] for [" + CONTENT_TYPE + "]"); } if (numeric != icuMergeWith.numeric) { - conflicts.add("Cannot update numeric setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [numeric] for [" + CONTENT_TYPE + "]"); } if (!Objects.equals(variableTop, icuMergeWith.variableTop)) { - conflicts.add("Cannot update variable_top setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [variable_top] for [" + CONTENT_TYPE + "]"); } if (hiraganaQuaternaryMode != icuMergeWith.hiraganaQuaternaryMode) { - conflicts.add("Cannot update hiragana_quaternary_mode setting for [" + CONTENT_TYPE + "]"); + conflicts.add("Cannot update parameter [hiragana_quaternary_mode] for [" + CONTENT_TYPE + "]"); } this.ignoreAbove = icuMergeWith.ignoreAbove; diff --git a/plugins/analysis-icu/src/test/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapperTests.java b/plugins/analysis-icu/src/test/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapperTests.java index fb31402e8b6..253e954b2c7 100644 --- a/plugins/analysis-icu/src/test/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapperTests.java +++ b/plugins/analysis-icu/src/test/java/org/elasticsearch/index/mapper/ICUCollationKeywordFieldMapperTests.java @@ -34,7 +34,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.plugin.analysis.icu.AnalysisICUPlugin; import org.elasticsearch.plugins.Plugin; -import org.junit.Before; import java.io.IOException; import java.util.Arrays; @@ -63,31 +62,16 @@ public class ICUCollationKeywordFieldMapperTests extends FieldMapperTestCase2 { - a.strength("primary"); - b.strength("secondary"); - }); - addModifier("decomposition", false, (a, b) -> { - a.decomposition("no"); - b.decomposition("canonical"); - }); - addModifier("alternate", false, (a, b) -> { - a.alternate("shifted"); - b.alternate("non-ignorable"); - }); - addBooleanModifier("case_level", false, ICUCollationKeywordFieldMapper.Builder::caseLevel); - addModifier("case_first", false, (a, b) -> { - a.caseFirst("upper"); - a.caseFirst("lower"); - }); - addBooleanModifier("numeric", false, ICUCollationKeywordFieldMapper.Builder::numeric); - addModifier("variable_top", false, (a, b) -> { - a.variableTop(";"); - b.variableTop(":"); - }); - addBooleanModifier("hiragana_quaternary_mode", false, ICUCollationKeywordFieldMapper.Builder::hiraganaQuaternaryMode); + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("strength", b -> b.field("strength", "secondary")); + checker.registerConflictCheck("decomposition", b -> b.field("decomposition", "canonical")); + checker.registerConflictCheck("alternate", b -> b.field("alternate", "non-ignorable")); + checker.registerConflictCheck("case_level", b -> b.field("case_level", true)); + checker.registerConflictCheck("case_first", b -> b.field("case_first", "lower")); + checker.registerConflictCheck("numeric", b -> b.field("numeric", true)); + checker.registerConflictCheck("variable_top", b -> b.field("variable_top", ":")); + checker.registerConflictCheck("hiragana_quaternary_mode", b -> b.field("hiragana_quaternary_mode", true)); } @Override diff --git a/plugins/mapper-murmur3/src/test/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapperTests.java b/plugins/mapper-murmur3/src/test/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapperTests.java index 9212ccceb80..41657c4c16c 100644 --- a/plugins/mapper-murmur3/src/test/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapperTests.java +++ b/plugins/mapper-murmur3/src/test/java/org/elasticsearch/index/mapper/murmur3/Murmur3FieldMapperTests.java @@ -59,6 +59,11 @@ public class Murmur3FieldMapperTests extends FieldMapperTestCase2 b.field("field", "value"))); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/AbstractPointGeometryFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/AbstractPointGeometryFieldMapper.java index 09fe37d3b73..f7079dbf3c5 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/AbstractPointGeometryFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/AbstractPointGeometryFieldMapper.java @@ -134,6 +134,7 @@ public abstract class AbstractPointGeometryFieldMapper extend @Override protected void mergeOptions(FieldMapper other, List conflicts) { + super.mergeOptions(other, conflicts); AbstractPointGeometryFieldMapper gpfm = (AbstractPointGeometryFieldMapper)other; // TODO make this un-updateable if (gpfm.nullValue != null) { diff --git a/server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java index c446eea310d..f2cf6263063 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java @@ -188,6 +188,7 @@ public abstract class AbstractShapeGeometryFieldMapper extend @Override protected final void mergeOptions(FieldMapper other, List conflicts) { + super.mergeOptions(other, conflicts); AbstractShapeGeometryFieldMapper gsfm = (AbstractShapeGeometryFieldMapper)other; if (gsfm.coerce.explicit()) { this.coerce = gsfm.coerce; diff --git a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java index 1c925b2e798..b33a6b75226 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java @@ -137,7 +137,7 @@ public class CompletionFieldMapper extends ParametrizedFieldMapper { b.startArray(n); c.toXContent(b, ToXContent.EMPTY_PARAMS); b.endArray(); - }, ContextMappings::toString); + }, Objects::toString); private final Parameter maxInputLength = Parameter.intParam("max_input_length", true, m -> toType(m).maxInputLength, Defaults.DEFAULT_MAX_INPUT_LENGTH) .addDeprecatedName("max_input_len") @@ -351,6 +351,10 @@ public class CompletionFieldMapper extends ParametrizedFieldMapper { return true; } + int getMaxInputLength() { + return maxInputLength; + } + /** * Parses and indexes inputs * diff --git a/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java index 009d78bec9a..264ce14985e 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java @@ -400,7 +400,7 @@ public abstract class FieldMapper extends Mapper implements Cloneable { conflicts.add("mapper [" + name() + "] has different [norms] values, cannot change from disable to enabled"); } if (fieldType.storeTermVectors() != other.storeTermVectors()) { - conflicts.add("mapper [" + name() + "] has different [store_term_vector] values"); + conflicts.add("mapper [" + name() + "] has different [term_vector] values"); } if (fieldType.storeTermVectorOffsets() != other.storeTermVectorOffsets()) { conflicts.add("mapper [" + name() + "] has different [store_term_vector_offsets] values"); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java index 9077e14eefe..cb6269f32ab 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java @@ -345,6 +345,10 @@ public class IpFieldMapper extends ParametrizedFieldMapper { this.indexCreatedVersion = builder.indexCreatedVersion; } + boolean ignoreMalformed() { + return ignoreMalformed; + } + @Override public IpFieldType fieldType() { return (IpFieldType) super.fieldType(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index eeb0e5d1bdd..53161baa93c 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -92,7 +92,8 @@ public final class KeywordFieldMapper extends ParametrizedFieldMapper { private final Parameter indexOptions = Parameter.restrictedStringParam("index_options", false, m -> toType(m).indexOptions, "docs", "freqs"); private final Parameter hasNorms - = Parameter.boolParam("norms", false, m -> toType(m).fieldType.omitNorms() == false, false); + = Parameter.boolParam("norms", true, m -> toType(m).fieldType.omitNorms() == false, false) + .setMergeValidator((o, n) -> o == n || (o && n == false)); // norms can be updated from 'true' to 'false' but not vv private final Parameter similarity = new Parameter<>("similarity", false, () -> null, (n, c, o) -> TypeParsers.resolveSimilarity(c, n, o), m -> toType(m).similarity) .setSerializer((b, f, v) -> b.field(f, v == null ? null : v.name()), v -> v == null ? null : v.name()) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java index 1cf13522d57..a6dc5fe499f 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java @@ -1014,6 +1014,14 @@ public class NumberFieldMapper extends ParametrizedFieldMapper { this.coerceByDefault = builder.coerce.getDefaultValue().value(); } + boolean coerce() { + return coerce.value(); + } + + boolean ignoreMalformed() { + return ignoreMalformed.value(); + } + @Override public NumberFieldType fieldType() { return (NumberFieldType) super.fieldType(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/ParametrizedFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/ParametrizedFieldMapper.java index c809309e1c4..7d71b4c39cc 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/ParametrizedFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/ParametrizedFieldMapper.java @@ -144,7 +144,6 @@ public abstract class ParametrizedFieldMapper extends FieldMapper { private final Supplier defaultValue; private final TriFunction parser; private final Function initializer; - private final boolean updateable; private boolean acceptsNull = false; private Consumer validator = null; private Serializer serializer = XContentBuilder::field; @@ -169,7 +168,6 @@ public abstract class ParametrizedFieldMapper extends FieldMapper { this.value = null; this.parser = parser; this.initializer = initializer; - this.updateable = updateable; this.mergeValidator = (previous, toMerge) -> updateable || Objects.equals(previous, toMerge); } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java index d727babedf6..7560de357de 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java @@ -274,6 +274,10 @@ public class RangeFieldMapper extends ParametrizedFieldMapper { this.coerceByDefault = builder.coerce.getDefaultValue().value(); } + boolean coerce() { + return coerce.value(); + } + @Override public ParametrizedFieldMapper.Builder getMergeBuilder() { return new Builder(simpleName(), type, coerceByDefault).init(this); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/BinaryFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/BinaryFieldMapperTests.java index 7cd3cadee59..4aec09ede40 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/BinaryFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/BinaryFieldMapperTests.java @@ -47,6 +47,12 @@ public class BinaryFieldMapperTests extends MapperTestCase { b.field("type", "binary"); } + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("doc_values", b -> b.field("doc_values", true)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + } + public void testExistsQueryDocValuesEnabled() throws IOException { MapperService mapperService = createMapperService(fieldMapping(b -> { minimalMapping(b); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java index 45c1a46781d..35da8f4ffc5 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java @@ -58,6 +58,14 @@ public class BooleanFieldMapperTests extends MapperTestCase { assertWarnings("Parameter [boost] on field [field] is deprecated and will be removed in 8.0"); } + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("doc_values", b -> b.field("doc_values", false)); + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerConflictCheck("null_value", b -> b.field("null_value", true)); + checker.registerUpdateCheck(b -> b.field("boost", 2.0), m -> assertEquals(m.fieldType().boost(), 2.0, 0)); + } + public void testExistsQueryDocValuesDisabled() throws IOException { MapperService mapperService = createMapperService(fieldMapping(b -> { minimalMapping(b); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java index 1c5f3b97cb1..02f5f39f2d7 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java @@ -87,6 +87,31 @@ public class CompletionFieldMapperTests extends MapperTestCase { b.field("max_input_length", 50); } + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("analyzer", b -> b.field("analyzer", "standard")); + checker.registerConflictCheck("preserve_separators", b -> b.field("preserve_separators", false)); + checker.registerConflictCheck("preserve_position_increments", b -> b.field("preserve_position_increments", false)); + checker.registerConflictCheck("contexts", b -> { + b.startArray("contexts"); + { + b.startObject(); + b.field("name", "place_type"); + b.field("type", "category"); + b.field("path", "cat"); + b.endObject(); + } + b.endArray(); + }); + + checker.registerUpdateCheck(b -> b.field("search_analyzer", "standard"), + m -> assertEquals("standard", m.fieldType().getTextSearchInfo().getSearchAnalyzer().name())); + checker.registerUpdateCheck(b -> b.field("max_input_length", 30), m -> { + CompletionFieldMapper cfm = (CompletionFieldMapper) m; + assertEquals(30, cfm.getMaxInputLength()); + }); + } + @Override protected IndexAnalyzers createIndexAnalyzers(IndexSettings indexSettings) { Map analyzers = new HashMap<>(); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DateFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DateFieldMapperTests.java index e528c89076c..fb4ecafdc2c 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DateFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DateFieldMapperTests.java @@ -54,6 +54,19 @@ public class DateFieldMapperTests extends MapperTestCase { b.field("type", "date"); } + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("doc_values", b -> b.field("doc_values", false)); + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerConflictCheck("format", b -> b.field("format", "yyyy-MM-dd")); + checker.registerConflictCheck("locale", b -> b.field("locale", "es")); + checker.registerConflictCheck("null_value", b -> b.field("null_value", "34500000")); + checker.registerUpdateCheck(b -> b.field("ignore_malformed", true), + m -> assertTrue(((DateFieldMapper)m).getIgnoreMalformed())); + checker.registerUpdateCheck(b -> b.field("boost", 2.0), m -> assertEquals(m.fieldType().boost(), 2.0, 0)); + } + public void testExistsQueryDocValuesDisabled() throws IOException { MapperService mapperService = createMapperService(fieldMapping(b -> { minimalMapping(b); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldMapperTests.java index 9d6248b9f08..d34ef89b096 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/GeoPointFieldMapperTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.Version; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.common.collect.List; import org.elasticsearch.common.geo.GeoPoint; +import org.elasticsearch.common.geo.GeoUtils; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; @@ -57,6 +58,23 @@ public class GeoPointFieldMapperTests extends FieldMapperTestCase2 b.field("ignore_malformed", true), m -> { + GeoPointFieldMapper gpfm = (GeoPointFieldMapper) m; + assertTrue(gpfm.ignoreMalformed.value()); + }); + checker.registerUpdateCheck(b -> b.field("ignore_z_value", false), m -> { + GeoPointFieldMapper gpfm = (GeoPointFieldMapper) m; + assertFalse(gpfm.ignoreZValue.value()); + }); + GeoPoint point = GeoUtils.parseFromString("41.12,-71.34"); + // TODO this should not be updateable! + checker.registerUpdateCheck(b -> b.field("null_value", "41.12,-71.34"), m -> { + GeoPointFieldMapper gpfm = (GeoPointFieldMapper) m; + assertEquals(gpfm.nullValue, point); + }); + } + protected void writeFieldValue(XContentBuilder builder) throws IOException { builder.value(stringEncode(1.3, 1.2)); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java index cbd1456e8a8..535f67d7941 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/GeoShapeFieldMapperTests.java @@ -54,6 +54,26 @@ public class GeoShapeFieldMapperTests extends FieldMapperTestCase2 b.field("orientation", "right"), m -> { + GeoShapeFieldMapper gsfm = (GeoShapeFieldMapper) m; + assertEquals(ShapeBuilder.Orientation.RIGHT, gsfm.orientation()); + }); + checker.registerUpdateCheck(b -> b.field("ignore_malformed", true), m -> { + GeoShapeFieldMapper gpfm = (GeoShapeFieldMapper) m; + assertTrue(gpfm.ignoreMalformed.value()); + }); + checker.registerUpdateCheck(b -> b.field("ignore_z_value", false), m -> { + GeoShapeFieldMapper gpfm = (GeoShapeFieldMapper) m; + assertFalse(gpfm.ignoreZValue.value()); + }); + checker.registerUpdateCheck(b -> b.field("coerce", true), m -> { + GeoShapeFieldMapper gpfm = (GeoShapeFieldMapper) m; + assertTrue(gpfm.coerce.value()); + }); + } + @Before public void addModifiers() { addModifier("orientation", true, (a, b) -> { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/IpFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/IpFieldMapperTests.java index d47ede96917..534849a1f21 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/IpFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/IpFieldMapperTests.java @@ -51,6 +51,16 @@ public class IpFieldMapperTests extends MapperTestCase { b.field("type", "ip"); } + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("doc_values", b -> b.field("doc_values", false)); + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerConflictCheck("null_value", b -> b.field("null_value", "::1")); + checker.registerUpdateCheck(b -> b.field("ignore_malformed", false), + m -> assertFalse(((IpFieldMapper) m).ignoreMalformed())); + } + public void testExistsQueryDocValuesDisabled() throws IOException { MapperService mapperService = createMapperService(fieldMapping(b -> { minimalMapping(b); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java index 7b9a411292a..a0a813538c7 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java @@ -164,6 +164,39 @@ public class KeywordFieldMapperTests extends MapperTestCase { assertWarnings("Parameter [boost] on field [field] is deprecated and will be removed in 8.0"); } + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("doc_values", b -> b.field("doc_values", false)); + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerConflictCheck("index_options", b -> b.field("index_options", "freqs")); + checker.registerConflictCheck("null_value", b -> b.field("null_value", "foo")); + checker.registerConflictCheck("similarity", b -> b.field("similarity", "boolean")); + checker.registerConflictCheck("normalizer", b -> b.field("normalizer", "lowercase")); + + checker.registerUpdateCheck(b -> b.field("eager_global_ordinals", true), + m -> assertTrue(m.fieldType().eagerGlobalOrdinals())); + checker.registerUpdateCheck(b -> b.field("ignore_above", 256), + m -> assertEquals(256, ((KeywordFieldMapper)m).ignoreAbove())); + checker.registerUpdateCheck(b -> b.field("split_queries_on_whitespace", true), + m -> assertEquals("_whitespace", m.fieldType().getTextSearchInfo().getSearchAnalyzer().name())); + + // norms can be set from true to false, but not vice versa + checker.registerConflictCheck("norms", b -> b.field("norms", true)); + checker.registerUpdateCheck( + b -> { + b.field("type", "keyword"); + b.field("norms", true); + }, + b -> { + b.field("type", "keyword"); + b.field("norms", false); + }, + m -> assertFalse(m.fieldType().getTextSearchInfo().hasNorms()) + ); + + checker.registerUpdateCheck(b -> b.field("boost", 2.0), m -> assertEquals(m.fieldType().boost(), 2.0, 0)); + } + public void testDefaults() throws Exception { XContentBuilder mapping = fieldMapping(this::minimalMapping); DocumentMapper mapper = createDocumentMapper(mapping); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapperTests.java index 204e13c98e4..a0b3cea0b27 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapperTests.java @@ -40,7 +40,6 @@ import org.elasticsearch.geometry.Point; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.TestGeoShapeFieldMapperPlugin; -import org.junit.Before; import java.io.IOException; import java.util.Collection; @@ -56,6 +55,7 @@ import static org.hamcrest.Matchers.not; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@SuppressWarnings("deprecation") public class LegacyGeoShapeFieldMapperTests extends FieldMapperTestCase2 { @Override @@ -73,32 +73,42 @@ public class LegacyGeoShapeFieldMapperTests extends FieldMapperTestCase2 { - a.deprecatedParameters.tree = "geohash"; - b.deprecatedParameters.tree = "quadtree"; + @Override + protected void minimalMapping(XContentBuilder b) throws IOException { + b.field("type", "geo_shape").field("strategy", "recursive"); + } + + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + + checker.registerConflictCheck("strategy", + fieldMapping(this::minimalMapping), + fieldMapping(b -> { + b.field("type", "geo_shape"); + b.field("strategy", "term"); + })); + + checker.registerConflictCheck("tree", b -> b.field("tree", "geohash")); + checker.registerConflictCheck("tree_levels", b -> b.field("tree_levels", 5)); + checker.registerConflictCheck("precision", b -> b.field("precision", 10)); + checker.registerUpdateCheck(b -> b.field("orientation", "right"), m -> { + LegacyGeoShapeFieldMapper gsfm = (LegacyGeoShapeFieldMapper) m; + assertEquals(ShapeBuilder.Orientation.RIGHT, gsfm.orientation()); }); - addModifier("strategy", false, (a, b) -> { - a.deprecatedParameters.strategy = SpatialStrategy.TERM; - b.deprecatedParameters.strategy = SpatialStrategy.RECURSIVE; + checker.registerUpdateCheck(b -> b.field("ignore_malformed", true), m -> { + LegacyGeoShapeFieldMapper gpfm = (LegacyGeoShapeFieldMapper) m; + assertTrue(gpfm.ignoreMalformed.value()); }); - addModifier("tree_levels", false, (a, b) -> { - a.deprecatedParameters.treeLevels = 2; - b.deprecatedParameters.treeLevels = 3; + checker.registerUpdateCheck(b -> b.field("ignore_z_value", false), m -> { + LegacyGeoShapeFieldMapper gpfm = (LegacyGeoShapeFieldMapper) m; + assertFalse(gpfm.ignoreZValue.value()); }); - addModifier("precision", false, (a, b) -> { - a.deprecatedParameters.precision = "10"; - b.deprecatedParameters.precision = "20"; - }); - addModifier("distance_error_pct", true, (a, b) -> { - a.deprecatedParameters.distanceErrorPct = 0.5; - b.deprecatedParameters.distanceErrorPct = 0.6; - }); - addModifier("orientation", true, (a, b) -> { - a.orientation = ShapeBuilder.Orientation.RIGHT; - b.orientation = ShapeBuilder.Orientation.LEFT; + checker.registerUpdateCheck(b -> b.field("coerce", true), m -> { + LegacyGeoShapeFieldMapper gpfm = (LegacyGeoShapeFieldMapper) m; + assertTrue(gpfm.coerce.value()); }); + // TODO - distance_error_pct ends up being subsumed into a calculated value, how to test + checker.registerUpdateCheck(b -> b.field("distance_error_pct", 0.8), m -> {}); } @Override @@ -106,11 +116,6 @@ public class LegacyGeoShapeFieldMapperTests extends FieldMapperTestCase2 b.field("doc_values", false)); + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerConflictCheck("null_value", b -> b.field("null_value", 1)); + checker.registerUpdateCheck(b -> b.field("coerce", false), + m -> assertFalse(((NumberFieldMapper) m).coerce())); + checker.registerUpdateCheck(b -> b.field("ignore_malformed", true), + m -> assertTrue(((NumberFieldMapper) m).ignoreMalformed())); + } + protected void writeFieldValue(XContentBuilder builder) throws IOException { builder.value(123); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldMapperTests.java index 630fbee7609..cfa1ba634e9 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldMapperTests.java @@ -99,6 +99,15 @@ public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase { assertWarnings("Parameter [boost] on field [field] is deprecated and will be removed in 8.0"); } + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerConflictCheck("doc_values", b -> b.field("doc_values", false)); + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerUpdateCheck(b -> b.field("coerce", false), + m -> assertFalse(((RangeFieldMapper)m).coerce())); + checker.registerUpdateCheck(b -> b.field("boost", 2.0), m -> assertEquals(m.fieldType().boost(), 2.0, 0)); + } + private Object getFrom(String type) { if (type.equals("date_range")) { return FROM_DATE; diff --git a/server/src/test/java/org/elasticsearch/index/mapper/TextFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/TextFieldMapperTests.java index 10f51516152..13e1e658c41 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/TextFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/TextFieldMapperTests.java @@ -45,8 +45,6 @@ import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.SynonymQuery; import org.apache.lucene.search.TermQuery; -import org.apache.lucene.search.similarities.BM25Similarity; -import org.apache.lucene.search.similarities.BooleanSimilarity; import org.apache.lucene.search.spans.FieldMaskingSpanQuery; import org.apache.lucene.search.spans.SpanNearQuery; import org.apache.lucene.search.spans.SpanOrQuery; @@ -73,8 +71,6 @@ import org.elasticsearch.index.query.MatchPhrasePrefixQueryBuilder; import org.elasticsearch.index.query.MatchPhraseQueryBuilder; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.search.MatchQuery; -import org.elasticsearch.index.similarity.SimilarityProvider; -import org.junit.Before; import java.io.IOException; import java.util.Arrays; @@ -132,36 +128,76 @@ public class TextFieldMapperTests extends FieldMapperTestCase2 { - a.fielddataFrequencyFilter(1, 10, 10); - a.fielddataFrequencyFilter(2, 10, 10); + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerUpdateCheck(b -> b.field("fielddata", true), m -> { + TextFieldType ft = (TextFieldType) m.fieldType(); + assertTrue(ft.fielddata()); }); - addModifier("fielddata_frequency_filter.max", true, (a, b) -> { - a.fielddataFrequencyFilter(1, 10, 10); - a.fielddataFrequencyFilter(1, 12, 10); - }); - addModifier("fielddata_frequency_filter.min_segment_size", true, (a, b) -> { - a.fielddataFrequencyFilter(1, 10, 10); - a.fielddataFrequencyFilter(1, 10, 11); - }); - addModifier("index_phrases", false, (a, b) -> { - a.indexPhrases(true); - b.indexPhrases(false); - }); - addModifier("index_prefixes", false, (a, b) -> { - a.indexPrefixes(2, 4); - }); - addModifier("index_options", false, (a, b) -> { - a.indexOptions(IndexOptions.DOCS_AND_FREQS); - b.indexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS); - }); - addModifier("similarity", false, (a, b) -> { - a.similarity(new SimilarityProvider("BM25", new BM25Similarity())); - b.similarity(new SimilarityProvider("boolean", new BooleanSimilarity())); + checker.registerUpdateCheck(b -> { + b.field("fielddata", true); + b.startObject("fielddata_frequency_filter"); + { + b.field("min", 10); + b.field("max", 20); + b.field("min_segment_size", 100); + } + b.endObject(); + }, m -> { + TextFieldType ft = (TextFieldType) m.fieldType(); + assertEquals(10, ft.fielddataMinFrequency(), 0); + assertEquals(20, ft.fielddataMaxFrequency(), 0); + assertEquals(100, ft.fielddataMinSegmentSize()); }); + checker.registerUpdateCheck(b -> b.field("eager_global_ordinals", "true"), + m -> assertTrue(m.fieldType().eagerGlobalOrdinals())); + checker.registerUpdateCheck(b -> { + b.field("analyzer", "default"); + b.field("search_analyzer", "keyword"); + }, + m -> assertEquals("keyword", m.fieldType().getTextSearchInfo().getSearchAnalyzer().name())); + checker.registerUpdateCheck(b -> { + b.field("analyzer", "default"); + b.field("search_analyzer", "keyword"); + b.field("search_quote_analyzer", "keyword"); + }, + m -> assertEquals("keyword", m.fieldType().getTextSearchInfo().getSearchQuoteAnalyzer().name())); + + + checker.registerConflictCheck("index", b -> b.field("index", false)); + checker.registerConflictCheck("store", b -> b.field("store", true)); + checker.registerConflictCheck("index_phrases", b -> b.field("index_phrases", true)); + checker.registerConflictCheck("index_prefixes", b -> b.startObject("index_prefixes").endObject()); + checker.registerConflictCheck("index_options", b -> b.field("index_options", "docs")); + checker.registerConflictCheck("similarity", b -> b.field("similarity", "boolean")); + checker.registerConflictCheck("analyzer", b -> b.field("analyzer", "keyword")); + checker.registerConflictCheck("term_vector", b -> b.field("term_vector", "yes")); + + // TODO position_increment_gap should not be updateable! + //checker.registerConflictCheck("position_increment_gap", b -> b.field("position_increment_gap", 10)); + + // norms can be set from true to false, but not vice versa + checker.registerConflictCheck("norms", + fieldMapping(b -> { + b.field("type", "text"); + b.field("norms", false); + }), + fieldMapping(b -> { + b.field("type", "text"); + b.field("norms", true); + })); + checker.registerUpdateCheck( + b -> { + b.field("type", "text"); + b.field("norms", true); + }, + b -> { + b.field("type", "text"); + b.field("norms", false); + }, + m -> assertFalse(m.fieldType().getTextSearchInfo().hasNorms()) + ); + } @Override diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java index 34883dc1872..ccbbb7bd957 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.NormsFieldExistsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.apache.lucene.util.SetOnce; +import org.elasticsearch.common.CheckedConsumer; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.ToXContent; @@ -45,9 +46,13 @@ import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SourceLookup; import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.BiFunction; +import java.util.function.Consumer; import java.util.function.Supplier; import static org.hamcrest.Matchers.anyOf; @@ -100,7 +105,7 @@ public abstract class MapperTestCase extends MapperServiceTestCase { protected void assertExistsQuery(MappedFieldType fieldType, Query query, ParseContext.Document fields) { if (fieldType.hasDocValues()) { assertThat(query, instanceOf(DocValuesFieldExistsQuery.class)); - DocValuesFieldExistsQuery fieldExistsQuery = (DocValuesFieldExistsQuery)query; + DocValuesFieldExistsQuery fieldExistsQuery = (DocValuesFieldExistsQuery) query; assertEquals("field", fieldExistsQuery.getField()); assertDocValuesField(fields, "field"); assertNoFieldNamesField(fields); @@ -283,7 +288,9 @@ public abstract class MapperTestCase extends MapperServiceTestCase { throws IOException { BiFunction, IndexFieldData> fieldDataLookup = (mft, lookupSource) -> mft - .fielddataBuilder("test", () -> { throw new UnsupportedOperationException(); }) + .fielddataBuilder("test", () -> { + throw new UnsupportedOperationException(); + }) .build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService(), mapperService); SetOnce> result = new SetOnce<>(); withLuceneIndex(mapperService, iw -> { @@ -299,4 +306,127 @@ public abstract class MapperTestCase extends MapperServiceTestCase { }); return result.get(); } + + private class UpdateCheck { + final XContentBuilder init; + final XContentBuilder update; + final Consumer check; + + private UpdateCheck(CheckedConsumer update, + Consumer check) throws IOException { + this.init = fieldMapping(MapperTestCase.this::minimalMapping); + this.update = fieldMapping(b -> { + minimalMapping(b); + update.accept(b); + }); + this.check = check; + } + + private UpdateCheck(CheckedConsumer init, + CheckedConsumer update, + Consumer check) throws IOException { + this.init = fieldMapping(init); + this.update = fieldMapping(update); + this.check = check; + } + } + + private static class ConflictCheck { + final XContentBuilder init; + final XContentBuilder update; + + private ConflictCheck(XContentBuilder init, XContentBuilder update) { + this.init = init; + this.update = update; + } + } + + public class ParameterChecker { + + List updateChecks = new ArrayList<>(); + Map conflictChecks = new HashMap<>(); + + /** + * Register a check that a parameter can be updated, using the minimal mapping as a base + * + * @param update a field builder applied on top of the minimal mapping + * @param check a check that the updated parameter has been applied to the FieldMapper + */ + public void registerUpdateCheck(CheckedConsumer update, + Consumer check) throws IOException { + updateChecks.add(new UpdateCheck(update, check)); + } + + /** + * Register a check that a parameter can be updated + * + * @param init the initial mapping + * @param update the updated mapping + * @param check a check that the updated parameter has been applied to the FieldMapper + */ + public void registerUpdateCheck(CheckedConsumer init, + CheckedConsumer update, + Consumer check) throws IOException { + updateChecks.add(new UpdateCheck(init, update, check)); + } + + /** + * Register a check that a parameter update will cause a conflict, using the minimal mapping as a base + * + * @param param the parameter name, expected to appear in the error message + * @param update a field builder applied on top of the minimal mapping + */ + public void registerConflictCheck(String param, CheckedConsumer update) throws IOException { + conflictChecks.put(param, new ConflictCheck( + fieldMapping(MapperTestCase.this::minimalMapping), + fieldMapping(b -> { + minimalMapping(b); + update.accept(b); + }) + )); + } + + /** + * Register a check that a parameter update will cause a conflict + * + * @param param the parameter name, expected to appear in the error message + * @param init the initial mapping + * @param update the updated mapping + */ + public void registerConflictCheck(String param, XContentBuilder init, XContentBuilder update) { + conflictChecks.put(param, new ConflictCheck(init, update)); + } + } + + protected abstract void registerParameters(ParameterChecker checker) throws IOException; + + public void testUpdates() throws IOException { + ParameterChecker checker = new ParameterChecker(); + registerParameters(checker); + for (UpdateCheck updateCheck : checker.updateChecks) { + MapperService mapperService = createMapperService(updateCheck.init); + merge(mapperService, updateCheck.update); + FieldMapper mapper = (FieldMapper) mapperService.documentMapper().mappers().getMapper("field"); + updateCheck.check.accept(mapper); + // do it again to ensure that we don't get conflicts the second time + merge(mapperService, updateCheck.update); + mapper = (FieldMapper) mapperService.documentMapper().mappers().getMapper("field"); + updateCheck.check.accept(mapper); + + } + for (String param : checker.conflictChecks.keySet()) { + MapperService mapperService = createMapperService(checker.conflictChecks.get(param).init); + // merging the same change is fine + merge(mapperService, checker.conflictChecks.get(param).init); + // merging the conflicting update should throw an exception + Exception e = expectThrows(IllegalArgumentException.class, + "No conflict when updating parameter [" + param + "]", + () -> merge(mapperService, checker.conflictChecks.get(param).update)); + assertThat(e.getMessage(), anyOf( + containsString("Cannot update parameter [" + param + "]"), + containsString("different [" + param + "]"))); + } + assertParseMaximalWarnings(); + } + } diff --git a/x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapper.java b/x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapper.java index fd2de491e17..1b2ce7bb404 100644 --- a/x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapper.java +++ b/x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapper.java @@ -148,6 +148,10 @@ public class HistogramFieldMapper extends FieldMapper { this.ignoreMalformed = ignoreMalformed; } + boolean ignoreMalformed() { + return ignoreMalformed.value(); + } + @Override protected void mergeOptions(FieldMapper other, List conflicts) { HistogramFieldMapper gpfmMergeWith = (HistogramFieldMapper) other; diff --git a/x-pack/plugin/analytics/src/test/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapperTests.java b/x-pack/plugin/analytics/src/test/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapperTests.java index d875e2c5def..88804d851a4 100644 --- a/x-pack/plugin/analytics/src/test/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapperTests.java +++ b/x-pack/plugin/analytics/src/test/java/org/elasticsearch/xpack/analytics/mapper/HistogramFieldMapperTests.java @@ -51,6 +51,12 @@ public class HistogramFieldMapperTests extends FieldMapperTestCase2 b.field("ignore_malformed", true), + m -> assertTrue(((HistogramFieldMapper)m).ignoreMalformed())); + } + public void testParseValue() throws Exception { DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping)); ParsedDocument doc = mapper.parse( diff --git a/x-pack/plugin/mapper-constant-keyword/src/internalClusterTest/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java b/x-pack/plugin/mapper-constant-keyword/src/internalClusterTest/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java index 1c673a95b8a..43d66578fd1 100644 --- a/x-pack/plugin/mapper-constant-keyword/src/internalClusterTest/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java +++ b/x-pack/plugin/mapper-constant-keyword/src/internalClusterTest/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java @@ -25,6 +25,7 @@ import org.elasticsearch.index.mapper.ValueFetcher; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.lookup.SourceLookup; import org.elasticsearch.xpack.constantkeyword.ConstantKeywordMapperPlugin; +import org.elasticsearch.xpack.constantkeyword.mapper.ConstantKeywordFieldMapper.ConstantKeywordFieldType; import java.io.IOException; import java.util.Collection; @@ -120,8 +121,8 @@ public class ConstantKeywordFieldMapperTests extends MapperTestCase { b.field("type", "constant_keyword"); b.field("value", 74); })); - ConstantKeywordFieldMapper.ConstantKeywordFieldType ft - = (ConstantKeywordFieldMapper.ConstantKeywordFieldType) mapperService.fieldType("field"); + ConstantKeywordFieldType ft + = (ConstantKeywordFieldType) mapperService.fieldType("field"); assertEquals("74", ft.value()); } @@ -145,6 +146,23 @@ public class ConstantKeywordFieldMapperTests extends MapperTestCase { b.field("type", "constant_keyword"); } + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + checker.registerUpdateCheck(b -> b.field("value", "foo"), m -> { + ConstantKeywordFieldType ft = (ConstantKeywordFieldType) m.fieldType(); + assertEquals("foo", ft.value()); + }); + checker.registerConflictCheck("value", + fieldMapping(b -> { + b.field("type", "constant_keyword"); + b.field("value", "foo"); + }), + fieldMapping(b -> { + b.field("type", "constant_keyword"); + b.field("value", "bar"); + })); + } + public void testFetchValue() throws Exception { MapperService mapperService = createMapperService(fieldMapping(b -> b.field("type", "constant_keyword"))); FieldMapper fieldMapper = (FieldMapper) mapperService.documentMapper().mappers().getMapper("field"); diff --git a/x-pack/plugin/mapper-version/src/test/java/org/elasticsearch/xpack/versionfield/VersionStringFieldMapperTests.java b/x-pack/plugin/mapper-version/src/test/java/org/elasticsearch/xpack/versionfield/VersionStringFieldMapperTests.java index e08f8844f72..6270b59c016 100644 --- a/x-pack/plugin/mapper-version/src/test/java/org/elasticsearch/xpack/versionfield/VersionStringFieldMapperTests.java +++ b/x-pack/plugin/mapper-version/src/test/java/org/elasticsearch/xpack/versionfield/VersionStringFieldMapperTests.java @@ -50,6 +50,11 @@ public class VersionStringFieldMapperTests extends MapperTestCase { builder.value("1.2.3"); } + @Override + protected void registerParameters(ParameterChecker checker) throws IOException { + // no configurable parameters + } + public void testDefaults() throws Exception { XContentBuilder mapping = fieldMapping(this::minimalMapping); DocumentMapper mapper = createDocumentMapper(mapping); diff --git a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/RuntimeFieldMapper.java b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/RuntimeFieldMapper.java index c8f5c0e8e6e..c375df1f799 100644 --- a/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/RuntimeFieldMapper.java +++ b/x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/RuntimeFieldMapper.java @@ -60,6 +60,14 @@ public final class RuntimeFieldMapper extends ParametrizedFieldMapper { this.scriptCompiler = scriptCompiler; } + String runtimeType() { + return runtimeType; + } + + Script script() { + return script; + } + @Override public ParametrizedFieldMapper.Builder getMergeBuilder() { return new RuntimeFieldMapper.Builder(simpleName(), scriptCompiler).init(this); diff --git a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/RuntimeFieldMapperTests.java b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/RuntimeFieldMapperTests.java index 8f9ca49d6f2..e732542861f 100644 --- a/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/RuntimeFieldMapperTests.java +++ b/x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/RuntimeFieldMapperTests.java @@ -76,6 +76,11 @@ public class RuntimeFieldMapperTests extends MapperTestCase { b.startObject("script").field("source", "dummy_source").field("lang", "test").endObject(); } + @Override + protected void registerParameters(ParameterChecker checker) { + // TODO need to be able to pass a completely new config rather than updating minimal mapping + } + public void testRuntimeTypeIsRequired() throws Exception { XContentBuilder mapping = XContentFactory.jsonBuilder() .startObject()