Skip to content

Commit

Permalink
Enforce Completion Context Limit (#38675) (#39075)
Browse files Browse the repository at this point in the history
This change adds a limit to the number of completion contexts that a completion field can define.

Closes #32741
  • Loading branch information
jimczi authored Feb 19, 2019
1 parent 59e9a0f commit 199155f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
7 changes: 7 additions & 0 deletions docs/reference/migration/migrate_7_0/mappings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,8 +32,10 @@
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;
Expand Down Expand Up @@ -85,6 +88,11 @@
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 {
Expand Down Expand Up @@ -354,6 +362,8 @@ public static class Builder extends FieldMapper.Builder<Builder, CompletionField
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
*/
Expand Down Expand Up @@ -397,6 +407,7 @@ public Builder preservePositionIncrements(boolean preservePositionIncrements) {

@Override
public CompletionFieldMapper build(BuilderContext context) {
checkCompletionContextsLimit(context);
setupFieldType(context);
CompletionFieldType completionFieldType = (CompletionFieldType) this.fieldType;
completionFieldType.setContextMappings(contextMappings);
Expand All @@ -405,6 +416,15 @@ public CompletionFieldMapper build(BuilderContext context) {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
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;
Expand Down Expand Up @@ -908,6 +909,27 @@ public void testEmptyName() throws IOException {
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<IndexableField> suggestField(String value) {
return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)),
Matchers.instanceOf(SuggestField.class));
Expand Down

0 comments on commit 199155f

Please sign in to comment.