Make MetadataFieldMapper extend ParametrizedFieldMapper (#59847) (#60924)

This commit cuts over all metadata field mappers to parametrized format.
This commit is contained in:
Alan Woodward 2020-08-11 09:02:28 +01:00 committed by GitHub
parent 3e2dfc6eac
commit 54279212cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 502 additions and 958 deletions

View File

@ -33,4 +33,4 @@ PUT tweets
}
}
--------------------------------------------------
// TEST[warning:Index [tweets] uses the deprecated `enabled` setting for `_field_names`. Disabling _field_names is not necessary because it no longer carries a large index overhead. Support for this setting will be removed in a future major version. Please remove it from your mappings and templates.]
// TEST[warning:Disabling _field_names is not necessary because it no longer carries a large index overhead. Support for the `enabled` setting will be removed in a future major version. Please remove it from your mappings and templates.]

View File

@ -45,7 +45,7 @@ public class MapperExtrasPlugin extends Plugin implements MapperPlugin, SearchPl
@Override
public Map<String, TypeParser> getMetadataMappers() {
return Collections.singletonMap(RankFeatureMetaFieldMapper.CONTENT_TYPE, new RankFeatureMetaFieldMapper.TypeParser());
return Collections.singletonMap(RankFeatureMetaFieldMapper.CONTENT_TYPE, RankFeatureMetaFieldMapper.PARSER);
}
@Override

View File

