Skip to content

Commit 199155f

Browse files
authored
Enforce Completion Context Limit (#38675) (#39075)
This change adds a limit to the number of completion contexts that a completion field can define. Closes #32741
1 parent 59e9a0f commit 199155f

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

docs/reference/migration/migrate_7_0/mappings.asciidoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,10 @@ or `quadtree`. This will ensure compatibility with previously created indexes.
7272
The following type parameters are deprecated for the `geo_shape` field type: `tree`,
7373
`precision`, `tree_levels`, `distance_error_pct`, `points_only`, and `strategy`. They
7474
will be removed in a future version.
75+
76+
[float]
77+
==== Limiting the number of completion contexts
78+
79+
The maximum allowed number of completion contexts in a mapping will be limited
80+
to 10 in the next major version. Completion fields that define more than 10
81+
contexts in a mapping will log a deprecation warning in this version.

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.elasticsearch.index.mapper;
2020

21+
import org.apache.logging.log4j.LogManager;
2122
import org.apache.lucene.codecs.PostingsFormat;
2223
import org.apache.lucene.index.IndexableField;
2324
import org.apache.lucene.index.Term;
@@ -31,8 +32,10 @@
3132
import org.apache.lucene.search.suggest.document.RegexCompletionQuery;
3233
import org.apache.lucene.search.suggest.document.SuggestField;
3334
import org.elasticsearch.Version;
35+
import org.elasticsearch.cluster.metadata.IndexMetaData;
3436
import org.elasticsearch.common.ParseField;
3537
import org.elasticsearch.common.ParsingException;
38+
import org.elasticsearch.common.logging.DeprecationLogger;
3639
import org.elasticsearch.common.settings.Settings;
3740
import org.elasticsearch.common.unit.Fuzziness;
3841
import org.elasticsearch.common.util.set.Sets;
@@ -85,6 +88,11 @@
8588
public class CompletionFieldMapper extends FieldMapper implements ArrayValueMapperParser {
8689
public static final String CONTENT_TYPE = "completion";
8790

91+
/**
92+
* Maximum allowed number of completion contexts in a mapping.
93+
*/
94+
static final int COMPLETION_CONTEXTS_LIMIT = 10;
95+
8896
public static class Defaults {
8997
public static final MappedFieldType FIELD_TYPE = new CompletionFieldType();
9098
static {
@@ -354,6 +362,8 @@ public static class Builder extends FieldMapper.Builder<Builder, CompletionField
354362
private boolean preserveSeparators = Defaults.DEFAULT_PRESERVE_SEPARATORS;
355363
private boolean preservePositionIncrements = Defaults.DEFAULT_POSITION_INCREMENTS;
356364

365+
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(LogManager.getLogger(Builder.class));
366+
357367
/**
358368
* @param name of the completion field to build
359369
*/
@@ -397,6 +407,7 @@ public Builder preservePositionIncrements(boolean preservePositionIncrements) {
397407

398408
@Override
399409
public CompletionFieldMapper build(BuilderContext context) {
410+
checkCompletionContextsLimit(context);
400411
setupFieldType(context);
401412
CompletionFieldType completionFieldType = (CompletionFieldType) this.fieldType;
402413
completionFieldType.setContextMappings(contextMappings);
@@ -405,6 +416,15 @@ public CompletionFieldMapper build(BuilderContext context) {
405416
return new CompletionFieldMapper(name, this.fieldType, context.indexSettings(),
406417
multiFieldsBuilder.build(this, context), copyTo, maxInputLength);
407418
}
419+
420+
private void checkCompletionContextsLimit(BuilderContext context) {
421+
if (this.contextMappings != null && this.contextMappings.size() > COMPLETION_CONTEXTS_LIMIT) {
422+
deprecationLogger.deprecated("You have defined more than [" + COMPLETION_CONTEXTS_LIMIT + "] completion contexts" +
423+
" in the mapping for index [" + context.indexSettings().get(IndexMetaData.SETTING_INDEX_PROVIDED_NAME) + "]. " +
424+
"The maximum allowed number of completion contexts in a mapping will be limited to " +
425+
"[" + COMPLETION_CONTEXTS_LIMIT + "] starting in version [8.0].");
426+
}
427+
}
408428
}
409429

410430
private int maxInputLength;

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import java.util.function.Function;
5555

5656
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
57+
import static org.elasticsearch.index.mapper.CompletionFieldMapper.COMPLETION_CONTEXTS_LIMIT;
5758
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
5859
import static org.hamcrest.Matchers.arrayWithSize;
5960
import static org.hamcrest.Matchers.containsString;
@@ -908,6 +909,27 @@ public void testEmptyName() throws IOException {
908909
assertThat(e.getMessage(), containsString("name cannot be empty string"));
909910
}
910911

912+
public void testLimitOfContextMappings() throws Throwable {
913+
final String index = "test";
914+
XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().startObject().startObject("properties")
915+
.startObject("suggest").field("type", "completion").startArray("contexts");
916+
for (int i = 0; i < COMPLETION_CONTEXTS_LIMIT + 1; i++) {
917+
mappingBuilder.startObject();
918+
mappingBuilder.field("name", Integer.toString(i));
919+
mappingBuilder.field("type", "category");
920+
mappingBuilder.endObject();
921+
}
922+
923+
mappingBuilder.endArray().endObject().endObject().endObject();
924+
String mappings = Strings.toString(mappingBuilder);
925+
926+
DocumentMapper mapper = createIndex(index).mapperService().documentMapperParser()
927+
.parse("type1", new CompressedXContent(mappings));
928+
assertWarnings("You have defined more than [" + COMPLETION_CONTEXTS_LIMIT + "] completion contexts" +
929+
" in the mapping for index [test]. The maximum allowed number of completion contexts in a mapping will be limited to " +
930+
"[" + COMPLETION_CONTEXTS_LIMIT + "] starting in version [8.0].");
931+
}
932+
911933
private Matcher<IndexableField> suggestField(String value) {
912934
return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)),
913935
Matchers.instanceOf(SuggestField.class));

0 commit comments

Comments
 (0)