Skip to content
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

New field mapping flag - allow_multiple_values #80289

Closed
wants to merge 6 commits into from
Closed
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
2 changes: 1 addition & 1 deletion docs/reference/mapping/types.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ as-you-type completion.
=== Arrays
In {es}, arrays do not require a dedicated field data type. Any field can contain
zero or more values by default, however, all values in the array must be of the
same field type. See <<array>>.
same field type. See <<array>> for more detail (including how to reject array values).

[discrete]
[[types-multi-fields]]
Expand Down
11 changes: 11 additions & 0 deletions docs/reference/mapping/types/array.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,14 @@ GET my-index-000001/_search
<3> The second document contains no arrays, but can be indexed into the same fields.
<4> The query looks for `elasticsearch` in the `tags` field, and matches both documents.

.Rejecting documents with arrays
[NOTE]
====================================================

It is possible to reject documents with array values for a field
by using the `allow_multiple_values` setting in the field's index mapping.
The default value for fields is `true`, meaning arrays are accepted.
When this property is set to `false` documents that present arrays instead of single
values are rejected with an error.

====================================================
6 changes: 6 additions & 0 deletions docs/reference/mapping/types/boolean.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ The following parameters are accepted by `boolean` fields:

[horizontal]

`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<doc-values,`doc_values`>>::

Should the field be stored on disk in a column-stride fashion, so that it
Expand Down
6 changes: 6 additions & 0 deletions docs/reference/mapping/types/date.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ The following parameters are accepted by `date` fields:

[horizontal]

`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<doc-values,`doc_values`>>::

Should the field be stored on disk in a column-stride fashion, so that it
Expand Down
6 changes: 6 additions & 0 deletions docs/reference/mapping/types/ip.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ NOTE: You can also store ip ranges in a single field using an <<range,ip_range d

The following parameters are accepted by `ip` fields:

`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<doc-values,`doc_values`>>::

Should the field be stored on disk in a column-stride fashion, so that it
Expand Down
6 changes: 6 additions & 0 deletions docs/reference/mapping/types/keyword.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ include::numeric.asciidoc[tag=map-ids-as-keyword]

The following parameters are accepted by `keyword` fields:

`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<doc-values,`doc_values`>>::

Should the field be stored on disk in a column-stride fashion, so that it
Expand Down
6 changes: 6 additions & 0 deletions docs/reference/mapping/types/numeric.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ the data as both a `keyword` _and_ a numeric data type.

The following parameters are accepted by numeric types:

`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<coerce,`coerce`>>::

Try to convert strings to numbers and truncate fractions for integers.
Expand Down
6 changes: 6 additions & 0 deletions docs/reference/mapping/types/object.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ You are not required to set the field `type` to `object` explicitly, as this is
The following parameters are accepted by `object` fields:

[horizontal]
`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<dynamic,`dynamic`>>::

Whether or not new `properties` should be added dynamically
Expand Down
5 changes: 5 additions & 0 deletions docs/reference/mapping/types/range.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ PUT range_index/_doc/2
The following parameters are accepted by range types:

[horizontal]
`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<coerce,`coerce`>>::

Expand Down
10 changes: 8 additions & 2 deletions docs/reference/mapping/types/version.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The `version` field type is a specialization of the `keyword` field for
handling software version values and to support specialized precedence
rules for them. Precedence is defined following the rules outlined by
https://semver.org/[Semantic Versioning], which for example means that
major, minor and patch version parts are sorted numerically (i.e.
major, minor and patch version parts are sorted numerically (i.e.
"2.1.0" < "2.4.1" < "2.11.2") and pre-release versions are sorted before
release versions (i.e. "1.0.0-alpha" < "1.0.0").

Expand All @@ -30,7 +30,7 @@ PUT my-index-000001

--------------------------------------------------

The field offers the same search capabilities as a regular keyword field. It
The field offers the same search capabilities as a regular keyword field. It
can e.g. be searched for exact matches using `match` or `term` queries and
supports prefix and wildcard searches. The main benefit is that `range` queries
will honor Semver ordering, so a `range` query between "1.0.0" and "1.5.0"
Expand All @@ -56,6 +56,12 @@ The following parameters are accepted by `version` fields:

[horizontal]

`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<mapping-field-meta,`meta`>>::

Metadata about the field.
Expand Down
5 changes: 5 additions & 0 deletions docs/reference/mapping/types/wildcard.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ GET my-index-000001/_search
The following parameters are accepted by `wildcard` fields:

[horizontal]
`allow_multiple_values`::

Should the field permit arrays of values? Accepts `true`
(default) or `false`. When `false`, documents presenting arrays
of values for this field will be rejected with an error.

<<null-value,`null_value`>>::

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ public LegacyGeoShapeFieldMapper(
builder.orientation.get(),
multiFields,
copyTo,
builder.getAllowMultipleValues(),
parser
);
this.indexCreatedVersion = builder.indexCreatedVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ protected List<Parameter<?>> getParameters() {
return Arrays.asList(positiveScoreImpact, meta);
}

@Override
protected boolean supportsAllowMultipleValuesChoice() {
// We don't allow users to redefine if multiple values are allowed - they are never allowed.
return false;
}

@Override
public RankFeatureFieldMapper build(MapperBuilderContext context) {
return new RankFeatureFieldMapper(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ protected List<Parameter<?>> getParameters() {
return List.of(positiveScoreImpact, meta);
}

@Override
protected boolean supportsAllowMultipleValuesChoice() {
// We don't allow users to redefine if multiple values are allowed - they are never allowed.
return false;
}

@Override
public RankFeaturesFieldMapper build(MapperBuilderContext context) {
return new RankFeaturesFieldMapper(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ public static class Builder extends FieldMapper.Builder {

private final Parameter<Map<String, String>> meta = Parameter.metaParam();

@Override
protected boolean supportsAllowMultipleValuesChoice() {
// We don't allow users to redefine if multiple values are allowed - they are always allowed.
return false;
}

public Builder(String name, IndexAnalyzers indexAnalyzers) {
super(name);
this.analyzers = new TextParams.Analyzers(
Expand Down Expand Up @@ -646,7 +652,7 @@ public SearchAsYouTypeFieldMapper(
ShingleFieldMapper[] shingleFields,
Builder builder
) {
super(simpleName, mappedFieldType, indexAnalyzers, MultiFields.empty(), copyTo, false, null);
super(simpleName, mappedFieldType, indexAnalyzers, MultiFields.empty(), copyTo, true, false, null);
this.prefixField = prefixField;
this.shingleFields = shingleFields;
this.maxShingleSize = builder.maxShingleSize.getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ protected List<Parameter<?>> getParameters() {
return Arrays.asList(index, hasDocValues, store, analyzer, nullValue, enablePositionIncrements, meta);
}

@Override
protected boolean supportsAllowMultipleValuesChoice() {
// Disable the default of parsing `allow_multiple_values` setting.
return false;
}

@Override
public TokenCountFieldMapper build(MapperBuilderContext context) {
if (analyzer.getValue() == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ protected List<Parameter<?>> getParameters() {
return Arrays.asList(eagerGlobalOrdinals, relations, meta);
}

@Override
protected boolean supportsAllowMultipleValuesChoice() {
// Disable the default of parsing `allow_multiple_values` setting.
return false;
}

@Override
public ParentJoinFieldMapper build(MapperBuilderContext context) {
checkObjectOrNested(context, name);
Expand Down Expand Up @@ -208,6 +214,7 @@ protected ParentJoinFieldMapper(
boolean eagerGlobalOrdinals,
List<Relations> relations
) {
// TODO pass allowMultipleValues = false here? DocumentParser would then reject any arrays
super(simpleName, mappedFieldType, Lucene.KEYWORD_ANALYZER, MultiFields.empty(), CopyTo.empty());
this.parentIdFields = parentIdFields;
this.eagerGlobalOrdinals = eagerGlobalOrdinals;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,14 @@ protected AnnotatedTextFieldMapper(
CopyTo copyTo,
Builder builder
) {
super(simpleName, mappedFieldType, wrapAnalyzer(builder.analyzers.getIndexAnalyzer()), multiFields, copyTo);
super(
simpleName,
mappedFieldType,
wrapAnalyzer(builder.analyzers.getIndexAnalyzer()),
multiFields,
copyTo,
builder.getAllowMultipleValues()
);
assert fieldType.tokenized();
this.fieldType = fieldType;
this.builder = builder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ protected AbstractGeometryFieldMapper(
Explicit<Boolean> ignoreZValue,
MultiFields multiFields,
CopyTo copyTo,
boolean allowMultipleValues,
Parser<T> parser
) {
super(simpleName, mappedFieldType, indexAnalyzers, multiFields, copyTo, false, null);
super(simpleName, mappedFieldType, indexAnalyzers, multiFields, copyTo, allowMultipleValues, false, null);
this.ignoreMalformed = ignoreMalformed;
this.ignoreZValue = ignoreZValue;
this.parser = parser;
Expand All @@ -138,20 +139,32 @@ protected AbstractGeometryFieldMapper(
Explicit<Boolean> ignoreZValue,
MultiFields multiFields,
CopyTo copyTo,
boolean allowMultipleValues,
Parser<T> parser
) {
this(simpleName, mappedFieldType, Collections.emptyMap(), ignoreMalformed, ignoreZValue, multiFields, copyTo, parser);
this(
simpleName,
mappedFieldType,
Collections.emptyMap(),
ignoreMalformed,
ignoreZValue,
multiFields,
copyTo,
allowMultipleValues,
parser
);
}

protected AbstractGeometryFieldMapper(
String simpleName,
MappedFieldType mappedFieldType,
MultiFields multiFields,
CopyTo copyTo,
boolean allowMultipleValues,
Parser<T> parser,
String onScriptError
) {
super(simpleName, mappedFieldType, Collections.emptyMap(), multiFields, copyTo, true, onScriptError);
super(simpleName, mappedFieldType, Collections.emptyMap(), multiFields, copyTo, allowMultipleValues, true, onScriptError);
this.ignoreMalformed = new Explicit<>(false, true);
this.ignoreZValue = new Explicit<>(false, true);
this.parser = parser;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ protected AbstractPointGeometryFieldMapper(
CopyTo copyTo,
Parser<T> parser
) {
super(simpleName, mappedFieldType, ignoreMalformed, ignoreZValue, multiFields, copyTo, parser);
super(simpleName, mappedFieldType, ignoreMalformed, ignoreZValue, multiFields, copyTo, true, parser);
this.nullValue = nullValue;
}

Expand All @@ -54,7 +54,7 @@ protected AbstractPointGeometryFieldMapper(
Parser<T> parser,
String onScriptError
) {
super(simpleName, mappedFieldType, multiFields, copyTo, parser, onScriptError);
super(simpleName, mappedFieldType, multiFields, copyTo, true, parser, onScriptError);
this.nullValue = null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ protected AbstractShapeGeometryFieldMapper(
Explicit<Orientation> orientation,
MultiFields multiFields,
CopyTo copyTo,
boolean allowMultipleValues,
Parser<T> parser
) {
super(simpleName, mappedFieldType, indexAnalyzers, ignoreMalformed, ignoreZValue, multiFields, copyTo, parser);
super(simpleName, mappedFieldType, indexAnalyzers, ignoreMalformed, ignoreZValue, multiFields, copyTo, allowMultipleValues, parser);
this.coerce = coerce;
this.orientation = orientation;
}
Expand All @@ -85,6 +86,7 @@ protected AbstractShapeGeometryFieldMapper(
Explicit<Orientation> orientation,
MultiFields multiFields,
CopyTo copyTo,
boolean allowMultipleValues,
Parser<T> parser
) {
this(
Expand All @@ -97,6 +99,7 @@ protected AbstractShapeGeometryFieldMapper(
orientation,
multiFields,
copyTo,
allowMultipleValues,
parser
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ protected BinaryFieldMapper(
CopyTo copyTo,
Builder builder
) {
super(simpleName, mappedFieldType, multiFields, copyTo);
super(simpleName, mappedFieldType, multiFields, copyTo, builder.allowMultipleValues);
this.stored = builder.stored.getValue();
this.hasDocValues = builder.hasDocValues.getValue();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ protected BooleanFieldMapper(
Lucene.KEYWORD_ANALYZER,
multiFields,
copyTo,
builder.allowMultipleValues,
builder.script.get() != null,
builder.onScriptError.getValue()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,15 @@ private DateFieldMapper(
Resolution resolution,
Builder builder
) {
super(simpleName, mappedFieldType, multiFields, copyTo, builder.script.get() != null, builder.onScriptError.get());
super(
simpleName,
mappedFieldType,
multiFields,
copyTo,
builder.allowMultipleValues,
builder.script.get() != null,
builder.onScriptError.get()
);
this.store = builder.store.getValue();
this.indexed = builder.index.getValue();
this.hasDocValues = builder.docValues.getValue();
Expand Down
Loading