@ -19,16 +19,10 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
/**
* This meta field only exists because rank feature fields index everything into a
@ -41,48 +35,7 @@ public class RankFeatureMetaFieldMapper extends MetadataFieldMapper {
public static final String CONTENT_TYPE = "_feature";
public static class Defaults {
public static final FieldType FIELD_TYPE = new FieldType();
static {
FIELD_TYPE.setIndexOptions(IndexOptions.DOCS_AND_FREQS);
FIELD_TYPE.setTokenized(true);
FIELD_TYPE.setStored(false);
FIELD_TYPE.setOmitNorms(true);
FIELD_TYPE.freeze();
}
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
public Builder() {
super(NAME, Defaults.FIELD_TYPE);
}
@Override
public RankFeatureMetaFieldMapper build(BuilderContext context) {
return new RankFeatureMetaFieldMapper();
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name,
Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
return new Builder();
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
final Settings indexSettings = context.mapperService().getIndexSettings().getSettings();
if (fieldType != null) {
return new RankFeatureMetaFieldMapper();
} else {
return parse(NAME, Collections.emptyMap(), context)
.build(new BuilderContext(indexSettings, new ContentPath(1)));
}
}
}
public static final TypeParser PARSER = new FixedTypeParser(c -> new RankFeatureMetaFieldMapper());
public static final class RankFeatureMetaFieldType extends MappedFieldType {
@ -109,27 +62,23 @@ public class RankFeatureMetaFieldMapper extends MetadataFieldMapper {
}
private RankFeatureMetaFieldMapper() {
super(Defaults.FIELD_TYPE, RankFeatureMetaFieldType.INSTANCE);
super(RankFeatureMetaFieldType.INSTANCE);
}
@Override
public void preParse(ParseContext context) throws IOException {}
public void preParse(ParseContext context) {}
@Override
protected void parseCreateField(ParseContext context) throws IOException {
protected void parseCreateField(ParseContext context) {
throw new AssertionError("Should never be called");
}
@Override
public void postParse(ParseContext context) throws IOException {}
public void postParse(ParseContext context) {}
@Override
protected String contentType() {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -19,88 +19,56 @@
package org.elasticsearch.index.mapper.size;
import org.apache.lucene.document.FieldType;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.mapper.EnabledAttributeMapper;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
import org.elasticsearch.index.mapper.ParametrizedFieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import java.io.IOException;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class SizeFieldMapper extends MetadataFieldMapper {
public static final String NAME = "_size";
public static class Defaults {
public static final EnabledAttributeMapper ENABLED_STATE = EnabledAttributeMapper.UNSET_DISABLED;
public static final FieldType SIZE_FIELD_TYPE = new FieldType();
static {
SIZE_FIELD_TYPE.setStored(true);
SIZE_FIELD_TYPE.freeze();
}
private static SizeFieldMapper toType(FieldMapper in) {
return (SizeFieldMapper) in;
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
public static class Builder extends MetadataFieldMapper.Builder {
protected EnabledAttributeMapper enabledState = EnabledAttributeMapper.UNSET_DISABLED;
private final Parameter<Explicit<Boolean>> enabled
= updateableBoolParam("enabled", m -> toType(m).enabled, false);
private Builder() {
super(NAME, Defaults.SIZE_FIELD_TYPE);
builder = this;
super(NAME);
}
public Builder enabled(EnabledAttributeMapper enabled) {
this.enabledState = enabled;
return builder;
@Override
protected List<Parameter<?>> getParameters() {
return Collections.singletonList(enabled);
}
@Override
public SizeFieldMapper build(BuilderContext context) {
return new SizeFieldMapper(fieldType, enabledState,
new NumberFieldMapper.NumberFieldType(NAME, NumberFieldMapper.NumberType.INTEGER));
return new SizeFieldMapper(enabled.getValue(), new NumberFieldType(NAME, NumberType.INTEGER));
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
Builder builder = new Builder();
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
Object fieldNode = entry.getValue();
if (fieldName.equals("enabled")) {
boolean enabled = XContentMapValues.nodeBooleanValue(fieldNode, name + ".enabled");
builder.enabled(enabled ? EnabledAttributeMapper.ENABLED : EnabledAttributeMapper.DISABLED);
iterator.remove();
}
}
return builder;
}
public static final TypeParser PARSER = new ConfigurableTypeParser(
c -> new SizeFieldMapper(new Explicit<>(false, false), new NumberFieldType(NAME, NumberType.INTEGER)),
c -> new Builder()
);
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return new SizeFieldMapper(Defaults.SIZE_FIELD_TYPE, Defaults.ENABLED_STATE,
new NumberFieldMapper.NumberFieldType(NAME, NumberFieldMapper.NumberType.INTEGER));
}
}
private final Explicit<Boolean> enabled;
private EnabledAttributeMapper enabledState;
private SizeFieldMapper(FieldType fieldType, EnabledAttributeMapper enabled,
MappedFieldType mappedFieldType) {
super(fieldType, mappedFieldType);
this.enabledState = enabled;
private SizeFieldMapper(Explicit<Boolean> enabled, MappedFieldType mappedFieldType) {
super(mappedFieldType);
this.enabled = enabled;
}
@Override
@ -109,7 +77,7 @@ public class SizeFieldMapper extends MetadataFieldMapper {
}
public boolean enabled() {
return this.enabledState.enabled;
return this.enabled.value();
}
@Override
@ -129,37 +97,15 @@ public class SizeFieldMapper extends MetadataFieldMapper {
@Override
protected void parseCreateField(ParseContext context) {
if (!enabledState.enabled) {
if (enabled.value() == false) {
return;
}
final int value = context.sourceToParse().source().length();
boolean indexed = fieldType().isSearchable();
boolean docValued = fieldType().hasDocValues();
boolean stored = fieldType.stored();
context.doc().addAll(NumberFieldMapper.NumberType.INTEGER.createFields(name(), value, indexed, docValued, stored));
context.doc().addAll(NumberType.INTEGER.createFields(name(), value, true, true, true));
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// all are defaults, no need to write it at all
if (!includeDefaults && enabledState == Defaults.ENABLED_STATE) {
return builder;
}
builder.startObject(contentType());
if (includeDefaults || enabledState != Defaults.ENABLED_STATE) {
builder.field("enabled", enabledState.enabled);
}
builder.endObject();
return builder;
}
@Override
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
SizeFieldMapper sizeFieldMapperMergeWith = (SizeFieldMapper) other;
if (sizeFieldMapperMergeWith.enabledState != enabledState && !sizeFieldMapperMergeWith.enabledState.unset()) {
this.enabledState = sizeFieldMapperMergeWith.enabledState;
}
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder().init(this);
}
}

View File

@ -19,18 +19,18 @@
package org.elasticsearch.plugin.mapper;
import java.util.Collections;
import java.util.Map;
import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.size.SizeFieldMapper;
import org.elasticsearch.plugins.MapperPlugin;
import org.elasticsearch.plugins.Plugin;
import java.util.Collections;
import java.util.Map;
public class MapperSizePlugin extends Plugin implements MapperPlugin {
@Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap(SizeFieldMapper.NAME, new SizeFieldMapper.TypeParser());
return Collections.singletonMap(SizeFieldMapper.NAME, SizeFieldMapper.PARSER);
}
}

View File

@ -19,6 +19,8 @@
package org.elasticsearch.common;
import java.util.Objects;
/**
* Holds a value that is either:
* a) set implicitly e.g. through some default value
@ -54,4 +56,18 @@ public class Explicit<T> {
public boolean explicit() {
return this.explicit;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Explicit<?> explicit1 = (Explicit<?>) o;
return explicit == explicit1.explicit &&
Objects.equals(value, explicit1.value);
}
@Override
public int hashCode() {
return Objects.hash(value, explicit);
}
}

View File

@ -23,14 +23,12 @@ import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
/**
* Noop mapper that ensures that mappings created in 6x that explicitly disable the _all field
@ -52,51 +50,37 @@ public class AllFieldMapper extends MetadataFieldMapper {
}
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
private boolean disableExplicit = false;
private static AllFieldMapper toType(FieldMapper in) {
return (AllFieldMapper) in;
}
public Builder(MappedFieldType existing) {
super(NAME, Defaults.FIELD_TYPE);
builder = this;
public static class Builder extends MetadataFieldMapper.Builder {
private final Parameter<Explicit<Boolean>> enabled = updateableBoolParam("enabled", m -> toType(m).enabled, false);
public Builder() {
super(NAME);
}
private Builder setDisableExplicit() {
this.disableExplicit = true;
return this;
@Override
protected List<Parameter<?>> getParameters() {
return Collections.singletonList(enabled);
}
@Override
public AllFieldMapper build(BuilderContext context) {
return new AllFieldMapper(disableExplicit);
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
Builder builder = new Builder(parserContext.mapperService().fieldType(NAME));
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
if (fieldName.equals("enabled")) {
boolean enabled = XContentMapValues.nodeBooleanValue(entry.getValue(), "enabled");
if (enabled) {
throw new IllegalArgumentException("[_all] is disabled in this version.");
}
builder.setDisableExplicit();
iterator.remove();
}
if (enabled.getValue().value()) {
throw new IllegalArgumentException("[_all] is disabled in this version.");
}
return builder;
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return new AllFieldMapper(false);
return new AllFieldMapper(enabled.getValue());
}
}
public static final TypeParser PARSER = new ConfigurableTypeParser(
c -> new AllFieldMapper(new Explicit<>(true, false)),
c -> new Builder()
);
static final class AllFieldType extends StringFieldType {
AllFieldType() {
super(NAME, false, false, TextSearchInfo.NONE, Collections.emptyMap());
@ -113,15 +97,15 @@ public class AllFieldMapper extends MetadataFieldMapper {
}
}
private final boolean disableExplicit;
private final Explicit<Boolean> enabled;
private AllFieldMapper(boolean disableExplicit) {
super(Defaults.FIELD_TYPE, new AllFieldType());
this.disableExplicit = disableExplicit;
private AllFieldMapper(Explicit<Boolean> enabled) {
super(new AllFieldType());
this.enabled = enabled;
}
@Override
public void preParse(ParseContext context) throws IOException {
public void preParse(ParseContext context) {
}
@Override
@ -137,7 +121,6 @@ public class AllFieldMapper extends MetadataFieldMapper {
@Override
protected void parseCreateField(ParseContext context) throws IOException {
// noop mapper
return;
}
@Override
@ -145,16 +128,4 @@ public class AllFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
if (includeDefaults || disableExplicit) {
builder.startObject(CONTENT_TYPE);
if (disableExplicit) {
builder.field("enabled", false);
}
builder.endObject();
}
return builder;
}
}

View File

@ -140,7 +140,7 @@ public class CompletionFieldMapper extends ParametrizedFieldMapper {
b.startArray(n);
c.toXContent(b, ToXContent.EMPTY_PARAMS);
b.endArray();
});
}, ContextMappings::toString);
private final Parameter<Integer> maxInputLength = Parameter.intParam("max_input_length", true,
m -> toType(m).maxInputLength, Defaults.DEFAULT_MAX_INPUT_LENGTH)
.addDeprecatedName("max_input_len")

View File

@ -96,7 +96,7 @@ public class DocumentMapper implements ToXContentFragment {
return this;
}
public Builder put(MetadataFieldMapper.Builder<?> mapper) {
public Builder put(MetadataFieldMapper.Builder mapper) {
MetadataFieldMapper metadataMapper = mapper.build(builderContext);
metadataMappers.put(metadataMapper.getClass(), metadataMapper);
return this;

View File

@ -1,33 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.mapper;
public enum EnabledAttributeMapper {
ENABLED(true), UNSET_ENABLED(true), DISABLED(false), UNSET_DISABLED(false);
public final boolean enabled;
EnabledAttributeMapper(boolean enabled) {
this.enabled = enabled;
}
public boolean unset() {
return this == UNSET_DISABLED || this == UNSET_ENABLED;
}
}

View File

@ -26,10 +26,8 @@ import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.Query;
import org.elasticsearch.Version;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException;
@ -37,7 +35,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A mapper that indexes the field names of a document under <code>_field_names</code>. This mapper is typically useful in order
@ -54,10 +51,15 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
public static final String CONTENT_TYPE = "_field_names";
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder(indexVersionCreated).init(this);
}
public static class Defaults {
public static final String NAME = FieldNamesFieldMapper.NAME;
public static final boolean ENABLED = true;
public static final Explicit<Boolean> ENABLED = new Explicit<>(true, false);
public static final FieldType FIELD_TYPE = new FieldType();
static {
@ -69,69 +71,53 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
}
}
static class Builder extends MetadataFieldMapper.Builder<Builder> {
private boolean enabled = Defaults.ENABLED;
private static FieldNamesFieldMapper toType(FieldMapper in) {
return (FieldNamesFieldMapper) in;
}
Builder() {
super(Defaults.NAME, Defaults.FIELD_TYPE);
public static final String ENABLED_DEPRECATION_MESSAGE =
"Disabling _field_names is not necessary because it no longer carries a large index overhead. Support for the `enabled` " +
"setting will be removed in a future major version. Please remove it from your mappings and templates.";
static class Builder extends MetadataFieldMapper.Builder {
private final Parameter<Explicit<Boolean>> enabled
= updateableBoolParam("enabled", m -> toType(m).enabled, Defaults.ENABLED.value());
private final Version indexVersionCreated;
Builder(Version indexVersionCreated) {
super(Defaults.NAME);
this.indexVersionCreated = indexVersionCreated;
}
Builder enabled(boolean enabled) {
this.enabled = enabled;
return this;
protected List<Parameter<?>> getParameters() {
return Collections.singletonList(enabled);
}
@Override
public FieldNamesFieldMapper build(BuilderContext context) {
FieldNamesFieldType fieldNamesFieldType = new FieldNamesFieldType();
fieldNamesFieldType.setEnabled(enabled);
return new FieldNamesFieldMapper(fieldType, fieldNamesFieldType);
if (enabled.getValue().explicit()) {
deprecationLogger.deprecatedAndMaybeLog("field_names_enabled_parameter", ENABLED_DEPRECATION_MESSAGE);
}
FieldNamesFieldType fieldNamesFieldType = new FieldNamesFieldType(enabled.getValue().value());
return new FieldNamesFieldMapper(enabled.getValue(), indexVersionCreated, fieldNamesFieldType);
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
public static final String ENABLED_DEPRECATION_MESSAGE = "Index [{}] uses the deprecated `enabled` setting for `_field_names`. "
+ "Disabling _field_names is not necessary because it no longer carries a large index overhead. Support for this setting "
+ "will be removed in a future major version. Please remove it from your mappings and templates.";
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
Builder builder = new Builder();
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
Object fieldNode = entry.getValue();
if (fieldName.equals("enabled")) {
String indexName = parserContext.mapperService().index().getName();
deprecationLogger.deprecatedAndMaybeLog("field_names_enabled_parameter", ENABLED_DEPRECATION_MESSAGE, indexName);
builder.enabled(XContentMapValues.nodeBooleanValue(fieldNode, name + ".enabled"));
iterator.remove();
}
}
return builder;
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
final Settings indexSettings = context.mapperService().getIndexSettings().getSettings();
if (fieldType != null) {
return new FieldNamesFieldMapper(Defaults.FIELD_TYPE, fieldType);
} else {
return parse(NAME, Collections.emptyMap(), context)
.build(new BuilderContext(indexSettings, new ContentPath(1)));
}
}
}
public static final TypeParser PARSER = new ConfigurableTypeParser(
c -> new FieldNamesFieldMapper(Defaults.ENABLED, c.indexVersionCreated(), new FieldNamesFieldType(Defaults.ENABLED.value())),
c -> new Builder(c.indexVersionCreated())
);
public static final class FieldNamesFieldType extends TermBasedFieldType {
private boolean enabled = Defaults.ENABLED;
private final boolean enabled;
public FieldNamesFieldType() {
public FieldNamesFieldType(boolean enabled) {
super(Defaults.NAME, true, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
this.enabled = enabled;
}
@Override
@ -139,10 +125,6 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isEnabled() {
return enabled;
}
@ -164,8 +146,13 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
}
}
private FieldNamesFieldMapper(FieldType fieldType, MappedFieldType mappedFieldType) {
super(fieldType, mappedFieldType);
private final Explicit<Boolean> enabled;
private final Version indexVersionCreated;
private FieldNamesFieldMapper(Explicit<Boolean> enabled, Version indexVersionCreated, FieldNamesFieldType mappedFieldType) {
super(mappedFieldType);
this.enabled = enabled;
this.indexVersionCreated = indexVersionCreated;
}
@Override
@ -261,21 +248,4 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
if (includeDefaults == false && fieldType().isEnabled() == Defaults.ENABLED) {
return builder;
}
builder.startObject(NAME);
if (includeDefaults || fieldType().isEnabled() != Defaults.ENABLED) {
builder.field("enabled", fieldType().isEnabled());
}
builder.endObject();
return builder;
}
}

View File

@ -32,7 +32,6 @@ import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
@ -55,7 +54,6 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A mapper for the _id field. It does nothing since _id is neither indexed nor
@ -78,7 +76,6 @@ public class IdFieldMapper extends MetadataFieldMapper {
public static final FieldType FIELD_TYPE = new FieldType();
public static final FieldType NESTED_FIELD_TYPE;
public static final MappedFieldType MAPPED_FIELD_TYPE = new IdFieldType();
static {
FIELD_TYPE.setTokenized(false);
@ -97,18 +94,7 @@ public class IdFieldMapper extends MetadataFieldMapper {
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
throw new MapperParsingException(NAME + " is not configurable");
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return new IdFieldMapper(Defaults.FIELD_TYPE);
}
}
public static final TypeParser PARSER = new FixedTypeParser(c -> new IdFieldMapper());
static final class IdFieldType extends TermBasedFieldType {
@ -263,8 +249,8 @@ public class IdFieldMapper extends MetadataFieldMapper {
};
}
private IdFieldMapper(FieldType fieldType) {
super(fieldType, new IdFieldType());
private IdFieldMapper() {
super(new IdFieldType());
}
@Override
@ -274,10 +260,8 @@ public class IdFieldMapper extends MetadataFieldMapper {
@Override
protected void parseCreateField(ParseContext context) throws IOException {
if (fieldType.indexOptions() != IndexOptions.NONE || fieldType.stored()) {
BytesRef id = Uid.encodeId(context.sourceToParse().id());
context.doc().add(new Field(NAME, id, fieldType));
}
BytesRef id = Uid.encodeId(context.sourceToParse().id());
context.doc().add(new Field(NAME, id, Defaults.FIELD_TYPE));
}
@Override
@ -285,8 +269,4 @@ public class IdFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -24,12 +24,10 @@ import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermRangeQuery;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
/**
* A field mapper that records fields that have been ignored because they were malformed.
@ -54,30 +52,7 @@ public final class IgnoredFieldMapper extends MetadataFieldMapper {
}
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
public Builder() {
super(Defaults.NAME, Defaults.FIELD_TYPE);
}
@Override
public IgnoredFieldMapper build(BuilderContext context) {
return new IgnoredFieldMapper();
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
return new Builder();
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return new IgnoredFieldMapper();
}
}
public static final TypeParser PARSER = new FixedTypeParser(c -> new IgnoredFieldMapper());
public static final class IgnoredFieldType extends StringFieldType {
@ -104,7 +79,7 @@ public final class IgnoredFieldMapper extends MetadataFieldMapper {
}
private IgnoredFieldMapper() {
super(Defaults.FIELD_TYPE, IgnoredFieldType.INSTANCE);
super(IgnoredFieldType.INSTANCE);
}
@Override
@ -124,7 +99,7 @@ public final class IgnoredFieldMapper extends MetadataFieldMapper {
@Override
protected void parseCreateField(ParseContext context) throws IOException {
for (String field : context.getIgnoredFields()) {
context.doc().add(new Field(NAME, field, fieldType));
context.doc().add(new Field(NAME, field, Defaults.FIELD_TYPE));
}
}
@ -133,9 +108,4 @@ public final class IgnoredFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -19,11 +19,8 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
import org.elasticsearch.index.query.QueryShardContext;
@ -31,7 +28,6 @@ import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
public class IndexFieldMapper extends MetadataFieldMapper {
@ -40,44 +36,7 @@ public class IndexFieldMapper extends MetadataFieldMapper {
public static final String CONTENT_TYPE = "_index";
public static class Defaults {
public static final String NAME = IndexFieldMapper.NAME;
public static final FieldType FIELD_TYPE = new FieldType();
static {
FIELD_TYPE.setIndexOptions(IndexOptions.NONE);
FIELD_TYPE.setTokenized(false);
FIELD_TYPE.setStored(false);
FIELD_TYPE.setOmitNorms(true);
FIELD_TYPE.freeze();
}
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
public Builder() {
super(Defaults.NAME, Defaults.FIELD_TYPE);
}
@Override
public IndexFieldMapper build(BuilderContext context) {
return new IndexFieldMapper(fieldType);
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
throw new MapperParsingException(NAME + " is not configurable");
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return new IndexFieldMapper(Defaults.FIELD_TYPE);
}
}
public static final TypeParser PARSER = new FixedTypeParser(c -> new IndexFieldMapper());
static final class IndexFieldType extends ConstantFieldType {
@ -109,8 +68,8 @@ public class IndexFieldMapper extends MetadataFieldMapper {
}
private IndexFieldMapper(FieldType fieldType) {
super(fieldType, IndexFieldType.INSTANCE);
public IndexFieldMapper() {
super(IndexFieldType.INSTANCE);
}
@Override
@ -124,8 +83,4 @@ public class IndexFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -33,6 +33,7 @@ import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData;
@ -72,7 +73,7 @@ public class IpFieldMapper extends ParametrizedFieldMapper {
} else {
b.field(f, InetAddresses.toAddrString(v));
}
});
}, NetworkAddress::format);
private final Parameter<Map<String, String>> meta = Parameter.metaParam();

View File

@ -19,22 +19,24 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.FieldType;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* A mapper for a builtin field containing metadata about a document.
*/
public abstract class MetadataFieldMapper extends FieldMapper {
public abstract class MetadataFieldMapper extends ParametrizedFieldMapper {
public interface TypeParser extends Mapper.TypeParser {
@Override
MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
MetadataFieldMapper.Builder parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException;
/**
@ -48,25 +50,109 @@ public abstract class MetadataFieldMapper extends FieldMapper {
MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext parserContext);
}
@SuppressWarnings("rawtypes")
public abstract static class Builder<T extends Builder<T>> extends FieldMapper.Builder<T> {
public Builder(String name, FieldType fieldType) {
super(name, fieldType);
/**
* Declares an updateable boolean parameter for a metadata field
*
* We need to distinguish between explicit configuration and default value for metadata
* fields, because mapping updates will carry over the previous metadata values if a
* metadata field is not explicitly declared in the update. A standard boolean
* parameter explicitly configured with a default value will not be serialized (as
* we do not serialize default parameters for mapping updates), and as such will be
* ignored by the update merge. Instead, we use an {@link Explicit} object that
* will serialize its value if it has been configured, no matter what the value is.
*/
public static Parameter<Explicit<Boolean>> updateableBoolParam(String name, Function<FieldMapper, Explicit<Boolean>> initializer,
boolean defaultValue) {
Explicit<Boolean> defaultExplicit = new Explicit<>(defaultValue, false);
return new Parameter<>(name, true, () -> defaultExplicit,
(n, c, o) -> new Explicit<>(XContentMapValues.nodeBooleanValue(o), true), initializer)
.setSerializer((b, n, v) -> b.field(n, v.value()), v -> Boolean.toString(v.value()));
}
/**
* A type parser for an unconfigurable metadata field.
*/
public static class FixedTypeParser implements TypeParser {
final Function<ParserContext, MetadataFieldMapper> mapperParser;
public FixedTypeParser(Function<ParserContext, MetadataFieldMapper> mapperParser) {
this.mapperParser = mapperParser;
}
@Override
public T index(boolean index) {
if (index == false) {
throw new IllegalArgumentException("Metadata fields must be indexed");
}
public Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
throw new MapperParsingException(name + " is not configurable");
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType defaultFieldType, ParserContext parserContext) {
return mapperParser.apply(parserContext);
}
}
public static class ConfigurableTypeParser implements TypeParser {
final Function<ParserContext, MetadataFieldMapper> defaultMapperParser;
final Function<ParserContext, Builder> builderFunction;
public ConfigurableTypeParser(Function<ParserContext, MetadataFieldMapper> defaultMapperParser,
Function<ParserContext, Builder> builderFunction) {
this.defaultMapperParser = defaultMapperParser;
this.builderFunction = builderFunction;
}
@Override
public Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
Builder builder = builderFunction.apply(parserContext);
builder.parse(name, parserContext, node);
return builder;
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType defaultFieldType, ParserContext parserContext) {
return defaultMapperParser.apply(parserContext);
}
}
public abstract static class Builder extends ParametrizedFieldMapper.Builder {
protected Builder(String name) {
super(name);
}
boolean isConfigured() {
for (Parameter<?> param : getParameters()) {
if (param.isConfigured()) {
return true;
}
}
return false;
}
@Override
public abstract MetadataFieldMapper build(BuilderContext context);
}
protected MetadataFieldMapper(FieldType fieldType, MappedFieldType mappedFieldType) {
super(mappedFieldType.name(), fieldType, mappedFieldType, MultiFields.empty(), CopyTo.empty());
protected MetadataFieldMapper(MappedFieldType mappedFieldType) {
super(mappedFieldType.name(), mappedFieldType, MultiFields.empty(), CopyTo.empty());
}
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return null; // by default, things can't be configured so we have no builder
}
@Override
public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
MetadataFieldMapper.Builder mergeBuilder = (MetadataFieldMapper.Builder) getMergeBuilder();
if (mergeBuilder == null || mergeBuilder.isConfigured() == false) {
return builder;
}
builder.startObject(simpleName());
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
getMergeBuilder().toXContent(builder, includeDefaults);
return builder.endObject();
}
/**
@ -86,7 +172,4 @@ public abstract class MetadataFieldMapper extends FieldMapper {
throw new UnsupportedOperationException("The " + typeName() + " field is not stored in _source.");
}
@Override
protected void mergeOptions(FieldMapper other, List<String> conflicts) { }
}

View File

@ -89,6 +89,9 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
}
ParametrizedFieldMapper.Builder builder = getMergeBuilder();
if (builder == null) {
return (ParametrizedFieldMapper) mergeWith;
}
Conflicts conflicts = new Conflicts(name());
builder.merge((FieldMapper) mergeWith, conflicts);
conflicts.check();
@ -108,11 +111,6 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
// TODO remove when everything is parametrized
}
@Override
public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return super.toXContent(builder, params);
}
@Override
protected final void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
builder.field("type", contentType());
@ -143,6 +141,7 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
private boolean acceptsNull = false;
private Consumer<T> validator = null;
private Serializer<T> serializer = XContentBuilder::field;
private Function<T, String> conflictSerializer = Object::toString;
private T value;
private boolean isSet;
@ -186,6 +185,10 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
this.value = value;
}
public boolean isConfigured() {
return isSet && Objects.equals(value, defaultValue.get()) == false;
}
/**
* Allows the parameter to accept a {@code null} value
*/
@ -216,8 +219,9 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
/**
* Configure a custom serializer for this parameter
*/
public Parameter<T> setSerializer(Serializer<T> serializer) {
public Parameter<T> setSerializer(Serializer<T> serializer, Function<T, String> conflictSerializer) {
this.serializer = serializer;
this.conflictSerializer = conflictSerializer;
return this;
}
@ -237,15 +241,16 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
private void merge(FieldMapper toMerge, Conflicts conflicts) {
T value = initializer.apply(toMerge);
if (updateable == false && isSet && Objects.equals(this.value, value) == false) {
conflicts.addConflict(name, this.value.toString(), value.toString());
T current = getValue();
if (updateable == false && Objects.equals(current, value) == false) {
conflicts.addConflict(name, conflictSerializer.apply(current), conflictSerializer.apply(value));
} else {
setValue(value);
}
}
private void toXContent(XContentBuilder builder, boolean includeDefaults) throws IOException {
if (includeDefaults || Objects.equals(getValue(), defaultValue.get()) == false) {
if (includeDefaults || isConfigured()) {
serializer.serialize(builder, name, getValue());
}
}
@ -299,6 +304,20 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
(n, c, o) -> XContentMapValues.nodeStringValue(o), initializer);
}
@SuppressWarnings("unchecked")
public static Parameter<List<String>> stringArrayParam(String name, boolean updateable,
Function<FieldMapper, List<String>> initializer, List<String> defaultValue) {
return new Parameter<>(name, updateable, () -> defaultValue,
(n, c, o) -> {
List<Object> values = (List<Object>) o;
List<String> strValues = new ArrayList<>();
for (Object item : values) {
strValues.add(item.toString());
}
return strValues;
}, initializer);
}
/**
* Defines a parameter that takes an analyzer name
* @param name the parameter name
@ -316,7 +335,7 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
throw new IllegalArgumentException("analyzer [" + analyzerName + "] has not been configured in mappings");
}
return a;
}, initializer).setSerializer((b, n, v) -> b.field(n, v.name()));
}, initializer).setSerializer((b, n, v) -> b.field(n, v.name()), NamedAnalyzer::name);
}
/**

View File

@ -26,26 +26,25 @@ import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
public class RoutingFieldMapper extends MetadataFieldMapper {
public static final String NAME = "_routing";
public static final String CONTENT_TYPE = "_routing";
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder().init(this);
}
public static class Defaults {
public static final String NAME = "_routing";
public static final FieldType FIELD_TYPE = new FieldType();
static {
FIELD_TYPE.setIndexOptions(IndexOptions.DOCS);
FIELD_TYPE.setTokenized(false);
@ -57,53 +56,33 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
public static final boolean REQUIRED = false;
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
private static RoutingFieldMapper toType(FieldMapper in) {
return (RoutingFieldMapper) in;
}
private boolean required = Defaults.REQUIRED;
public static class Builder extends MetadataFieldMapper.Builder {
public Builder() {
super(Defaults.NAME, Defaults.FIELD_TYPE);
final Parameter<Boolean> required = Parameter.boolParam("required", false, m -> toType(m).required, Defaults.REQUIRED);
protected Builder() {
super(NAME);
}
public Builder required(boolean required) {
this.required = required;
return builder;
@Override
protected List<Parameter<?>> getParameters() {
return Collections.singletonList(required);
}
@Override
public RoutingFieldMapper build(BuilderContext context) {
return new RoutingFieldMapper(fieldType, required);
return new RoutingFieldMapper(required.getValue());
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
Builder builder = new Builder();
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
Object fieldNode = entry.getValue();
if (fieldName.equals("required")) {
builder.required(XContentMapValues.nodeBooleanValue(fieldNode, name + ".required"));
iterator.remove();
}
}
return builder;
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
final Settings indexSettings = context.mapperService().getIndexSettings().getSettings();
if (fieldType != null) {
return new RoutingFieldMapper(Defaults.FIELD_TYPE, Defaults.REQUIRED);
} else {
return parse(NAME, Collections.emptyMap(), context)
.build(new BuilderContext(indexSettings, new ContentPath(1)));
}
}
}
public static final TypeParser PARSER = new ConfigurableTypeParser(
c -> new RoutingFieldMapper(Defaults.REQUIRED),
c -> new Builder()
);
static final class RoutingFieldType extends StringFieldType {
@ -127,8 +106,8 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
private final boolean required;
private RoutingFieldMapper(FieldType fieldType, boolean required) {
super(fieldType, RoutingFieldType.INSTANCE);
private RoutingFieldMapper(boolean required) {
super(RoutingFieldType.INSTANCE);
this.required = required;
}
@ -152,10 +131,8 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
protected void parseCreateField(ParseContext context) throws IOException {
String routing = context.sourceToParse().routing();
if (routing != null) {
if (fieldType.indexOptions() != IndexOptions.NONE || fieldType.stored()) {
context.doc().add(new Field(fieldType().name(), routing, fieldType));
createFieldNamesField(context);
}
context.doc().add(new Field(fieldType().name(), routing, Defaults.FIELD_TYPE));
createFieldNamesField(context);
}
}
@ -164,19 +141,4 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// if all are defaults, no sense to write it at all
if (!includeDefaults && required == Defaults.REQUIRED) {
return builder;
}
builder.startObject(CONTENT_TYPE);
if (includeDefaults || required != Defaults.REQUIRED) {
builder.field("required", required);
}
builder.endObject();
return builder;
}
}

View File

@ -20,18 +20,14 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.search.DocValuesFieldExistsQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData.NumericType;
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
@ -42,7 +38,6 @@ import org.elasticsearch.index.seqno.SequenceNumbers;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
@ -94,33 +89,12 @@ public class SeqNoFieldMapper extends MetadataFieldMapper {
public static final String PRIMARY_TERM_NAME = "_primary_term";
public static final String TOMBSTONE_NAME = "_tombstone";
public static class Defaults {
public static final String NAME = SeqNoFieldMapper.NAME;
public static final MappedFieldType MAPPED_FIELD_TYPE = new SeqNoFieldType();
public static final FieldType FIELD_TYPE = new FieldType();
static {
FIELD_TYPE.setDocValuesType(DocValuesType.SORTED);
FIELD_TYPE.freeze();
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node, ParserContext parserContext)
throws MapperParsingException {
throw new MapperParsingException(NAME + " is not configurable");
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
final Settings indexSettings = context.mapperService().getIndexSettings().getSettings();
return new SeqNoFieldMapper();
}
}
public static final TypeParser PARSER = new FixedTypeParser(c -> new SeqNoFieldMapper());
static final class SeqNoFieldType extends SimpleMappedFieldType {
private static final SeqNoFieldType INSTANCE = new SeqNoFieldType();
SeqNoFieldType() {
super(NAME, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
@ -202,7 +176,7 @@ public class SeqNoFieldMapper extends MetadataFieldMapper {
}
public SeqNoFieldMapper() {
super(Defaults.FIELD_TYPE, Defaults.MAPPED_FIELD_TYPE);
super(SeqNoFieldType.INSTANCE);
}
@Override
@ -252,9 +226,4 @@ public class SeqNoFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -30,7 +30,6 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
@ -43,7 +42,6 @@ import org.elasticsearch.index.query.QueryShardException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@ -71,78 +69,36 @@ public class SourceFieldMapper extends MetadataFieldMapper {
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
private static SourceFieldMapper toType(FieldMapper in) {
return (SourceFieldMapper) in;
}
private boolean enabled = Defaults.ENABLED;
public static class Builder extends MetadataFieldMapper.Builder {
private String[] includes = null;
private String[] excludes = null;
private final Parameter<Boolean> enabled = Parameter.boolParam("enabled", false, m -> toType(m).enabled, Defaults.ENABLED);
private final Parameter<List<String>> includes
= Parameter.stringArrayParam("includes", false, m -> Arrays.asList(toType(m).includes), Collections.emptyList());
private final Parameter<List<String>> excludes
= Parameter.stringArrayParam("excludes", false, m -> Arrays.asList(toType(m).excludes), Collections.emptyList());
public Builder() {
super(Defaults.NAME, new FieldType(Defaults.FIELD_TYPE));
super(Defaults.NAME);
}
public Builder enabled(boolean enabled) {
this.enabled = enabled;
return this;
}
public Builder includes(String[] includes) {
this.includes = includes;
return this;
}
public Builder excludes(String[] excludes) {
this.excludes = excludes;
return this;
@Override
protected List<Parameter<?>> getParameters() {
return Arrays.asList(enabled, includes, excludes);
}
@Override
public SourceFieldMapper build(BuilderContext context) {
return new SourceFieldMapper(enabled, includes, excludes);
return new SourceFieldMapper(enabled.getValue(),
includes.getValue().toArray(new String[0]),
excludes.getValue().toArray(new String[0]));
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
Builder builder = new Builder();
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
Object fieldNode = entry.getValue();
if (fieldName.equals("enabled")) {
builder.enabled(XContentMapValues.nodeBooleanValue(fieldNode, name + ".enabled"));
iterator.remove();
} else if (fieldName.equals("includes")) {
List<Object> values = (List<Object>) fieldNode;
String[] includes = new String[values.size()];
for (int i = 0; i < includes.length; i++) {
includes[i] = values.get(i).toString();
}
builder.includes(includes);
iterator.remove();
} else if (fieldName.equals("excludes")) {
List<Object> values = (List<Object>) fieldNode;
String[] excludes = new String[values.size()];
for (int i = 0; i < excludes.length; i++) {
excludes[i] = values.get(i).toString();
}
builder.excludes(excludes);
iterator.remove();
}
}
return builder;
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
final Settings indexSettings = context.mapperService().getIndexSettings().getSettings();
return new SourceFieldMapper();
}
}
public static final TypeParser PARSER = new ConfigurableTypeParser(c -> new SourceFieldMapper(), c -> new Builder());
static final class SourceFieldType extends MappedFieldType {
@ -177,32 +133,23 @@ public class SourceFieldMapper extends MetadataFieldMapper {
private final String[] excludes;
private SourceFieldMapper() {
this(Defaults.ENABLED, null, null);
this(Defaults.ENABLED, Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY);
}
private SourceFieldMapper(boolean enabled, String[] includes, String[] excludes) {
super(Defaults.FIELD_TYPE, SourceFieldType.INSTANCE); // Only stored.
super(SourceFieldType.INSTANCE); // Only stored.
this.enabled = enabled;
this.includes = includes;
this.excludes = excludes;
final boolean filtered = CollectionUtils.isEmpty(includes) == false || CollectionUtils.isEmpty(excludes) == false;
this.filter = enabled && filtered && fieldType.stored() ? XContentMapValues.filter(includes, excludes) : null;
this.complete = enabled && includes == null && excludes == null;
this.filter = enabled && filtered ? XContentMapValues.filter(includes, excludes) : null;
this.complete = enabled && CollectionUtils.isEmpty(includes) && CollectionUtils.isEmpty(excludes);
}
public boolean enabled() {
return enabled;
}
public String[] excludes() {
return this.excludes != null ? this.excludes : Strings.EMPTY_ARRAY;
}
public String[] includes() {
return this.includes != null ? this.includes : Strings.EMPTY_ARRAY;
}
public boolean isComplete() {
return complete;
}
@ -238,7 +185,7 @@ public class SourceFieldMapper extends MetadataFieldMapper {
@Nullable
public BytesReference applyFilters(@Nullable BytesReference originalSource, @Nullable XContentType contentType) throws IOException {
if (enabled && fieldType.stored() && originalSource != null) {
if (enabled && originalSource != null) {
// Percolate and tv APIs may not set the source and that is ok, because these APIs will not index any data
if (filter != null) {
// we don't update the context source if we filter, we want to keep it as is...
@ -264,46 +211,7 @@ public class SourceFieldMapper extends MetadataFieldMapper {
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// all are defaults, no need to write it at all
if (!includeDefaults && enabled == Defaults.ENABLED && includes == null && excludes == null) {
return builder;
}
builder.startObject(contentType());
if (includeDefaults || enabled != Defaults.ENABLED) {
builder.field("enabled", enabled);
}
if (includes != null) {
builder.array("includes", includes);
} else if (includeDefaults) {
builder.array("includes", Strings.EMPTY_ARRAY);
}
if (excludes != null) {
builder.array("excludes", excludes);
} else if (includeDefaults) {
builder.array("excludes", Strings.EMPTY_ARRAY);
}
builder.endObject();
return builder;
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder().init(this);
}
@Override
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
SourceFieldMapper sourceMergeWith = (SourceFieldMapper) other;
if (this.enabled != sourceMergeWith.enabled) {
conflicts.add("Cannot update enabled setting for [_source]");
}
if (Arrays.equals(includes(), sourceMergeWith.includes()) == false) {
conflicts.add("Cannot update includes setting for [_source]");
}
if (Arrays.equals(excludes(), sourceMergeWith.excludes()) == false) {
conflicts.add("Cannot update excludes setting for [_source]");
}
}
}

View File

@ -39,8 +39,6 @@ import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
import org.elasticsearch.index.query.QueryShardContext;
@ -52,7 +50,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
@ -64,35 +61,18 @@ public class TypeFieldMapper extends MetadataFieldMapper {
public static final String CONTENT_TYPE = "_type";
public static final TypeParser PARSER = new FixedTypeParser(c -> new TypeFieldMapper());
public static class Defaults {
public static final String NAME = TypeFieldMapper.NAME;
public static final FieldType FIELD_TYPE = new FieldType();
static {
FIELD_TYPE.setIndexOptions(IndexOptions.NONE);
FIELD_TYPE.setTokenized(false);
FIELD_TYPE.setStored(false);
FIELD_TYPE.setOmitNorms(true);
FIELD_TYPE.freeze();
}
public static final FieldType NESTED_FIELD_TYPE = new FieldType();
public static final FieldType NESTED_FIELD_TYPE = new FieldType(FIELD_TYPE);
static {
NESTED_FIELD_TYPE.setIndexOptions(IndexOptions.DOCS);
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
throw new MapperParsingException(NAME + " is not configurable");
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
final IndexSettings indexSettings = context.mapperService().getIndexSettings();
return new TypeFieldMapper(Defaults.FIELD_TYPE);
NESTED_FIELD_TYPE.setTokenized(false);
NESTED_FIELD_TYPE.setStored(false);
NESTED_FIELD_TYPE.setOmitNorms(true);
NESTED_FIELD_TYPE.freeze();
}
}
@ -275,8 +255,8 @@ public class TypeFieldMapper extends MetadataFieldMapper {
}
}
private TypeFieldMapper(FieldType fieldType) {
super(fieldType, new TypeFieldType());
private TypeFieldMapper() {
super(new TypeFieldType());
}
@Override
@ -305,9 +285,4 @@ public class TypeFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -20,20 +20,15 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.search.DocValuesFieldExistsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
/** Mapper for the _version field. */
public class VersionFieldMapper extends MetadataFieldMapper {
@ -41,31 +36,7 @@ public class VersionFieldMapper extends MetadataFieldMapper {
public static final String NAME = "_version";
public static final String CONTENT_TYPE = "_version";
public static class Defaults {
public static final String NAME = VersionFieldMapper.NAME;
public static final FieldType FIELD_TYPE = new FieldType();
public static final MappedFieldType MAPPED_FIELD_TYPE = new VersionFieldType();
static {
FIELD_TYPE.setDocValuesType(DocValuesType.NUMERIC);
FIELD_TYPE.setIndexOptions(IndexOptions.NONE);
FIELD_TYPE.freeze();
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
throw new MapperParsingException(NAME + " is not configurable");
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return new VersionFieldMapper();
}
}
public static final TypeParser PARSER = new FixedTypeParser(c -> new VersionFieldMapper());
static final class VersionFieldType extends MappedFieldType {
@ -92,7 +63,7 @@ public class VersionFieldMapper extends MetadataFieldMapper {
}
private VersionFieldMapper() {
super(Defaults.FIELD_TYPE, Defaults.MAPPED_FIELD_TYPE);
super(VersionFieldType.INSTANCE);
}
@Override
@ -129,9 +100,4 @@ public class VersionFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -153,18 +153,18 @@ public class IndicesModule extends AbstractModule {
// Use a LinkedHashMap for metadataMappers because iteration order matters
builtInMetadataMappers = new LinkedHashMap<>();
// _ignored first so that we always load it, even if only _id is requested
builtInMetadataMappers.put(IgnoredFieldMapper.NAME, new IgnoredFieldMapper.TypeParser());
builtInMetadataMappers.put(IgnoredFieldMapper.NAME, IgnoredFieldMapper.PARSER);
// ID second so it will be the first (if no ignored fields) stored field to load
// (so will benefit from "fields: []" early termination
builtInMetadataMappers.put(IdFieldMapper.NAME, new IdFieldMapper.TypeParser());
builtInMetadataMappers.put(RoutingFieldMapper.NAME, new RoutingFieldMapper.TypeParser());
builtInMetadataMappers.put(IndexFieldMapper.NAME, new IndexFieldMapper.TypeParser());
builtInMetadataMappers.put(SourceFieldMapper.NAME, new SourceFieldMapper.TypeParser());
builtInMetadataMappers.put(TypeFieldMapper.NAME, new TypeFieldMapper.TypeParser());
builtInMetadataMappers.put(VersionFieldMapper.NAME, new VersionFieldMapper.TypeParser());
builtInMetadataMappers.put(SeqNoFieldMapper.NAME, new SeqNoFieldMapper.TypeParser());
builtInMetadataMappers.put(IdFieldMapper.NAME, IdFieldMapper.PARSER);
builtInMetadataMappers.put(RoutingFieldMapper.NAME, RoutingFieldMapper.PARSER);
builtInMetadataMappers.put(IndexFieldMapper.NAME, IndexFieldMapper.PARSER);
builtInMetadataMappers.put(SourceFieldMapper.NAME, SourceFieldMapper.PARSER);
builtInMetadataMappers.put(TypeFieldMapper.NAME, TypeFieldMapper.PARSER);
builtInMetadataMappers.put(VersionFieldMapper.NAME, VersionFieldMapper.PARSER);
builtInMetadataMappers.put(SeqNoFieldMapper.NAME, SeqNoFieldMapper.PARSER);
//_field_names must be added last so that it has a chance to see all the other mappers
builtInMetadataMappers.put(FieldNamesFieldMapper.NAME, new FieldNamesFieldMapper.TypeParser());
builtInMetadataMappers.put(FieldNamesFieldMapper.NAME, FieldNamesFieldMapper.PARSER);
return Collections.unmodifiableMap(builtInMetadataMappers);
}

View File

@ -48,7 +48,7 @@ public final class MapperRegistry {
this.metadataMapperParsers = Collections.unmodifiableMap(new LinkedHashMap<>(metadataMapperParsers));
// add the _all field mapper for indices created in 6x
Map<String, MetadataFieldMapper.TypeParser> metadata6x = new LinkedHashMap<>();
metadata6x.put(AllFieldMapper.NAME, new AllFieldMapper.TypeParser());
metadata6x.put(AllFieldMapper.NAME, AllFieldMapper.PARSER);
metadata6x.putAll(metadataMapperParsers);
this.metadataMapperParsers6x = Collections.unmodifiableMap(metadata6x);
this.fieldFilter = fieldFilter;

View File

@ -43,6 +43,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static org.elasticsearch.search.suggest.completion.context.ContextMapping.FIELD_NAME;
import static org.elasticsearch.search.suggest.completion.context.ContextMapping.FIELD_TYPE;
@ -297,4 +298,9 @@ public class ContextMappings implements ToXContent, Iterable<ContextMapping<?>>
ContextMappings other = ((ContextMappings) obj);
return contextMappings.equals(other.contextMappings);
}
@Override
public String toString() {
return contextMappings.stream().map(ContextMapping::toString).collect(Collectors.joining(",", "[", "]"));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.cluster.metadata;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.search.Query;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
@ -35,17 +34,18 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.ParametrizedFieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
@ -75,6 +75,7 @@ import java.util.stream.Collectors;
import static java.util.Collections.singletonList;
import static org.elasticsearch.cluster.metadata.MetadataIndexTemplateService.DEFAULT_TIMESTAMP_FIELD;
import static org.elasticsearch.common.settings.Settings.builder;
import static org.elasticsearch.index.mapper.ParametrizedFieldMapper.Parameter;
import static org.elasticsearch.indices.ShardLimitValidatorTests.createTestShardLimitService;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.containsStringIgnoringCase;
@ -1550,75 +1551,77 @@ public class MetadataIndexTemplateServiceTests extends ESSingleNodeTestCase {
@Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap("_data_stream_timestamp", new MetadataFieldMapper.TypeParser() {
return Collections.singletonMap("_data_stream_timestamp", new MetadataFieldMapper.ConfigurableTypeParser(
c -> new MetadataTimestampFieldMapper(false),
c -> new MetadataTimestampFieldBuilder())
);
}
}
private static MetadataTimestampFieldMapper toType(FieldMapper in) {
return (MetadataTimestampFieldMapper) in;
}
public static class MetadataTimestampFieldBuilder extends MetadataFieldMapper.Builder {
private final Parameter<Boolean> enabled = Parameter.boolParam("enabled", true, m -> toType(m).enabled, false);
protected MetadataTimestampFieldBuilder() {
super("_data_stream_timestamp");
}
@Override
protected List<ParametrizedFieldMapper.Parameter<?>> getParameters() {
return Collections.singletonList(enabled);
}
@Override
public MetadataFieldMapper build(Mapper.BuilderContext context) {
return new MetadataTimestampFieldMapper(enabled.getValue());
}
}
public static class MetadataTimestampFieldMapper extends MetadataFieldMapper {
final boolean enabled;
public MetadataTimestampFieldMapper(boolean enabled) {
super(new MappedFieldType("_data_stream_timestamp", false, false, TextSearchInfo.NONE, Collections.emptyMap()) {
@Override
public MetadataFieldMapper.Builder<?> parse(String name,
Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
Boolean enabled = (Boolean) node.remove("enabled");
return new MetadataFieldMapper.Builder(name, new FieldType()) {
@Override
public MetadataFieldMapper build(Mapper.BuilderContext context) {
return newInstance(enabled);
}
};
public String typeName() {
return "_data_stream_timestamp";
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext parserContext) {
return newInstance(null);
public Query termQuery(Object value, QueryShardContext context) {
return null;
}
MetadataFieldMapper newInstance(Boolean enabled) {
FieldType fieldType = new FieldType();
fieldType.freeze();
MappedFieldType mappedFieldType =
new MappedFieldType("_data_stream_timestamp", false, false, TextSearchInfo.NONE, Collections.emptyMap()) {
@Override
public String typeName() {
return "_data_stream_timestamp";
}
@Override
public Query termQuery(Object value, QueryShardContext context) {
return null;
}
@Override
public Query existsQuery(QueryShardContext context) {
return null;
}
};
return new MetadataFieldMapper(fieldType, mappedFieldType) {
@Override
public void preParse(ParseContext context) throws IOException {
}
@Override
protected void parseCreateField(ParseContext context) throws IOException {
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (enabled == null) {
return builder;
}
builder.startObject(simpleName());
builder.field("enabled", enabled);
return builder.endObject();
}
@Override
protected String contentType() {
return "_data_stream_timestamp";
}
};
@Override
public Query existsQuery(QueryShardContext context) {
return null;
}
});
this.enabled = enabled;
}
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new MetadataTimestampFieldBuilder().init(this);
}
@Override
public void preParse(ParseContext context) {
}
@Override
protected void parseCreateField(ParseContext context) {
}
@Override
protected String contentType() {
return "_data_stream_timestamp";
}
}
}

View File

@ -69,7 +69,7 @@ public class ExternalFieldMapperTests extends ESSingleNodeTestCase {
IndexService indexService = createIndex("test", settings);
MapperRegistry mapperRegistry = new MapperRegistry(
singletonMap(ExternalMapperPlugin.EXTERNAL, new ExternalMapper.TypeParser(ExternalMapperPlugin.EXTERNAL, "foo")),
singletonMap(ExternalMetadataMapper.CONTENT_TYPE, new ExternalMetadataMapper.TypeParser()), MapperPlugin.NOOP_FIELD_FILTER);
singletonMap(ExternalMetadataMapper.CONTENT_TYPE, ExternalMetadataMapper.PARSER), MapperPlugin.NOOP_FIELD_FILTER);
Supplier<QueryShardContext> queryShardContext = () -> {
return indexService.newQueryShardContext(0, null, () -> { throw new UnsupportedOperationException(); }, null);

View File

@ -46,7 +46,7 @@ public class ExternalMapperPlugin extends Plugin implements MapperPlugin {
@Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap(ExternalMetadataMapper.CONTENT_TYPE, new ExternalMetadataMapper.TypeParser());
return Collections.singletonMap(ExternalMetadataMapper.CONTENT_TYPE, ExternalMetadataMapper.PARSER);
}
}

View File

@ -20,14 +20,12 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.StringField;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
public class ExternalMetadataMapper extends MetadataFieldMapper {
@ -36,7 +34,7 @@ public class ExternalMetadataMapper extends MetadataFieldMapper {
static final String FIELD_VALUE = "true";
protected ExternalMetadataMapper() {
super(new FieldType(), new BooleanFieldMapper.BooleanFieldType(FIELD_NAME));
super(new BooleanFieldMapper.BooleanFieldType(FIELD_NAME));
}
@Override
@ -49,11 +47,6 @@ public class ExternalMetadataMapper extends MetadataFieldMapper {
return Collections.emptyIterator();
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(CONTENT_TYPE).endObject();
}
@Override
protected String contentType() {
return CONTENT_TYPE;
@ -68,10 +61,15 @@ public class ExternalMetadataMapper extends MetadataFieldMapper {
context.doc().add(new StringField(FIELD_NAME, FIELD_VALUE, Store.YES));
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
public static class Builder extends MetadataFieldMapper.Builder {
protected Builder() {
super(FIELD_NAME, new FieldType());
super(FIELD_NAME);
}
@Override
protected List<Parameter<?>> getParameters() {
return Collections.emptyList();
}
@Override
@ -81,19 +79,6 @@ public class ExternalMetadataMapper extends MetadataFieldMapper {
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
return new Builder();
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return new ExternalMetadataMapper();
}
}
public static final TypeParser PARSER = new ConfigurableTypeParser(c -> new ExternalMetadataMapper(), c -> new Builder());
}

View File

@ -81,10 +81,10 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
FieldNamesFieldMapper fieldNamesMapper = docMapper.metadataMapper(FieldNamesFieldMapper.class);
assertFalse(fieldNamesMapper.fieldType().hasDocValues());
assertEquals(IndexOptions.DOCS, fieldNamesMapper.fieldType.indexOptions());
assertFalse(fieldNamesMapper.fieldType.tokenized());
assertFalse(fieldNamesMapper.fieldType.stored());
assertTrue(fieldNamesMapper.fieldType.omitNorms());
assertEquals(IndexOptions.DOCS, FieldNamesFieldMapper.Defaults.FIELD_TYPE.indexOptions());
assertFalse(FieldNamesFieldMapper.Defaults.FIELD_TYPE.tokenized());
assertFalse(FieldNamesFieldMapper.Defaults.FIELD_TYPE.stored());
assertTrue(FieldNamesFieldMapper.Defaults.FIELD_TYPE.omitNorms());
}
public void testInjectIntoDocDuringParsing() throws Exception {
@ -124,7 +124,7 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
XContentType.JSON));
assertFieldNames(set("field"), doc);
assertWarnings(FieldNamesFieldMapper.TypeParser.ENABLED_DEPRECATION_MESSAGE.replace("{}", "test"));
assertWarnings(FieldNamesFieldMapper.ENABLED_DEPRECATION_MESSAGE);
}
public void testDisabled() throws Exception {
@ -144,7 +144,7 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
XContentType.JSON));
assertNull(doc.rootDoc().get("_field_names"));
assertWarnings(FieldNamesFieldMapper.TypeParser.ENABLED_DEPRECATION_MESSAGE.replace("{}", "test"));
assertWarnings(FieldNamesFieldMapper.ENABLED_DEPRECATION_MESSAGE.replace("{}", "test"));
}
public void testMergingMappings() throws Exception {
@ -164,6 +164,6 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
DocumentMapper mapperEnabled
= mapperService.merge("type", new CompressedXContent(enabledMapping), MapperService.MergeReason.MAPPING_UPDATE);
assertTrue(mapperEnabled.metadataMapper(FieldNamesFieldMapper.class).fieldType().isEnabled());
assertWarnings(FieldNamesFieldMapper.TypeParser.ENABLED_DEPRECATION_MESSAGE.replace("{}", "test"));
assertWarnings(FieldNamesFieldMapper.ENABLED_DEPRECATION_MESSAGE.replace("{}", "test"));
}
}

View File

@ -38,7 +38,7 @@ public class FieldNamesFieldTypeTests extends ESTestCase {
public void testTermQuery() {
FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = new FieldNamesFieldMapper.FieldNamesFieldType();
FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = new FieldNamesFieldMapper.FieldNamesFieldType(true);
KeywordFieldMapper.KeywordFieldType fieldType = new KeywordFieldMapper.KeywordFieldType("field_name");
Settings settings = settings(Version.CURRENT).build();
@ -52,12 +52,12 @@ public class FieldNamesFieldTypeTests extends ESTestCase {
QueryShardContext queryShardContext = new QueryShardContext(0,
indexSettings, BigArrays.NON_RECYCLING_INSTANCE, null, null, mapperService,
null, null, null, null, null, null, () -> 0L, null, null, () -> true, null);
fieldNamesFieldType.setEnabled(true);
Query termQuery = fieldNamesFieldType.termQuery("field_name", queryShardContext);
Query termQuery = fieldNamesFieldType.termQuery("field_name", queryShardContext);
assertEquals(new TermQuery(new Term(FieldNamesFieldMapper.CONTENT_TYPE, "field_name")), termQuery);
assertWarnings("terms query on the _field_names field is deprecated and will be removed, use exists query instead");
fieldNamesFieldType.setEnabled(false);
IllegalStateException e = expectThrows(IllegalStateException.class, () -> fieldNamesFieldType.termQuery("field_name", null));
FieldNamesFieldMapper.FieldNamesFieldType unsearchable = new FieldNamesFieldMapper.FieldNamesFieldType(false);
IllegalStateException e = expectThrows(IllegalStateException.class, () -> unsearchable.termQuery("field_name", null));
assertEquals("Cannot run [exists] queries if the [_field_names] field is disabled", e.getMessage());
}
}

View File

@ -99,12 +99,12 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
final Parameter<String> variable
= Parameter.stringParam("variable", true, m -> toType(m).variable, "default").acceptsNull();
final Parameter<StringWrapper> wrapper
= new Parameter<>("wrapper", true, () -> new StringWrapper("default"),
= new Parameter<>("wrapper", false, () -> new StringWrapper("default"),
(n, c, o) -> {
if (o == null) return null;
return new StringWrapper(o.toString());
},
m -> toType(m).wrapper).setSerializer((b, n, v) -> b.field(n, v.name));
m -> toType(m).wrapper).setSerializer((b, n, v) -> b.field(n, v.name), v -> "wrapper_" + v.name);
final Parameter<Integer> intValue = Parameter.intParam("int_value", true, m -> toType(m).intValue, 5)
.setValidator(n -> {
if (n > 50) {
@ -112,7 +112,7 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
}
});
final Parameter<NamedAnalyzer> analyzer
= Parameter.analyzerParam("analyzer", true, m -> toType(m).analyzer, () -> Lucene.KEYWORD_ANALYZER);
= Parameter.analyzerParam("analyzer", false, m -> toType(m).analyzer, () -> Lucene.KEYWORD_ANALYZER);
final Parameter<NamedAnalyzer> searchAnalyzer
= Parameter.analyzerParam("search_analyzer", true, m -> toType(m).searchAnalyzer, analyzer::getValue);
final Parameter<Boolean> index = Parameter.boolParam("index", false, m -> toType(m).index, true);
@ -345,6 +345,12 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
TestMapper mapper = fromMapping(mapping);
assertEquals("wrapped value", mapper.wrapper.name);
assertEquals("{\"field\":" + mapping + "}", Strings.toString(mapper));
String conflict = "{\"type\":\"test_mapper\",\"wrapper\":\"new value\",\"required\":\"value\"}";
TestMapper toMerge = fromMapping(conflict);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> mapper.merge(toMerge));
assertEquals("Mapper for [field] conflicts with existing mapper:\n" +
"\tCannot update parameter [wrapper] from [wrapper_wrapped value] to [wrapper_new value]", e.getMessage());
}
// test validator
@ -383,6 +389,12 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
String badAnalyzer = "{\"type\":\"test_mapper\",\"analyzer\":\"wibble\",\"required\":\"value\"}";
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> fromMapping(badAnalyzer));
assertEquals("analyzer [wibble] has not been configured in mappings", e.getMessage());
TestMapper original = mapper;
TestMapper toMerge = fromMapping(mapping);
e = expectThrows(IllegalArgumentException.class, () -> original.merge(toMerge));
assertEquals("Mapper for [field] conflicts with existing mapper:\n" +
"\tCannot update parameter [analyzer] from [default] to [_standard]", e.getMessage());
}
public void testDeprecatedParameters() {

View File

@ -97,7 +97,7 @@ public class SourceFieldMapperTests extends ESSingleNodeTestCase {
public void testExcludes() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("excludes", new String[]{"path1*"}).endObject()
.startObject("_source").array("excludes", "path1*").endObject()
.endObject().endObject());
DocumentMapper documentMapper = createIndex("test").mapperService().documentMapperParser()
@ -126,7 +126,7 @@ public class SourceFieldMapperTests extends ESSingleNodeTestCase {
String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").field("enabled", false).endObject()
.endObject().endObject());
assertConflicts(mapping1, mapping2, parser, "Cannot update enabled setting for [_source]");
assertConflicts(mapping1, mapping2, parser, "Cannot update parameter [enabled] from [true] to [false]");
// not changing is ok
String mapping3 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
@ -141,13 +141,13 @@ public class SourceFieldMapperTests extends ESSingleNodeTestCase {
String mapping1 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("includes", "foo.*").endObject()
.endObject().endObject());
assertConflicts(defaultMapping, mapping1, parser, "Cannot update includes setting for [_source]");
assertConflicts(mapping1, defaultMapping, parser, "Cannot update includes setting for [_source]");
assertConflicts(defaultMapping, mapping1, parser, "Cannot update parameter [includes] from [[]] to [[foo.*]]");
assertConflicts(mapping1, defaultMapping, parser, "Cannot update parameter [includes] from [[foo.*]] to [[]]");
String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("includes", "foo.*", "bar.*").endObject()
.endObject().endObject());
assertConflicts(mapping1, mapping2, parser, "Cannot update includes setting for [_source]");
assertConflicts(mapping1, mapping2, parser, "Cannot update parameter [includes] from [[foo.*]] to [[foo.*, bar.*]]");
// not changing is ok
assertConflicts(mapping1, mapping1, parser);
@ -159,13 +159,13 @@ public class SourceFieldMapperTests extends ESSingleNodeTestCase {
String mapping1 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("excludes", "foo.*").endObject()
.endObject().endObject());
assertConflicts(defaultMapping, mapping1, parser, "Cannot update excludes setting for [_source]");
assertConflicts(mapping1, defaultMapping, parser, "Cannot update excludes setting for [_source]");
assertConflicts(defaultMapping, mapping1, parser, "Cannot update parameter [excludes] from [[]] to [[foo.*]]");
assertConflicts(mapping1, defaultMapping, parser, "Cannot update parameter [excludes] from [[foo.*]] to [[]]");
String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("excludes", "foo.*", "bar.*").endObject()
.endObject().endObject());
assertConflicts(mapping1, mapping2, parser, "Cannot update excludes setting for [_source]");
assertConflicts(mapping1, mapping2, parser, "Cannot update parameter [excludes]");
// not changing is ok
assertConflicts(mapping1, mapping1, parser);

View File

@ -30,10 +30,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.plain.AbstractLeafOrdinalsFieldData;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.IndexFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.TextFieldMapper;
import org.elasticsearch.test.ESTestCase;
@ -117,8 +115,7 @@ public class QueryShardContextTests extends ESTestCase {
final String clusterAlias = randomBoolean() ? null : "remote_cluster";
QueryShardContext context = createQueryShardContext(IndexMetadata.INDEX_UUID_NA_VALUE, clusterAlias);
Mapper.BuilderContext ctx = new Mapper.BuilderContext(context.getIndexSettings().getSettings(), new ContentPath());
IndexFieldMapper mapper = new IndexFieldMapper.Builder().build(ctx);
IndexFieldMapper mapper = new IndexFieldMapper();
IndexFieldData<?> forField = context.getForField(mapper.fieldType());
String expected = clusterAlias == null ? context.getIndexSettings().getIndexMetadata().getIndex().getName()

View File

@ -1105,7 +1105,7 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
"enabled=true"))),
MapperService.MergeReason.MAPPING_UPDATE);
}
assertWarnings(FieldNamesFieldMapper.TypeParser.ENABLED_DEPRECATION_MESSAGE.replace("{}", context.index().getName()));
assertWarnings(FieldNamesFieldMapper.ENABLED_DEPRECATION_MESSAGE);
}
public void testFromJson() throws IOException {

View File

@ -25,7 +25,6 @@ import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
import org.elasticsearch.index.mapper.IdFieldMapper;
import org.elasticsearch.index.mapper.IgnoredFieldMapper;
import org.elasticsearch.index.mapper.IndexFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MetadataFieldMapper;
@ -63,17 +62,7 @@ public class IndicesModuleTests extends ESTestCase {
}
}
private static class FakeMetadataMapperParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node, ParserContext parserContext)
throws MapperParsingException {
return null;
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return null;
}
}
private static final MetadataFieldMapper.TypeParser PARSER = new MetadataFieldMapper.ConfigurableTypeParser(c -> null, c -> null);
private final List<MapperPlugin> fakePlugins = Arrays.asList(new MapperPlugin() {
@Override
@ -82,7 +71,7 @@ public class IndicesModuleTests extends ESTestCase {
}
@Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap("fake-metadata-mapper", new FakeMetadataMapperParser());
return Collections.singletonMap("fake-metadata-mapper", PARSER);
}
});
@ -180,7 +169,7 @@ public class IndicesModuleTests extends ESTestCase {
List<MapperPlugin> plugins = Arrays.asList(new MapperPlugin() {
@Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap(IdFieldMapper.NAME, new FakeMetadataMapperParser());
return Collections.singletonMap(IdFieldMapper.NAME, PARSER);
}
});
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
@ -192,7 +181,7 @@ public class IndicesModuleTests extends ESTestCase {
MapperPlugin plugin = new MapperPlugin() {
@Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap("foo", new FakeMetadataMapperParser());
return Collections.singletonMap("foo", PARSER);
}
};
List<MapperPlugin> plugins = Arrays.asList(plugin, plugin);
@ -205,7 +194,7 @@ public class IndicesModuleTests extends ESTestCase {
List<MapperPlugin> plugins = Arrays.asList(new MapperPlugin() {
@Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap(FieldNamesFieldMapper.NAME, new FakeMetadataMapperParser());
return Collections.singletonMap(FieldNamesFieldMapper.NAME, PARSER);
}
});
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,

