Skip to content

Enforce Completion Context Limit #39075

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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