diff --git a/docs/reference/migration/migrate_7_0/mappings.asciidoc b/docs/reference/migration/migrate_7_0/mappings.asciidoc index 653dd2fb4ca..bfe80cf100c 100644 --- a/docs/reference/migration/migrate_7_0/mappings.asciidoc +++ b/docs/reference/migration/migrate_7_0/mappings.asciidoc @@ -72,3 +72,10 @@ or `quadtree`. This will ensure compatibility with previously created indexes. The following type parameters are deprecated for the `geo_shape` field type: `tree`, `precision`, `tree_levels`, `distance_error_pct`, `points_only`, and `strategy`. They will be removed in a future version. + +[float] +==== Limiting the number of completion contexts + +The maximum allowed number of completion contexts in a mapping will be limited +to 10 in the next major version. Completion fields that define more than 10 +contexts in a mapping will log a deprecation warning in this version. \ No newline at end of file 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 df6a291372f..df293f3afbf 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java @@ -18,6 +18,7 @@ */ package org.elasticsearch.index.mapper; +import org.apache.logging.log4j.LogManager; import org.apache.lucene.codecs.PostingsFormat; import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.Term; @@ -31,8 +32,10 @@ import org.apache.lucene.search.suggest.document.PrefixCompletionQuery; import org.apache.lucene.search.suggest.document.RegexCompletionQuery; import org.apache.lucene.search.suggest.document.SuggestField; import org.elasticsearch.Version; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParsingException; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.util.set.Sets; @@ -85,6 +88,11 @@ import static org.elasticsearch.index.mapper.TypeParsers.parseMultiField; public class CompletionFieldMapper extends FieldMapper implements ArrayValueMapperParser { public static final String CONTENT_TYPE = "completion"; + /** + * Maximum allowed number of completion contexts in a mapping. + */ + static final int COMPLETION_CONTEXTS_LIMIT = 10; + public static class Defaults { public static final MappedFieldType FIELD_TYPE = new CompletionFieldType(); static { @@ -354,6 +362,8 @@ public class CompletionFieldMapper extends FieldMapper implements ArrayValueMapp private boolean preserveSeparators = Defaults.DEFAULT_PRESERVE_SEPARATORS; private boolean preservePositionIncrements = Defaults.DEFAULT_POSITION_INCREMENTS; + private static final DeprecationLogger deprecationLogger = new DeprecationLogger(LogManager.getLogger(Builder.class)); + /** * @param name of the completion field to build */ @@ -397,6 +407,7 @@ public class CompletionFieldMapper extends FieldMapper implements ArrayValueMapp @Override public CompletionFieldMapper build(BuilderContext context) { + checkCompletionContextsLimit(context); setupFieldType(context); CompletionFieldType completionFieldType = (CompletionFieldType) this.fieldType; completionFieldType.setContextMappings(contextMappings); @@ -405,6 +416,15 @@ public class CompletionFieldMapper extends FieldMapper implements ArrayValueMapp return new CompletionFieldMapper(name, this.fieldType, context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo, maxInputLength); } + + private void checkCompletionContextsLimit(BuilderContext context) { + if (this.contextMappings != null && this.contextMappings.size() > COMPLETION_CONTEXTS_LIMIT) { + deprecationLogger.deprecated("You have defined more than [" + COMPLETION_CONTEXTS_LIMIT + "] completion contexts" + + " in the mapping for index [" + context.indexSettings().get(IndexMetaData.SETTING_INDEX_PROVIDED_NAME) + "]. " + + "The maximum allowed number of completion contexts in a mapping will be limited to " + + "[" + COMPLETION_CONTEXTS_LIMIT + "] starting in version [8.0]."); + } + } } private int maxInputLength; 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 7354af17043..fb7f3cdc4e6 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java @@ -54,6 +54,7 @@ import java.util.Map; import java.util.function.Function; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.elasticsearch.index.mapper.CompletionFieldMapper.COMPLETION_CONTEXTS_LIMIT; import static org.hamcrest.Matchers.arrayContainingInAnyOrder; import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.containsString; @@ -908,6 +909,27 @@ public class CompletionFieldMapperTests extends ESSingleNodeTestCase { assertThat(e.getMessage(), containsString("name cannot be empty string")); } + public void testLimitOfContextMappings() throws Throwable { + final String index = "test"; + XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().startObject().startObject("properties") + .startObject("suggest").field("type", "completion").startArray("contexts"); + for (int i = 0; i < COMPLETION_CONTEXTS_LIMIT + 1; i++) { + mappingBuilder.startObject(); + mappingBuilder.field("name", Integer.toString(i)); + mappingBuilder.field("type", "category"); + mappingBuilder.endObject(); + } + + mappingBuilder.endArray().endObject().endObject().endObject(); + String mappings = Strings.toString(mappingBuilder); + + DocumentMapper mapper = createIndex(index).mapperService().documentMapperParser() + .parse("type1", new CompressedXContent(mappings)); + assertWarnings("You have defined more than [" + COMPLETION_CONTEXTS_LIMIT + "] completion contexts" + + " in the mapping for index [test]. The maximum allowed number of completion contexts in a mapping will be limited to " + + "[" + COMPLETION_CONTEXTS_LIMIT + "] starting in version [8.0]."); + } + private Matcher suggestField(String value) { return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)), Matchers.instanceOf(SuggestField.class));