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 @Override
public Map<String, TypeParser> getMetadataMappers() { public Map<String, TypeParser> getMetadataMappers() {
return Collections.singletonMap(RankFeatureMetaFieldMapper.CONTENT_TYPE, new RankFeatureMetaFieldMapper.TypeParser()); return Collections.singletonMap(RankFeatureMetaFieldMapper.CONTENT_TYPE, RankFeatureMetaFieldMapper.PARSER);
} }
@Override @Override

View File

@ -19,16 +19,10 @@
package org.elasticsearch.index.mapper; 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.apache.lucene.search.Query;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
/** /**
* This meta field only exists because rank feature fields index everything into a * 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 final String CONTENT_TYPE = "_feature";
public static class Defaults { public static final TypeParser PARSER = new FixedTypeParser(c -> new RankFeatureMetaFieldMapper());
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 class RankFeatureMetaFieldType extends MappedFieldType { public static final class RankFeatureMetaFieldType extends MappedFieldType {
@ -109,27 +62,23 @@ public class RankFeatureMetaFieldMapper extends MetadataFieldMapper {
} }
private RankFeatureMetaFieldMapper() { private RankFeatureMetaFieldMapper() {
super(Defaults.FIELD_TYPE, RankFeatureMetaFieldType.INSTANCE); super(RankFeatureMetaFieldType.INSTANCE);
} }
@Override @Override
public void preParse(ParseContext context) throws IOException {} public void preParse(ParseContext context) {}
@Override @Override
protected void parseCreateField(ParseContext context) throws IOException { protected void parseCreateField(ParseContext context) {
throw new AssertionError("Should never be called"); throw new AssertionError("Should never be called");
} }
@Override @Override
public void postParse(ParseContext context) throws IOException {} public void postParse(ParseContext context) {}
@Override @Override
protected String contentType() { protected String contentType() {
return CONTENT_TYPE; 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; package org.elasticsearch.index.mapper.size;
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 org.elasticsearch.index.mapper.EnabledAttributeMapper;
import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MetadataFieldMapper; 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 org.elasticsearch.index.mapper.ParseContext;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
public class SizeFieldMapper extends MetadataFieldMapper { public class SizeFieldMapper extends MetadataFieldMapper {
public static final String NAME = "_size"; public static final String NAME = "_size";
public static class Defaults { private static SizeFieldMapper toType(FieldMapper in) {
public static final EnabledAttributeMapper ENABLED_STATE = EnabledAttributeMapper.UNSET_DISABLED; return (SizeFieldMapper) in;
public static final FieldType SIZE_FIELD_TYPE = new FieldType();
static {
SIZE_FIELD_TYPE.setStored(true);
SIZE_FIELD_TYPE.freeze();
}
} }
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() { private Builder() {
super(NAME, Defaults.SIZE_FIELD_TYPE); super(NAME);
builder = this;
} }
public Builder enabled(EnabledAttributeMapper enabled) { @Override
this.enabledState = enabled; protected List<Parameter<?>> getParameters() {
return builder; return Collections.singletonList(enabled);
} }
@Override @Override
public SizeFieldMapper build(BuilderContext context) { public SizeFieldMapper build(BuilderContext context) {
return new SizeFieldMapper(fieldType, enabledState, return new SizeFieldMapper(enabled.getValue(), new NumberFieldType(NAME, NumberType.INTEGER));
new NumberFieldMapper.NumberFieldType(NAME, NumberFieldMapper.NumberType.INTEGER));
} }
} }
public static class TypeParser implements MetadataFieldMapper.TypeParser { public static final TypeParser PARSER = new ConfigurableTypeParser(
@Override c -> new SizeFieldMapper(new Explicit<>(false, false), new NumberFieldType(NAME, NumberType.INTEGER)),
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node, c -> new Builder()
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;
}
@Override private final Explicit<Boolean> enabled;
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 EnabledAttributeMapper enabledState; private SizeFieldMapper(Explicit<Boolean> enabled, MappedFieldType mappedFieldType) {
super(mappedFieldType);
private SizeFieldMapper(FieldType fieldType, EnabledAttributeMapper enabled, this.enabled = enabled;
MappedFieldType mappedFieldType) {
super(fieldType, mappedFieldType);
this.enabledState = enabled;
} }
@Override @Override
@ -109,7 +77,7 @@ public class SizeFieldMapper extends MetadataFieldMapper {
} }
public boolean enabled() { public boolean enabled() {
return this.enabledState.enabled; return this.enabled.value();
} }
@Override @Override
@ -129,37 +97,15 @@ public class SizeFieldMapper extends MetadataFieldMapper {
@Override @Override
protected void parseCreateField(ParseContext context) { protected void parseCreateField(ParseContext context) {
if (!enabledState.enabled) { if (enabled.value() == false) {
return; return;
} }
final int value = context.sourceToParse().source().length(); final int value = context.sourceToParse().source().length();
boolean indexed = fieldType().isSearchable(); context.doc().addAll(NumberType.INTEGER.createFields(name(), value, true, true, true));
boolean docValued = fieldType().hasDocValues();
boolean stored = fieldType.stored();
context.doc().addAll(NumberFieldMapper.NumberType.INTEGER.createFields(name(), value, indexed, docValued, stored));
} }
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public ParametrizedFieldMapper.Builder getMergeBuilder() {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false); return new Builder().init(this);
// 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;
}
} }
} }

View File

@ -19,18 +19,18 @@
package org.elasticsearch.plugin.mapper; package org.elasticsearch.plugin.mapper;
import java.util.Collections;
import java.util.Map;
import org.elasticsearch.index.mapper.MetadataFieldMapper; import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.size.SizeFieldMapper; import org.elasticsearch.index.mapper.size.SizeFieldMapper;
import org.elasticsearch.plugins.MapperPlugin; import org.elasticsearch.plugins.MapperPlugin;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import java.util.Collections;
import java.util.Map;
public class MapperSizePlugin extends Plugin implements MapperPlugin { public class MapperSizePlugin extends Plugin implements MapperPlugin {
@Override @Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() { 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; package org.elasticsearch.common;
import java.util.Objects;
/** /**
* Holds a value that is either: * Holds a value that is either:
* a) set implicitly e.g. through some default value * a) set implicitly e.g. through some default value
@ -54,4 +56,18 @@ public class Explicit<T> {
public boolean explicit() { public boolean explicit() {
return this.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.index.IndexOptions;
import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.List;
import java.util.Map;
/** /**
* Noop mapper that ensures that mappings created in 6x that explicitly disable the _all field * 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 static AllFieldMapper toType(FieldMapper in) {
private boolean disableExplicit = false; return (AllFieldMapper) in;
}
public Builder(MappedFieldType existing) { public static class Builder extends MetadataFieldMapper.Builder {
super(NAME, Defaults.FIELD_TYPE);
builder = this; private final Parameter<Explicit<Boolean>> enabled = updateableBoolParam("enabled", m -> toType(m).enabled, false);
public Builder() {
super(NAME);
} }
private Builder setDisableExplicit() { @Override
this.disableExplicit = true; protected List<Parameter<?>> getParameters() {
return this; return Collections.singletonList(enabled);
} }
@Override @Override
public AllFieldMapper build(BuilderContext context) { public AllFieldMapper build(BuilderContext context) {
return new AllFieldMapper(disableExplicit); if (enabled.getValue().value()) {
} throw new IllegalArgumentException("[_all] is disabled in this version.");
}
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();
}
} }
return builder; return new AllFieldMapper(enabled.getValue());
}
@Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext context) {
return new AllFieldMapper(false);
} }
} }
public static final TypeParser PARSER = new ConfigurableTypeParser(
c -> new AllFieldMapper(new Explicit<>(true, false)),
c -> new Builder()
);
static final class AllFieldType extends StringFieldType { static final class AllFieldType extends StringFieldType {
AllFieldType() { AllFieldType() {
super(NAME, false, false, TextSearchInfo.NONE, Collections.emptyMap()); 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) { private AllFieldMapper(Explicit<Boolean> enabled) {
super(Defaults.FIELD_TYPE, new AllFieldType()); super(new AllFieldType());
this.disableExplicit = disableExplicit; this.enabled = enabled;
} }
@Override @Override
public void preParse(ParseContext context) throws IOException { public void preParse(ParseContext context) {
} }
@Override @Override
@ -137,7 +121,6 @@ public class AllFieldMapper extends MetadataFieldMapper {
@Override @Override
protected void parseCreateField(ParseContext context) throws IOException { protected void parseCreateField(ParseContext context) throws IOException {
// noop mapper // noop mapper
return;
} }
@Override @Override
@ -145,16 +128,4 @@ public class AllFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; 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); b.startArray(n);
c.toXContent(b, ToXContent.EMPTY_PARAMS); c.toXContent(b, ToXContent.EMPTY_PARAMS);
b.endArray(); b.endArray();
}); }, ContextMappings::toString);
private final Parameter<Integer> maxInputLength = Parameter.intParam("max_input_length", true, private final Parameter<Integer> maxInputLength = Parameter.intParam("max_input_length", true,
m -> toType(m).maxInputLength, Defaults.DEFAULT_MAX_INPUT_LENGTH) m -> toType(m).maxInputLength, Defaults.DEFAULT_MAX_INPUT_LENGTH)
.addDeprecatedName("max_input_len") .addDeprecatedName("max_input_len")

View File

@ -96,7 +96,7 @@ public class DocumentMapper implements ToXContentFragment {
return this; return this;
} }
public Builder put(MetadataFieldMapper.Builder<?> mapper) { public Builder put(MetadataFieldMapper.Builder mapper) {
MetadataFieldMapper metadataMapper = mapper.build(builderContext); MetadataFieldMapper metadataMapper = mapper.build(builderContext);
metadataMappers.put(metadataMapper.getClass(), metadataMapper); metadataMappers.put(metadataMapper.getClass(), metadataMapper);
return this; 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.index.IndexableField;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.logging.DeprecationLogger; 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 org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException; import java.io.IOException;
@ -37,7 +35,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; 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 * 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"; 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 class Defaults {
public static final String NAME = FieldNamesFieldMapper.NAME; 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(); public static final FieldType FIELD_TYPE = new FieldType();
static { static {
@ -69,69 +71,53 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
} }
} }
static class Builder extends MetadataFieldMapper.Builder<Builder> { private static FieldNamesFieldMapper toType(FieldMapper in) {
private boolean enabled = Defaults.ENABLED; return (FieldNamesFieldMapper) in;
}
Builder() { public static final String ENABLED_DEPRECATION_MESSAGE =
super(Defaults.NAME, Defaults.FIELD_TYPE); "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) { protected List<Parameter<?>> getParameters() {
this.enabled = enabled; return Collections.singletonList(enabled);
return this;
} }
@Override @Override
public FieldNamesFieldMapper build(BuilderContext context) { public FieldNamesFieldMapper build(BuilderContext context) {
FieldNamesFieldType fieldNamesFieldType = new FieldNamesFieldType(); if (enabled.getValue().explicit()) {
fieldNamesFieldType.setEnabled(enabled); deprecationLogger.deprecatedAndMaybeLog("field_names_enabled_parameter", ENABLED_DEPRECATION_MESSAGE);
return new FieldNamesFieldMapper(fieldType, fieldNamesFieldType); }
FieldNamesFieldType fieldNamesFieldType = new FieldNamesFieldType(enabled.getValue().value());
return new FieldNamesFieldMapper(enabled.getValue(), indexVersionCreated, fieldNamesFieldType);
} }
} }
public static class TypeParser implements MetadataFieldMapper.TypeParser { public static final TypeParser PARSER = new ConfigurableTypeParser(
c -> new FieldNamesFieldMapper(Defaults.ENABLED, c.indexVersionCreated(), new FieldNamesFieldType(Defaults.ENABLED.value())),
public static final String ENABLED_DEPRECATION_MESSAGE = "Index [{}] uses the deprecated `enabled` setting for `_field_names`. " c -> new Builder(c.indexVersionCreated())
+ "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 class FieldNamesFieldType extends TermBasedFieldType { 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()); super(Defaults.NAME, true, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
this.enabled = enabled;
} }
@Override @Override
@ -139,10 +125,6 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; return CONTENT_TYPE;
} }
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
} }
@ -164,8 +146,13 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
} }
} }
private FieldNamesFieldMapper(FieldType fieldType, MappedFieldType mappedFieldType) { private final Explicit<Boolean> enabled;
super(fieldType, mappedFieldType); private final Version indexVersionCreated;
private FieldNamesFieldMapper(Explicit<Boolean> enabled, Version indexVersionCreated, FieldNamesFieldType mappedFieldType) {
super(mappedFieldType);
this.enabled = enabled;
this.indexVersionCreated = indexVersionCreated;
} }
@Override @Override
@ -261,21 +248,4 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; 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.logging.DeprecationLogger;
import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested; import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
import org.elasticsearch.index.fielddata.IndexFieldDataCache; import org.elasticsearch.index.fielddata.IndexFieldDataCache;
@ -55,7 +54,6 @@ import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* A mapper for the _id field. It does nothing since _id is neither indexed nor * 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 FIELD_TYPE = new FieldType();
public static final FieldType NESTED_FIELD_TYPE; public static final FieldType NESTED_FIELD_TYPE;
public static final MappedFieldType MAPPED_FIELD_TYPE = new IdFieldType();
static { static {
FIELD_TYPE.setTokenized(false); FIELD_TYPE.setTokenized(false);
@ -97,18 +94,7 @@ public class IdFieldMapper extends MetadataFieldMapper {
} }
} }
public static class TypeParser implements MetadataFieldMapper.TypeParser { public static final TypeParser PARSER = new FixedTypeParser(c -> new IdFieldMapper());
@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);
}
}
static final class IdFieldType extends TermBasedFieldType { static final class IdFieldType extends TermBasedFieldType {
@ -263,8 +249,8 @@ public class IdFieldMapper extends MetadataFieldMapper {
}; };
} }
private IdFieldMapper(FieldType fieldType) { private IdFieldMapper() {
super(fieldType, new IdFieldType()); super(new IdFieldType());
} }
@Override @Override
@ -274,10 +260,8 @@ public class IdFieldMapper extends MetadataFieldMapper {
@Override @Override
protected void parseCreateField(ParseContext context) throws IOException { protected void parseCreateField(ParseContext context) throws IOException {
if (fieldType.indexOptions() != IndexOptions.NONE || fieldType.stored()) { BytesRef id = Uid.encodeId(context.sourceToParse().id());
BytesRef id = Uid.encodeId(context.sourceToParse().id()); context.doc().add(new Field(NAME, id, Defaults.FIELD_TYPE));
context.doc().add(new Field(NAME, id, fieldType));
}
} }
@Override @Override
@ -285,8 +269,4 @@ public class IdFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; 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.index.IndexOptions;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.search.TermRangeQuery;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
/** /**
* A field mapper that records fields that have been ignored because they were malformed. * 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 static final TypeParser PARSER = new FixedTypeParser(c -> new IgnoredFieldMapper());
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 class IgnoredFieldType extends StringFieldType { public static final class IgnoredFieldType extends StringFieldType {
@ -104,7 +79,7 @@ public final class IgnoredFieldMapper extends MetadataFieldMapper {
} }
private IgnoredFieldMapper() { private IgnoredFieldMapper() {
super(Defaults.FIELD_TYPE, IgnoredFieldType.INSTANCE); super(IgnoredFieldType.INSTANCE);
} }
@Override @Override
@ -124,7 +99,7 @@ public final class IgnoredFieldMapper extends MetadataFieldMapper {
@Override @Override
protected void parseCreateField(ParseContext context) throws IOException { protected void parseCreateField(ParseContext context) throws IOException {
for (String field : context.getIgnoredFields()) { 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; 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; 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.MatchAllDocsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData; import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
@ -31,7 +28,6 @@ import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
public class IndexFieldMapper extends MetadataFieldMapper { public class IndexFieldMapper extends MetadataFieldMapper {
@ -40,44 +36,7 @@ public class IndexFieldMapper extends MetadataFieldMapper {
public static final String CONTENT_TYPE = "_index"; public static final String CONTENT_TYPE = "_index";
public static class Defaults { public static final TypeParser PARSER = new FixedTypeParser(c -> new IndexFieldMapper());
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);
}
}
static final class IndexFieldType extends ConstantFieldType { static final class IndexFieldType extends ConstantFieldType {
@ -109,8 +68,8 @@ public class IndexFieldMapper extends MetadataFieldMapper {
} }
private IndexFieldMapper(FieldType fieldType) { public IndexFieldMapper() {
super(fieldType, IndexFieldType.INSTANCE); super(IndexFieldType.INSTANCE);
} }
@Override @Override
@ -124,8 +83,4 @@ public class IndexFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; 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.Nullable;
import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.ScriptDocValues; import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData; import org.elasticsearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData;
@ -72,7 +73,7 @@ public class IpFieldMapper extends ParametrizedFieldMapper {
} else { } else {
b.field(f, InetAddresses.toAddrString(v)); b.field(f, InetAddresses.toAddrString(v));
} }
}); }, NetworkAddress::format);
private final Parameter<Map<String, String>> meta = Parameter.metaParam(); private final Parameter<Map<String, String>> meta = Parameter.metaParam();

View File

@ -19,22 +19,24 @@
package org.elasticsearch.index.mapper; 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.io.IOException;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
/** /**
* A mapper for a builtin field containing metadata about a document. * 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 { public interface TypeParser extends Mapper.TypeParser {
@Override @Override
MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node, MetadataFieldMapper.Builder parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException; ParserContext parserContext) throws MapperParsingException;
/** /**
@ -48,25 +50,109 @@ public abstract class MetadataFieldMapper extends FieldMapper {
MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext parserContext); MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext parserContext);
} }
@SuppressWarnings("rawtypes") /**
public abstract static class Builder<T extends Builder<T>> extends FieldMapper.Builder<T> { * Declares an updateable boolean parameter for a metadata field
public Builder(String name, FieldType fieldType) { *
super(name, fieldType); * 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 @Override
public T index(boolean index) { public Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
if (index == false) { throw new MapperParsingException(name + " is not configurable");
throw new IllegalArgumentException("Metadata fields must be indexed"); }
}
@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; 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); public abstract MetadataFieldMapper build(BuilderContext context);
} }
protected MetadataFieldMapper(FieldType fieldType, MappedFieldType mappedFieldType) { protected MetadataFieldMapper(MappedFieldType mappedFieldType) {
super(mappedFieldType.name(), fieldType, mappedFieldType, MultiFields.empty(), CopyTo.empty()); 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."); 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(); ParametrizedFieldMapper.Builder builder = getMergeBuilder();
if (builder == null) {
return (ParametrizedFieldMapper) mergeWith;
}
Conflicts conflicts = new Conflicts(name()); Conflicts conflicts = new Conflicts(name());
builder.merge((FieldMapper) mergeWith, conflicts); builder.merge((FieldMapper) mergeWith, conflicts);
conflicts.check(); conflicts.check();
@ -108,11 +111,6 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
// TODO remove when everything is parametrized // TODO remove when everything is parametrized
} }
@Override
public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return super.toXContent(builder, params);
}
@Override @Override
protected final void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException { protected final void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
builder.field("type", contentType()); builder.field("type", contentType());
@ -143,6 +141,7 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
private boolean acceptsNull = false; private boolean acceptsNull = false;
private Consumer<T> validator = null; private Consumer<T> validator = null;
private Serializer<T> serializer = XContentBuilder::field; private Serializer<T> serializer = XContentBuilder::field;
private Function<T, String> conflictSerializer = Object::toString;
private T value; private T value;
private boolean isSet; private boolean isSet;
@ -186,6 +185,10 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
this.value = value; this.value = value;
} }
public boolean isConfigured() {
return isSet && Objects.equals(value, defaultValue.get()) == false;
}
/** /**
* Allows the parameter to accept a {@code null} value * 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 * 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.serializer = serializer;
this.conflictSerializer = conflictSerializer;
return this; return this;
} }
@ -237,15 +241,16 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
private void merge(FieldMapper toMerge, Conflicts conflicts) { private void merge(FieldMapper toMerge, Conflicts conflicts) {
T value = initializer.apply(toMerge); T value = initializer.apply(toMerge);
if (updateable == false && isSet && Objects.equals(this.value, value) == false) { T current = getValue();
conflicts.addConflict(name, this.value.toString(), value.toString()); if (updateable == false && Objects.equals(current, value) == false) {
conflicts.addConflict(name, conflictSerializer.apply(current), conflictSerializer.apply(value));
} else { } else {
setValue(value); setValue(value);
} }
} }
private void toXContent(XContentBuilder builder, boolean includeDefaults) throws IOException { 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()); serializer.serialize(builder, name, getValue());
} }
} }
@ -299,6 +304,20 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
(n, c, o) -> XContentMapValues.nodeStringValue(o), initializer); (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 * Defines a parameter that takes an analyzer name
* @param name the parameter 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"); throw new IllegalArgumentException("analyzer [" + analyzerName + "] has not been configured in mappings");
} }
return a; 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.Query;
import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TermQuery;
import org.elasticsearch.common.lucene.Lucene; 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 org.elasticsearch.index.query.QueryShardContext;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.List;
import java.util.Map;
public class RoutingFieldMapper extends MetadataFieldMapper { public class RoutingFieldMapper extends MetadataFieldMapper {
public static final String NAME = "_routing"; public static final String NAME = "_routing";
public static final String CONTENT_TYPE = "_routing"; public static final String CONTENT_TYPE = "_routing";
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder().init(this);
}
public static class Defaults { public static class Defaults {
public static final String NAME = "_routing";
public static final FieldType FIELD_TYPE = new FieldType(); public static final FieldType FIELD_TYPE = new FieldType();
static { static {
FIELD_TYPE.setIndexOptions(IndexOptions.DOCS); FIELD_TYPE.setIndexOptions(IndexOptions.DOCS);
FIELD_TYPE.setTokenized(false); FIELD_TYPE.setTokenized(false);
@ -57,53 +56,33 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
public static final boolean REQUIRED = false; 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() { final Parameter<Boolean> required = Parameter.boolParam("required", false, m -> toType(m).required, Defaults.REQUIRED);
super(Defaults.NAME, Defaults.FIELD_TYPE);
protected Builder() {
super(NAME);
} }
public Builder required(boolean required) { @Override
this.required = required; protected List<Parameter<?>> getParameters() {
return builder; return Collections.singletonList(required);
} }
@Override @Override
public RoutingFieldMapper build(BuilderContext context) { public RoutingFieldMapper build(BuilderContext context) {
return new RoutingFieldMapper(fieldType, required); return new RoutingFieldMapper(required.getValue());
} }
} }
public static class TypeParser implements MetadataFieldMapper.TypeParser { public static final TypeParser PARSER = new ConfigurableTypeParser(
@Override c -> new RoutingFieldMapper(Defaults.REQUIRED),
public MetadataFieldMapper.Builder<?> parse(String name, Map<String, Object> node, c -> new Builder()
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)));
}
}
}
static final class RoutingFieldType extends StringFieldType { static final class RoutingFieldType extends StringFieldType {
@ -127,8 +106,8 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
private final boolean required; private final boolean required;
private RoutingFieldMapper(FieldType fieldType, boolean required) { private RoutingFieldMapper(boolean required) {
super(fieldType, RoutingFieldType.INSTANCE); super(RoutingFieldType.INSTANCE);
this.required = required; this.required = required;
} }
@ -152,10 +131,8 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
protected void parseCreateField(ParseContext context) throws IOException { protected void parseCreateField(ParseContext context) throws IOException {
String routing = context.sourceToParse().routing(); String routing = context.sourceToParse().routing();
if (routing != null) { if (routing != null) {
if (fieldType.indexOptions() != IndexOptions.NONE || fieldType.stored()) { context.doc().add(new Field(fieldType().name(), routing, Defaults.FIELD_TYPE));
context.doc().add(new Field(fieldType().name(), routing, fieldType)); createFieldNamesField(context);
createFieldNamesField(context);
}
} }
} }
@ -164,19 +141,4 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; 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; package org.elasticsearch.index.mapper;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.NumericDocValuesField; import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.search.DocValuesFieldExistsQuery; import org.apache.lucene.search.DocValuesFieldExistsQuery;
import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable; 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.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData.NumericType; import org.elasticsearch.index.fielddata.IndexNumericFieldData.NumericType;
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData; import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
@ -42,7 +38,6 @@ import org.elasticsearch.index.seqno.SequenceNumbers;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; 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 PRIMARY_TERM_NAME = "_primary_term";
public static final String TOMBSTONE_NAME = "_tombstone"; public static final String TOMBSTONE_NAME = "_tombstone";
public static class Defaults { public static final TypeParser PARSER = new FixedTypeParser(c -> new SeqNoFieldMapper());
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();
}
}
static final class SeqNoFieldType extends SimpleMappedFieldType { static final class SeqNoFieldType extends SimpleMappedFieldType {
private static final SeqNoFieldType INSTANCE = new SeqNoFieldType();
SeqNoFieldType() { SeqNoFieldType() {
super(NAME, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap()); super(NAME, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
} }
@ -202,7 +176,7 @@ public class SeqNoFieldMapper extends MetadataFieldMapper {
} }
public SeqNoFieldMapper() { public SeqNoFieldMapper() {
super(Defaults.FIELD_TYPE, Defaults.MAPPED_FIELD_TYPE); super(SeqNoFieldType.INSTANCE);
} }
@Override @Override
@ -252,9 +226,4 @@ public class SeqNoFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; 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.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
@ -43,7 +42,6 @@ import org.elasticsearch.index.query.QueryShardException;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; 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 final Parameter<Boolean> enabled = Parameter.boolParam("enabled", false, m -> toType(m).enabled, Defaults.ENABLED);
private String[] excludes = null; 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() { public Builder() {
super(Defaults.NAME, new FieldType(Defaults.FIELD_TYPE)); super(Defaults.NAME);
} }
public Builder enabled(boolean enabled) { @Override
this.enabled = enabled; protected List<Parameter<?>> getParameters() {
return this; return Arrays.asList(enabled, includes, excludes);
}
public Builder includes(String[] includes) {
this.includes = includes;
return this;
}
public Builder excludes(String[] excludes) {
this.excludes = excludes;
return this;
} }
@Override @Override
public SourceFieldMapper build(BuilderContext context) { 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 { public static final TypeParser PARSER = new ConfigurableTypeParser(c -> new SourceFieldMapper(), 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.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();
}
}
static final class SourceFieldType extends MappedFieldType { static final class SourceFieldType extends MappedFieldType {
@ -177,32 +133,23 @@ public class SourceFieldMapper extends MetadataFieldMapper {
private final String[] excludes; private final String[] excludes;
private SourceFieldMapper() { private SourceFieldMapper() {
this(Defaults.ENABLED, null, null); this(Defaults.ENABLED, Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY);
} }
private SourceFieldMapper(boolean enabled, String[] includes, String[] excludes) { 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.enabled = enabled;
this.includes = includes; this.includes = includes;
this.excludes = excludes; this.excludes = excludes;
final boolean filtered = CollectionUtils.isEmpty(includes) == false || CollectionUtils.isEmpty(excludes) == false; final boolean filtered = CollectionUtils.isEmpty(includes) == false || CollectionUtils.isEmpty(excludes) == false;
this.filter = enabled && filtered && fieldType.stored() ? XContentMapValues.filter(includes, excludes) : null; this.filter = enabled && filtered ? XContentMapValues.filter(includes, excludes) : null;
this.complete = enabled && includes == null && excludes == null; this.complete = enabled && CollectionUtils.isEmpty(includes) && CollectionUtils.isEmpty(excludes);
} }
public boolean enabled() { public boolean enabled() {
return 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() { public boolean isComplete() {
return complete; return complete;
} }
@ -238,7 +185,7 @@ public class SourceFieldMapper extends MetadataFieldMapper {
@Nullable @Nullable
public BytesReference applyFilters(@Nullable BytesReference originalSource, @Nullable XContentType contentType) throws IOException { 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 // Percolate and tv APIs may not set the source and that is ok, because these APIs will not index any data
if (filter != null) { if (filter != null) {
// we don't update the context source if we filter, we want to keep it as is... // 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 @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public ParametrizedFieldMapper.Builder getMergeBuilder() {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false); return new Builder().init(this);
// 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;
} }
@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.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.lucene.search.Queries; 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.IndexFieldData;
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData; import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
@ -52,7 +50,6 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
@ -64,35 +61,18 @@ public class TypeFieldMapper extends MetadataFieldMapper {
public static final String CONTENT_TYPE = "_type"; public static final String CONTENT_TYPE = "_type";
public static final TypeParser PARSER = new FixedTypeParser(c -> new TypeFieldMapper());
public static class Defaults { public static class Defaults {
public static final String NAME = TypeFieldMapper.NAME;
public static final FieldType FIELD_TYPE = new FieldType(); public static final FieldType NESTED_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(FIELD_TYPE);
static { static {
NESTED_FIELD_TYPE.setIndexOptions(IndexOptions.DOCS); NESTED_FIELD_TYPE.setIndexOptions(IndexOptions.DOCS);
} NESTED_FIELD_TYPE.setTokenized(false);
} NESTED_FIELD_TYPE.setStored(false);
NESTED_FIELD_TYPE.setOmitNorms(true);
public static class TypeParser implements MetadataFieldMapper.TypeParser { NESTED_FIELD_TYPE.freeze();
@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);
} }
} }
@ -275,8 +255,8 @@ public class TypeFieldMapper extends MetadataFieldMapper {
} }
} }
private TypeFieldMapper(FieldType fieldType) { private TypeFieldMapper() {
super(fieldType, new TypeFieldType()); super(new TypeFieldType());
} }
@Override @Override
@ -305,9 +285,4 @@ public class TypeFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; 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; package org.elasticsearch.index.mapper;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.NumericDocValuesField; 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.DocValuesFieldExistsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.mapper.ParseContext.Document; import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.index.query.QueryShardException;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
/** Mapper for the _version field. */ /** Mapper for the _version field. */
public class VersionFieldMapper extends MetadataFieldMapper { public class VersionFieldMapper extends MetadataFieldMapper {
@ -41,31 +36,7 @@ public class VersionFieldMapper extends MetadataFieldMapper {
public static final String NAME = "_version"; public static final String NAME = "_version";
public static final String CONTENT_TYPE = "_version"; public static final String CONTENT_TYPE = "_version";
public static class Defaults { public static final TypeParser PARSER = new FixedTypeParser(c -> new VersionFieldMapper());
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();
}
}
static final class VersionFieldType extends MappedFieldType { static final class VersionFieldType extends MappedFieldType {
@ -92,7 +63,7 @@ public class VersionFieldMapper extends MetadataFieldMapper {
} }
private VersionFieldMapper() { private VersionFieldMapper() {
super(Defaults.FIELD_TYPE, Defaults.MAPPED_FIELD_TYPE); super(VersionFieldType.INSTANCE);
} }
@Override @Override
@ -129,9 +100,4 @@ public class VersionFieldMapper extends MetadataFieldMapper {
return CONTENT_TYPE; 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 // Use a LinkedHashMap for metadataMappers because iteration order matters
builtInMetadataMappers = new LinkedHashMap<>(); builtInMetadataMappers = new LinkedHashMap<>();
// _ignored first so that we always load it, even if only _id is requested // _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 // ID second so it will be the first (if no ignored fields) stored field to load
// (so will benefit from "fields: []" early termination // (so will benefit from "fields: []" early termination
builtInMetadataMappers.put(IdFieldMapper.NAME, new IdFieldMapper.TypeParser()); builtInMetadataMappers.put(IdFieldMapper.NAME, IdFieldMapper.PARSER);
builtInMetadataMappers.put(RoutingFieldMapper.NAME, new RoutingFieldMapper.TypeParser()); builtInMetadataMappers.put(RoutingFieldMapper.NAME, RoutingFieldMapper.PARSER);
builtInMetadataMappers.put(IndexFieldMapper.NAME, new IndexFieldMapper.TypeParser()); builtInMetadataMappers.put(IndexFieldMapper.NAME, IndexFieldMapper.PARSER);
builtInMetadataMappers.put(SourceFieldMapper.NAME, new SourceFieldMapper.TypeParser()); builtInMetadataMappers.put(SourceFieldMapper.NAME, SourceFieldMapper.PARSER);
builtInMetadataMappers.put(TypeFieldMapper.NAME, new TypeFieldMapper.TypeParser()); builtInMetadataMappers.put(TypeFieldMapper.NAME, TypeFieldMapper.PARSER);
builtInMetadataMappers.put(VersionFieldMapper.NAME, new VersionFieldMapper.TypeParser()); builtInMetadataMappers.put(VersionFieldMapper.NAME, VersionFieldMapper.PARSER);
builtInMetadataMappers.put(SeqNoFieldMapper.NAME, new SeqNoFieldMapper.TypeParser()); builtInMetadataMappers.put(SeqNoFieldMapper.NAME, SeqNoFieldMapper.PARSER);
//_field_names must be added last so that it has a chance to see all the other mappers //_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); return Collections.unmodifiableMap(builtInMetadataMappers);
} }

View File

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

View File

@ -43,6 +43,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; 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_NAME;
import static org.elasticsearch.search.suggest.completion.context.ContextMapping.FIELD_TYPE; 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); ContextMappings other = ((ContextMappings) obj);
return contextMappings.equals(other.contextMappings); 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; package org.elasticsearch.cluster.metadata;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener; 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.unit.TimeValue;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException; import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.MetadataFieldMapper; import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.ParametrizedFieldMapper;
import org.elasticsearch.index.mapper.ParseContext; import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TextSearchInfo; import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
@ -75,6 +75,7 @@ import java.util.stream.Collectors;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.elasticsearch.cluster.metadata.MetadataIndexTemplateService.DEFAULT_TIMESTAMP_FIELD; import static org.elasticsearch.cluster.metadata.MetadataIndexTemplateService.DEFAULT_TIMESTAMP_FIELD;
import static org.elasticsearch.common.settings.Settings.builder; 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.elasticsearch.indices.ShardLimitValidatorTests.createTestShardLimitService;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.containsStringIgnoringCase; import static org.hamcrest.CoreMatchers.containsStringIgnoringCase;
@ -1550,75 +1551,77 @@ public class MetadataIndexTemplateServiceTests extends ESSingleNodeTestCase {
@Override @Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() { 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 @Override
public MetadataFieldMapper.Builder<?> parse(String name, public String typeName() {
Map<String, Object> node, return "_data_stream_timestamp";
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);
}
};
} }
@Override @Override
public MetadataFieldMapper getDefault(MappedFieldType fieldType, ParserContext parserContext) { public Query termQuery(Object value, QueryShardContext context) {
return newInstance(null); return null;
} }
MetadataFieldMapper newInstance(Boolean enabled) { @Override
FieldType fieldType = new FieldType(); public Query existsQuery(QueryShardContext context) {
fieldType.freeze(); return null;
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";
}
};
} }
}); });
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); IndexService indexService = createIndex("test", settings);
MapperRegistry mapperRegistry = new MapperRegistry( MapperRegistry mapperRegistry = new MapperRegistry(
singletonMap(ExternalMapperPlugin.EXTERNAL, new ExternalMapper.TypeParser(ExternalMapperPlugin.EXTERNAL, "foo")), 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 = () -> { Supplier<QueryShardContext> queryShardContext = () -> {
return indexService.newQueryShardContext(0, null, () -> { throw new UnsupportedOperationException(); }, null); return indexService.newQueryShardContext(0, null, () -> { throw new UnsupportedOperationException(); }, null);

View File

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

View File

@ -81,10 +81,10 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
FieldNamesFieldMapper fieldNamesMapper = docMapper.metadataMapper(FieldNamesFieldMapper.class); FieldNamesFieldMapper fieldNamesMapper = docMapper.metadataMapper(FieldNamesFieldMapper.class);
assertFalse(fieldNamesMapper.fieldType().hasDocValues()); assertFalse(fieldNamesMapper.fieldType().hasDocValues());
assertEquals(IndexOptions.DOCS, fieldNamesMapper.fieldType.indexOptions()); assertEquals(IndexOptions.DOCS, FieldNamesFieldMapper.Defaults.FIELD_TYPE.indexOptions());
assertFalse(fieldNamesMapper.fieldType.tokenized()); assertFalse(FieldNamesFieldMapper.Defaults.FIELD_TYPE.tokenized());
assertFalse(fieldNamesMapper.fieldType.stored()); assertFalse(FieldNamesFieldMapper.Defaults.FIELD_TYPE.stored());
assertTrue(fieldNamesMapper.fieldType.omitNorms()); assertTrue(FieldNamesFieldMapper.Defaults.FIELD_TYPE.omitNorms());
} }
public void testInjectIntoDocDuringParsing() throws Exception { public void testInjectIntoDocDuringParsing() throws Exception {
@ -124,7 +124,7 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
XContentType.JSON)); XContentType.JSON));
assertFieldNames(set("field"), doc); assertFieldNames(set("field"), doc);
assertWarnings(FieldNamesFieldMapper.TypeParser.ENABLED_DEPRECATION_MESSAGE.replace("{}", "test")); assertWarnings(FieldNamesFieldMapper.ENABLED_DEPRECATION_MESSAGE);
} }
public void testDisabled() throws Exception { public void testDisabled() throws Exception {
@ -144,7 +144,7 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
XContentType.JSON)); XContentType.JSON));
assertNull(doc.rootDoc().get("_field_names")); 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 { public void testMergingMappings() throws Exception {
@ -164,6 +164,6 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
DocumentMapper mapperEnabled DocumentMapper mapperEnabled
= mapperService.merge("type", new CompressedXContent(enabledMapping), MapperService.MergeReason.MAPPING_UPDATE); = mapperService.merge("type", new CompressedXContent(enabledMapping), MapperService.MergeReason.MAPPING_UPDATE);
assertTrue(mapperEnabled.metadataMapper(FieldNamesFieldMapper.class).fieldType().isEnabled()); 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() { public void testTermQuery() {
FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = new FieldNamesFieldMapper.FieldNamesFieldType(); FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = new FieldNamesFieldMapper.FieldNamesFieldType(true);
KeywordFieldMapper.KeywordFieldType fieldType = new KeywordFieldMapper.KeywordFieldType("field_name"); KeywordFieldMapper.KeywordFieldType fieldType = new KeywordFieldMapper.KeywordFieldType("field_name");
Settings settings = settings(Version.CURRENT).build(); Settings settings = settings(Version.CURRENT).build();
@ -52,12 +52,12 @@ public class FieldNamesFieldTypeTests extends ESTestCase {
QueryShardContext queryShardContext = new QueryShardContext(0, QueryShardContext queryShardContext = new QueryShardContext(0,
indexSettings, BigArrays.NON_RECYCLING_INSTANCE, null, null, mapperService, indexSettings, BigArrays.NON_RECYCLING_INSTANCE, null, null, mapperService,
null, null, null, null, null, null, () -> 0L, null, null, () -> true, null); 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); 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"); 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()); 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 final Parameter<String> variable
= Parameter.stringParam("variable", true, m -> toType(m).variable, "default").acceptsNull(); = Parameter.stringParam("variable", true, m -> toType(m).variable, "default").acceptsNull();
final Parameter<StringWrapper> wrapper final Parameter<StringWrapper> wrapper
= new Parameter<>("wrapper", true, () -> new StringWrapper("default"), = new Parameter<>("wrapper", false, () -> new StringWrapper("default"),
(n, c, o) -> { (n, c, o) -> {
if (o == null) return null; if (o == null) return null;
return new StringWrapper(o.toString()); 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) final Parameter<Integer> intValue = Parameter.intParam("int_value", true, m -> toType(m).intValue, 5)
.setValidator(n -> { .setValidator(n -> {
if (n > 50) { if (n > 50) {
@ -112,7 +112,7 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
} }
}); });
final Parameter<NamedAnalyzer> analyzer 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 final Parameter<NamedAnalyzer> searchAnalyzer
= Parameter.analyzerParam("search_analyzer", true, m -> toType(m).searchAnalyzer, analyzer::getValue); = Parameter.analyzerParam("search_analyzer", true, m -> toType(m).searchAnalyzer, analyzer::getValue);
final Parameter<Boolean> index = Parameter.boolParam("index", false, m -> toType(m).index, true); 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); TestMapper mapper = fromMapping(mapping);
assertEquals("wrapped value", mapper.wrapper.name); assertEquals("wrapped value", mapper.wrapper.name);
assertEquals("{\"field\":" + mapping + "}", Strings.toString(mapper)); 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 // test validator
@ -383,6 +389,12 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
String badAnalyzer = "{\"type\":\"test_mapper\",\"analyzer\":\"wibble\",\"required\":\"value\"}"; String badAnalyzer = "{\"type\":\"test_mapper\",\"analyzer\":\"wibble\",\"required\":\"value\"}";
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> fromMapping(badAnalyzer)); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> fromMapping(badAnalyzer));
assertEquals("analyzer [wibble] has not been configured in mappings", e.getMessage()); 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() { public void testDeprecatedParameters() {

View File

@ -97,7 +97,7 @@ public class SourceFieldMapperTests extends ESSingleNodeTestCase {
public void testExcludes() throws Exception { public void testExcludes() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") 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()); .endObject().endObject());
DocumentMapper documentMapper = createIndex("test").mapperService().documentMapperParser() DocumentMapper documentMapper = createIndex("test").mapperService().documentMapperParser()
@ -126,7 +126,7 @@ public class SourceFieldMapperTests extends ESSingleNodeTestCase {
String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").field("enabled", false).endObject() .startObject("_source").field("enabled", false).endObject()
.endObject().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 // not changing is ok
String mapping3 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") 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") String mapping1 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("includes", "foo.*").endObject() .startObject("_source").array("includes", "foo.*").endObject()
.endObject().endObject()); .endObject().endObject());
assertConflicts(defaultMapping, mapping1, parser, "Cannot update includes setting for [_source]"); assertConflicts(defaultMapping, mapping1, parser, "Cannot update parameter [includes] from [[]] to [[foo.*]]");
assertConflicts(mapping1, defaultMapping, parser, "Cannot update includes setting for [_source]"); assertConflicts(mapping1, defaultMapping, parser, "Cannot update parameter [includes] from [[foo.*]] to [[]]");
String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("includes", "foo.*", "bar.*").endObject() .startObject("_source").array("includes", "foo.*", "bar.*").endObject()
.endObject().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 // not changing is ok
assertConflicts(mapping1, mapping1, parser); assertConflicts(mapping1, mapping1, parser);
@ -159,13 +159,13 @@ public class SourceFieldMapperTests extends ESSingleNodeTestCase {
String mapping1 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") String mapping1 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("excludes", "foo.*").endObject() .startObject("_source").array("excludes", "foo.*").endObject()
.endObject().endObject()); .endObject().endObject());
assertConflicts(defaultMapping, mapping1, parser, "Cannot update excludes setting for [_source]"); assertConflicts(defaultMapping, mapping1, parser, "Cannot update parameter [excludes] from [[]] to [[foo.*]]");
assertConflicts(mapping1, defaultMapping, parser, "Cannot update excludes setting for [_source]"); assertConflicts(mapping1, defaultMapping, parser, "Cannot update parameter [excludes] from [[foo.*]] to [[]]");
String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_source").array("excludes", "foo.*", "bar.*").endObject() .startObject("_source").array("excludes", "foo.*", "bar.*").endObject()
.endObject().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 // not changing is ok
assertConflicts(mapping1, mapping1, parser); 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.IndexSettings;
import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.plain.AbstractLeafOrdinalsFieldData; import org.elasticsearch.index.fielddata.plain.AbstractLeafOrdinalsFieldData;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.IndexFieldMapper; import org.elasticsearch.index.mapper.IndexFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.TextFieldMapper; import org.elasticsearch.index.mapper.TextFieldMapper;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
@ -117,8 +115,7 @@ public class QueryShardContextTests extends ESTestCase {
final String clusterAlias = randomBoolean() ? null : "remote_cluster"; final String clusterAlias = randomBoolean() ? null : "remote_cluster";
QueryShardContext context = createQueryShardContext(IndexMetadata.INDEX_UUID_NA_VALUE, clusterAlias); QueryShardContext context = createQueryShardContext(IndexMetadata.INDEX_UUID_NA_VALUE, clusterAlias);
Mapper.BuilderContext ctx = new Mapper.BuilderContext(context.getIndexSettings().getSettings(), new ContentPath()); IndexFieldMapper mapper = new IndexFieldMapper();
IndexFieldMapper mapper = new IndexFieldMapper.Builder().build(ctx);
IndexFieldData<?> forField = context.getForField(mapper.fieldType()); IndexFieldData<?> forField = context.getForField(mapper.fieldType());
String expected = clusterAlias == null ? context.getIndexSettings().getIndexMetadata().getIndex().getName() String expected = clusterAlias == null ? context.getIndexSettings().getIndexMetadata().getIndex().getName()

View File

@ -1105,7 +1105,7 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
"enabled=true"))), "enabled=true"))),
MapperService.MergeReason.MAPPING_UPDATE); MapperService.MergeReason.MAPPING_UPDATE);
} }
assertWarnings(FieldNamesFieldMapper.TypeParser.ENABLED_DEPRECATION_MESSAGE.replace("{}", context.index().getName())); assertWarnings(FieldNamesFieldMapper.ENABLED_DEPRECATION_MESSAGE);
} }
public void testFromJson() throws IOException { 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.IdFieldMapper;
import org.elasticsearch.index.mapper.IgnoredFieldMapper; import org.elasticsearch.index.mapper.IgnoredFieldMapper;
import org.elasticsearch.index.mapper.IndexFieldMapper; import org.elasticsearch.index.mapper.IndexFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException; import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MetadataFieldMapper; import org.elasticsearch.index.mapper.MetadataFieldMapper;
@ -63,17 +62,7 @@ public class IndicesModuleTests extends ESTestCase {
} }
} }
private static class FakeMetadataMapperParser implements MetadataFieldMapper.TypeParser { private static final MetadataFieldMapper.TypeParser PARSER = new MetadataFieldMapper.ConfigurableTypeParser(c -> null, c -> null);
@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 final List<MapperPlugin> fakePlugins = Arrays.asList(new MapperPlugin() { private final List<MapperPlugin> fakePlugins = Arrays.asList(new MapperPlugin() {
@Override @Override
@ -82,7 +71,7 @@ public class IndicesModuleTests extends ESTestCase {
} }
@Override @Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() { 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() { List<MapperPlugin> plugins = Arrays.asList(new MapperPlugin() {
@Override @Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() { public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap(IdFieldMapper.NAME, new FakeMetadataMapperParser()); return Collections.singletonMap(IdFieldMapper.NAME, PARSER);
} }
}); });
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
@ -192,7 +181,7 @@ public class IndicesModuleTests extends ESTestCase {
MapperPlugin plugin = new MapperPlugin() { MapperPlugin plugin = new MapperPlugin() {
@Override @Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() { public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap("foo", new FakeMetadataMapperParser()); return Collections.singletonMap("foo", PARSER);
} }
}; };
List<MapperPlugin> plugins = Arrays.asList(plugin, plugin); List<MapperPlugin> plugins = Arrays.asList(plugin, plugin);
@ -205,7 +194,7 @@ public class IndicesModuleTests extends ESTestCase {
List<MapperPlugin> plugins = Arrays.asList(new MapperPlugin() { List<MapperPlugin> plugins = Arrays.asList(new MapperPlugin() {
@Override @Override
public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() { public Map<String, MetadataFieldMapper.TypeParser> getMetadataMappers() {
return Collections.singletonMap(FieldNamesFieldMapper.NAME, new FakeMetadataMapperParser()); return Collections.singletonMap(FieldNamesFieldMapper.NAME, PARSER);
} }
}); });
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, IllegalArgumentException e = expectThrows(IllegalArgumentException.class,

View File

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

View File

@ -6,23 +6,20 @@
package org.elasticsearch.xpack.datastreams.mapper; package org.elasticsearch.xpack.datastreams.mapper;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.DocValuesType; import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.mapper.DateFieldMapper; import org.elasticsearch.index.mapper.DateFieldMapper;
import org.elasticsearch.index.mapper.MappingLookup; import org.elasticsearch.index.mapper.MappingLookup;
import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MetadataFieldMapper; import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.ParametrizedFieldMapper;
import org.elasticsearch.index.mapper.ParseContext; import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TextSearchInfo; import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
@ -31,10 +28,8 @@ import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; 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"; public static final String NAME = "_data_stream_timestamp";
private static final String DEFAULT_PATH = "@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. // 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. // In the future it should act as an alias to the actual data stream timestamp field.
public static final class TimestampFieldType extends MappedFieldType { 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() { public Builder() {
super(NAME, Defaults.TIMESTAMP_FIELD_TYPE); super(NAME);
} }
public void setEnabled(boolean enabled) { @Override
this.enabled = enabled; protected List<Parameter<?>> getParameters() {
return Collections.singletonList(enabled);
} }
@Override @Override
public MetadataFieldMapper build(BuilderContext context) { 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 private final String path = DEFAULT_PATH;
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 boolean enabled; private final boolean enabled;
private DataStreamTimestampFieldMapper(FieldType fieldType, MappedFieldType mappedFieldType, boolean enabled) { private DataStreamTimestampFieldMapper(MappedFieldType mappedFieldType, boolean enabled) {
super(fieldType, mappedFieldType); super(mappedFieldType);
this.path = DEFAULT_PATH;
this.enabled = enabled; this.enabled = enabled;
} }
@Override @Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder().init(this);
}
public void doValidate(MappingLookup lookup) { public void doValidate(MappingLookup lookup) {
if (enabled == false) { if (enabled == false) {
// not configured, so skip the validation // 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 @Override
protected String contentType() { protected String contentType() {
return NAME; 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\"}}}}}"; "{\"type\":{\"_data_stream_timestamp\":{\"enabled\":false}, \"properties\": {\"@timestamp\": {\"type\": \"date\"}}}}}";
String mapping2 = "{\"type\":{\"_data_stream_timestamp\":{\"enabled\":true}, \"properties\": {\"@timestamp2\": " String mapping2 = "{\"type\":{\"_data_stream_timestamp\":{\"enabled\":true}, \"properties\": {\"@timestamp2\": "
+ "{\"type\": \"date\"},\"@timestamp\": {\"type\": \"date\"}}}})"; + "{\"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\"}}}}}"; mapping1 = "{\"type\":{\"properties\":{\"@timestamp\": {\"type\": \"date\"}}}}}";
mapping2 = "{\"type\":{\"_data_stream_timestamp\":{\"enabled\":true}, \"properties\": " mapping2 = "{\"type\":{\"_data_stream_timestamp\":{\"enabled\":true}, \"properties\": "
+ "{\"@timestamp2\": {\"type\": \"date\"},\"@timestamp\": {\"type\": \"date\"}}}})"; + "{\"@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]");
} }
} }