View File

@ -53,7 +53,7 @@ public class DataStreamsPlugin extends Plugin implements ActionPlugin, MapperPlu
@Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap(DataStreamTimestampFieldMapper.NAME, new DataStreamTimestampFieldMapper.TypeParser());
return Collections.singletonMap(DataStreamTimestampFieldMapper.NAME, DataStreamTimestampFieldMapper.PARSER);
}
@Override

View File

@ -6,23 +6,20 @@
package org.elasticsearch.xpack.datastreams.mapper;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.mapper.DateFieldMapper;
import org.elasticsearch.index.mapper.MappingLookup;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.ParametrizedFieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
@ -31,10 +28,8 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
@ -43,16 +38,6 @@ public class DataStreamTimestampFieldMapper extends MetadataFieldMapper {
public static final String NAME = "_data_stream_timestamp";
private static final String DEFAULT_PATH = "@timestamp";
public static class Defaults {
public static final FieldType TIMESTAMP_FIELD_TYPE = new FieldType();
static {
TIMESTAMP_FIELD_TYPE.setIndexOptions(IndexOptions.NONE);
TIMESTAMP_FIELD_TYPE.freeze();
}
}
// For now the field shouldn't be useable in searches.
// In the future it should act as an alias to the actual data stream timestamp field.
public static final class TimestampFieldType extends MappedFieldType {
@ -78,58 +63,47 @@ public class DataStreamTimestampFieldMapper extends MetadataFieldMapper {
}
public static class Builder extends MetadataFieldMapper.Builder<Builder> {
private static DataStreamTimestampFieldMapper toType(FieldMapper in) {
return (DataStreamTimestampFieldMapper) in;
}
private boolean enabled;
public static class Builder extends MetadataFieldMapper.Builder {
private final Parameter<Boolean> enabled = Parameter.boolParam("enabled", false, m -> toType(m).enabled, false);
public Builder() {
super(NAME, Defaults.TIMESTAMP_FIELD_TYPE);
super(NAME);
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
@Override
protected List<Parameter<?>> getParameters() {
return Collections.singletonList(enabled);
}
@Override
public MetadataFieldMapper build(BuilderContext context) {
return new DataStreamTimestampFieldMapper(fieldType, new TimestampFieldType(), enabled);
return new DataStreamTimestampFieldMapper(new TimestampFieldType(), enabled.getValue());
}
}
public static class TypeParser implements MetadataFieldMapper.TypeParser {
public static final TypeParser PARSER = new ConfigurableTypeParser(
c -> new DataStreamTimestampFieldMapper(new TimestampFieldType(), false),
c -> new Builder()
);
@Override
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node, ParserContext parserContext)
throws MapperParsingException {
Builder builder = new Builder();
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
Object fieldNode = entry.getValue();
if (fieldName.equals("enabled")) {
builder.setEnabled(XContentMapValues.nodeBooleanValue(fieldNode, name + ".enabled"));
iterator.remove();
}
}
return builder;
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext parserContext) {
return new DataStreamTimestampFieldMapper(Defaults.TIMESTAMP_FIELD_TYPE, new TimestampFieldType(), false);
}
}
private final String path;
private final String path = DEFAULT_PATH;
private final boolean enabled;
private DataStreamTimestampFieldMapper(FieldType fieldType, MappedFieldType mappedFieldType, boolean enabled) {
super(fieldType, mappedFieldType);
this.path = DEFAULT_PATH;
private DataStreamTimestampFieldMapper(MappedFieldType mappedFieldType, boolean enabled) {
super(mappedFieldType);
this.enabled = enabled;
}
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder().init(this);
}
public void doValidate(MappingLookup lookup) {
if (enabled == false) {
// not configured, so skip the validation
@ -227,37 +201,8 @@ public class DataStreamTimestampFieldMapper extends MetadataFieldMapper {
}
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (enabled == false) {
return builder;
}
builder.startObject(simpleName());
builder.field("enabled", enabled);
return builder.endObject();
}
@Override
protected String contentType() {
return NAME;
}
@Override
protected boolean indexedByDefault() {
return false;
}
@Override
protected boolean docValuesByDefault() {
return false;
}
@Override
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
DataStreamTimestampFieldMapper otherTimestampFieldMapper = (DataStreamTimestampFieldMapper) other;
if (Objects.equals(enabled, otherTimestampFieldMapper.enabled) == false) {
conflicts.add("cannot update enabled setting for [_data_stream_timestamp]");
}
}
}

View File

@ -287,12 +287,12 @@ public class DataStreamTimestampFieldMapperTests extends ESSingleNodeTestCase {
"{\"type\":{\"_data_stream_timestamp\":{\"enabled\":false}, \"properties\": {\"@timestamp\": {\"type\": \"date\"}}}}}";
String mapping2 = "{\"type\":{\"_data_stream_timestamp\":{\"enabled\":true}, \"properties\": {\"@timestamp2\": "
+ "{\"type\": \"date\"},\"@timestamp\": {\"type\": \"date\"}}}})";
assertConflicts(mapping1, mapping2, parser, "cannot update enabled setting for [_data_stream_timestamp]");
assertConflicts(mapping1, mapping2, parser, "Mapper for [_data_stream_timestamp]", "[enabled] from [false] to [true]");
mapping1 = "{\"type\":{\"properties\":{\"@timestamp\": {\"type\": \"date\"}}}}}";
mapping2 = "{\"type\":{\"_data_stream_timestamp\":{\"enabled\":true}, \"properties\": "
+ "{\"@timestamp2\": {\"type\": \"date\"},\"@timestamp\": {\"type\": \"date\"}}}})";
assertConflicts(mapping1, mapping2, parser, "cannot update enabled setting for [_data_stream_timestamp]");
assertConflicts(mapping1, mapping2, parser, "Mapper for [_data_stream_timestamp]", "[enabled] from [false] to [true]");
}
}