Skip to content

Commit c1ab821

Browse files
TommyWindjimczi
authored andcommitted
Enforce Completion Context Limit (#38675)
This change adds a limit to the number of completion contexts that a completion field can define. Closes #32741
1 parent d9f924c commit c1ab821

File tree

5 files changed

+72
-1
lines changed

5 files changed

+72
-1
lines changed

docs/reference/migration/migrate_8_0.asciidoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,20 @@ coming[8.0.0]
1313

1414
* <<breaking_80_mappings_changes>>
1515

16+
[float]
17+
=== Indices created before 7.0
18+
19+
Elasticsearch 8.0 can read indices created in version 7.0 or above. An
20+
Elasticsearch 8.0 node will not start in the presence of indices created in a
21+
version of Elasticsearch before 7.0.
22+
23+
[IMPORTANT]
24+
.Reindex indices from Elasticsearch 6.x or before
25+
=========================================
26+
27+
Indices created in Elasticsearch 6.x or before will need to be reindexed with
28+
Elasticsearch 7.x in order to be readable by Elasticsearch 8.x.
29+
30+
=========================================
31+
1632
include::migrate_8_0/mappings.asciidoc[]

docs/reference/migration/migrate_8_0/mappings.asciidoc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,10 @@
77

88
The `nGram` and `edgeNGram` token filter names that have been deprecated since
99
version 6.4 have been removed. Both token filters should be used by their
10-
alternative names `ngram` and `edge_ngram` instead.
10+
alternative names `ngram` and `edge_ngram` instead.
11+
12+
[float]
13+
==== Limiting the number of completion contexts
14+
15+
The number of completion contexts within a single completion field
16+
has been limited to 10.

docs/reference/search/suggesters/context-suggest.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ the field mapping.
1616
NOTE: It is mandatory to provide a context when indexing and querying
1717
a context enabled completion field.
1818

19+
NOTE: The maximum allowed number of completion field context mappings is 10.
20+
1921
The following defines types, each with two context mappings for a completion
2022
field:
2123

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

Lines changed: 25 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,20 @@ 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+
if (context.indexCreatedVersion().onOrAfter(Version.V_8_0_0)) {
423+
throw new IllegalArgumentException(
424+
"Limit of completion field contexts [" + COMPLETION_CONTEXTS_LIMIT + "] has been exceeded");
425+
} else {
426+
deprecationLogger.deprecated("You have defined more than [" + COMPLETION_CONTEXTS_LIMIT + "] completion contexts" +
427+
" in the mapping for index [" + context.indexSettings().get(IndexMetaData.SETTING_INDEX_PROVIDED_NAME) + "]. " +
428+
"The maximum allowed number of completion contexts in a mapping will be limited to " +
429+
"[" + COMPLETION_CONTEXTS_LIMIT + "] starting in version [8.0].");
430+
}
431+
}
432+
}
408433
}
409434

410435
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
@@ -908,6 +908,28 @@ public void testEmptyName() throws IOException {
908908
assertThat(e.getMessage(), containsString("name cannot be empty string"));
909909
}
910910

911+
public void testLimitOfContextMappings() throws Throwable {
912+
final String index = "test";
913+
XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().startObject().startObject("properties")
914+
.startObject("suggest").field("type", "completion").startArray("contexts");
915+
for (int i = 0; i < CompletionFieldMapper.COMPLETION_CONTEXTS_LIMIT + 1; i++) {
916+
mappingBuilder.startObject();
917+
mappingBuilder.field("name", Integer.toString(i));
918+
mappingBuilder.field("type", "category");
919+
mappingBuilder.endObject();
920+
}
921+
922+
mappingBuilder.endArray().endObject().endObject().endObject();
923+
String mappings = Strings.toString(mappingBuilder);
924+
925+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> {
926+
createIndex(index).mapperService().documentMapperParser().parse("type1", new CompressedXContent(mappings));
927+
});
928+
assertTrue(e.getMessage(),
929+
e.getMessage().contains("Limit of completion field contexts [" +
930+
CompletionFieldMapper.COMPLETION_CONTEXTS_LIMIT + "] has been exceeded"));
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)