mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-24 17:09:48 +00:00
Convert KeywordFieldMapper to parametrized form (#60645)
This makes KeywordFieldMapper extend ParametrizedFieldMapper, with explicitly defined parameters. In addition, we add a new option to Parameter, restrictedStringParam, which accepts a restricted set of string options.
This commit is contained in:
parent
3a046e125d
commit
c81dc2b8b7
@ -153,8 +153,6 @@ public class PercolatorFieldMapper extends FieldMapper {
|
||||
static KeywordFieldMapper createExtractQueryFieldBuilder(String name, BuilderContext context) {
|
||||
KeywordFieldMapper.Builder queryMetadataFieldBuilder = new KeywordFieldMapper.Builder(name);
|
||||
queryMetadataFieldBuilder.docValues(false);
|
||||
queryMetadataFieldBuilder.store(false);
|
||||
queryMetadataFieldBuilder.indexOptions(IndexOptions.DOCS);
|
||||
return queryMetadataFieldBuilder.build(context);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
package org.elasticsearch.index.mapper;
|
||||
|
||||
import org.apache.lucene.analysis.TokenStream;
|
||||
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
|
||||
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.FieldType;
|
||||
@ -33,34 +32,27 @@ import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.lucene.Lucene;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.index.analysis.AnalyzerScope;
|
||||
import org.elasticsearch.index.analysis.IndexAnalyzers;
|
||||
import org.elasticsearch.index.analysis.NamedAnalyzer;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.similarity.SimilarityProvider;
|
||||
import org.elasticsearch.index.similarity.SimilarityService;
|
||||
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.index.mapper.TypeParsers.checkNull;
|
||||
import static org.elasticsearch.index.mapper.TypeParsers.parseField;
|
||||
|
||||
/**
|
||||
* A field mapper for keywords. This mapper accepts strings and indexes them as-is.
|
||||
*/
|
||||
public final class KeywordFieldMapper extends FieldMapper {
|
||||
public final class KeywordFieldMapper extends ParametrizedFieldMapper {
|
||||
|
||||
public static final String CONTENT_TYPE = "keyword";
|
||||
|
||||
@ -73,11 +65,6 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||
FIELD_TYPE.setIndexOptions(IndexOptions.DOCS);
|
||||
FIELD_TYPE.freeze();
|
||||
}
|
||||
|
||||
public static final String NULL_VALUE = null;
|
||||
public static final int IGNORE_ABOVE = Integer.MAX_VALUE;
|
||||
public static final boolean EAGER_GLOBAL_ORDINALS = false;
|
||||
public static final boolean SPLIT_QUERIES_ON_WHITESPACE = false;
|
||||
}
|
||||
|
||||
public static class KeywordField extends Field {
|
||||
@ -86,147 +73,128 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||
super(field, term, ft);
|
||||
}
|
||||
|
||||
public KeywordField(String field, BytesRef term) {
|
||||
super(field, term, Defaults.FIELD_TYPE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Builder extends FieldMapper.Builder<Builder> {
|
||||
private static KeywordFieldMapper toType(FieldMapper in) {
|
||||
return (KeywordFieldMapper) in;
|
||||
}
|
||||
|
||||
protected String nullValue = Defaults.NULL_VALUE;
|
||||
protected int ignoreAbove = Defaults.IGNORE_ABOVE;
|
||||
private IndexAnalyzers indexAnalyzers;
|
||||
private String normalizerName = "default";
|
||||
private boolean eagerGlobalOrdinals = Defaults.EAGER_GLOBAL_ORDINALS;
|
||||
private boolean splitQueriesOnWhitespace = Defaults.SPLIT_QUERIES_ON_WHITESPACE;
|
||||
private SimilarityProvider similarity;
|
||||
public static class Builder extends ParametrizedFieldMapper.Builder {
|
||||
|
||||
private final Parameter<Boolean> indexed = Parameter.indexParam(m -> toType(m).indexed, true);
|
||||
private final Parameter<Boolean> hasDocValues = Parameter.docValuesParam(m -> toType(m).hasDocValues, true);
|
||||
private final Parameter<Boolean> stored = Parameter.storeParam(m -> toType(m).fieldType.stored(), false);
|
||||
|
||||
private final Parameter<String> nullValue = Parameter.stringParam("null_value", false, m -> toType(m).nullValue, null);
|
||||
|
||||
private final Parameter<Boolean> eagerGlobalOrdinals
|
||||
= Parameter.boolParam("eager_global_ordinals", true, m -> toType(m).eagerGlobalOrdinals, false);
|
||||
private final Parameter<Integer> ignoreAbove
|
||||
= Parameter.intParam("ignore_above", true, m -> toType(m).ignoreAbove, Integer.MAX_VALUE);
|
||||
|
||||
private final Parameter<String> indexOptions
|
||||
= Parameter.restrictedStringParam("index_options", false, m -> toType(m).indexOptions, "docs", "freqs");
|
||||
private final Parameter<Boolean> hasNorms
|
||||
= Parameter.boolParam("norms", false, m -> toType(m).fieldType.omitNorms() == false, false);
|
||||
private final Parameter<SimilarityProvider> similarity = new Parameter<>("similarity", false, () -> null,
|
||||
(n, c, o) -> TypeParsers.resolveSimilarity(c, n, o.toString()), m -> toType(m).similarity);
|
||||
|
||||
private final Parameter<String> normalizer
|
||||
= Parameter.stringParam("normalizer", false, m -> toType(m).normalizerName, "default");
|
||||
|
||||
private final Parameter<Boolean> splitQueriesOnWhitespace
|
||||
= Parameter.boolParam("split_queries_on_whitespace", true, m -> toType(m).splitQueriesOnWhitespace, false);
|
||||
|
||||
private final Parameter<Map<String, String>> meta = Parameter.metaParam();
|
||||
private final Parameter<Float> boost = Parameter.boostParam();
|
||||
|
||||
private final IndexAnalyzers indexAnalyzers;
|
||||
|
||||
public Builder(String name, IndexAnalyzers indexAnalyzers) {
|
||||
super(name);
|
||||
this.indexAnalyzers = indexAnalyzers;
|
||||
}
|
||||
|
||||
public Builder(String name) {
|
||||
super(name, Defaults.FIELD_TYPE);
|
||||
builder = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder omitNorms(boolean omitNorms) {
|
||||
fieldType.setOmitNorms(omitNorms);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public void similarity(SimilarityProvider similarity) {
|
||||
this.similarity = similarity;
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
public Builder ignoreAbove(int ignoreAbove) {
|
||||
if (ignoreAbove < 0) {
|
||||
throw new IllegalArgumentException("[ignore_above] must be positive, got " + ignoreAbove);
|
||||
}
|
||||
this.ignoreAbove = ignoreAbove;
|
||||
this.ignoreAbove.setValue(ignoreAbove);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder indexOptions(IndexOptions indexOptions) {
|
||||
if (indexOptions.compareTo(IndexOptions.DOCS_AND_FREQS) > 0) {
|
||||
throw new IllegalArgumentException("The [keyword] field does not support positions, got [index_options]="
|
||||
+ indexOptionToString(indexOptions));
|
||||
Builder normalizer(String normalizerName) {
|
||||
this.normalizer.setValue(normalizerName);
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder nullValue(String nullValue) {
|
||||
this.nullValue.setValue(nullValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder docValues(boolean hasDocValues) {
|
||||
this.hasDocValues.setValue(hasDocValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static IndexOptions toIndexOptions(boolean indexed, String in) {
|
||||
if (indexed == false) {
|
||||
return IndexOptions.NONE;
|
||||
}
|
||||
return super.indexOptions(indexOptions);
|
||||
switch (in) {
|
||||
case "docs":
|
||||
return IndexOptions.DOCS;
|
||||
case "freqs":
|
||||
return IndexOptions.DOCS_AND_FREQS;
|
||||
}
|
||||
throw new MapperParsingException("Unknown index option [" + in + "]");
|
||||
}
|
||||
|
||||
public Builder eagerGlobalOrdinals(boolean eagerGlobalOrdinals) {
|
||||
this.eagerGlobalOrdinals = eagerGlobalOrdinals;
|
||||
return builder;
|
||||
@Override
|
||||
protected List<Parameter<?>> getParameters() {
|
||||
return Arrays.asList(indexed, hasDocValues, stored, nullValue, eagerGlobalOrdinals, ignoreAbove,
|
||||
indexOptions, hasNorms, similarity, normalizer, splitQueriesOnWhitespace, boost, meta);
|
||||
}
|
||||
|
||||
public Builder splitQueriesOnWhitespace(boolean splitQueriesOnWhitespace) {
|
||||
this.splitQueriesOnWhitespace = splitQueriesOnWhitespace;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder normalizer(IndexAnalyzers indexAnalyzers, String name) {
|
||||
this.indexAnalyzers = indexAnalyzers;
|
||||
this.normalizerName = name;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder nullValue(String nullValue) {
|
||||
this.nullValue = nullValue;
|
||||
return builder;
|
||||
}
|
||||
|
||||
private KeywordFieldType buildFieldType(BuilderContext context) {
|
||||
private KeywordFieldType buildFieldType(BuilderContext context, FieldType fieldType) {
|
||||
NamedAnalyzer normalizer = Lucene.KEYWORD_ANALYZER;
|
||||
NamedAnalyzer searchAnalyzer = Lucene.KEYWORD_ANALYZER;
|
||||
if (normalizerName == null || "default".equals(normalizerName) == false) {
|
||||
String normalizerName = this.normalizer.getValue();
|
||||
if (Objects.equals(normalizerName, "default") == false) {
|
||||
assert indexAnalyzers != null;
|
||||
normalizer = indexAnalyzers.getNormalizer(normalizerName);
|
||||
if (normalizer == null) {
|
||||
throw new MapperParsingException("normalizer [" + normalizerName + "] not found for field [" + name + "]");
|
||||
}
|
||||
if (splitQueriesOnWhitespace) {
|
||||
if (splitQueriesOnWhitespace.getValue()) {
|
||||
searchAnalyzer = indexAnalyzers.getWhitespaceNormalizer(normalizerName);
|
||||
} else {
|
||||
searchAnalyzer = normalizer;
|
||||
}
|
||||
}
|
||||
else if (splitQueriesOnWhitespace) {
|
||||
// TODO should this be a Lucene global analyzer as well?
|
||||
searchAnalyzer = new NamedAnalyzer("whitespace", AnalyzerScope.INDEX, new WhitespaceAnalyzer());
|
||||
else if (splitQueriesOnWhitespace.getValue()) {
|
||||
searchAnalyzer = Lucene.WHITESPACE_ANALYZER;
|
||||
}
|
||||
return new KeywordFieldType(buildFullName(context), hasDocValues, fieldType,
|
||||
eagerGlobalOrdinals, normalizer, searchAnalyzer, similarity, meta, boost);
|
||||
return new KeywordFieldType(buildFullName(context), hasDocValues.getValue(), fieldType,
|
||||
eagerGlobalOrdinals.getValue(), normalizer, searchAnalyzer,
|
||||
similarity.getValue(), boost.getValue(), meta.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeywordFieldMapper build(BuilderContext context) {
|
||||
return new KeywordFieldMapper(name,
|
||||
fieldType, buildFieldType(context), ignoreAbove, splitQueriesOnWhitespace, nullValue,
|
||||
multiFieldsBuilder.build(this, context), copyTo);
|
||||
FieldType fieldtype = new FieldType(Defaults.FIELD_TYPE);
|
||||
fieldtype.setOmitNorms(this.hasNorms.getValue() == false);
|
||||
fieldtype.setIndexOptions(toIndexOptions(this.indexed.getValue(), this.indexOptions.getValue()));
|
||||
fieldtype.setStored(this.stored.getValue());
|
||||
return new KeywordFieldMapper(name, fieldtype, buildFieldType(context, fieldtype),
|
||||
multiFieldsBuilder.build(this, context), copyTo.build(), this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeParser implements Mapper.TypeParser {
|
||||
@Override
|
||||
public Mapper.Builder<?> parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
|
||||
KeywordFieldMapper.Builder builder = new KeywordFieldMapper.Builder(name);
|
||||
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
|
||||
Map.Entry<String, Object> entry = iterator.next();
|
||||
String propName = entry.getKey();
|
||||
Object propNode = entry.getValue();
|
||||
checkNull(propName, propNode);
|
||||
if (propName.equals("null_value")) {
|
||||
if (propNode == null) {
|
||||
throw new MapperParsingException("Property [null_value] cannot be null.");
|
||||
}
|
||||
builder.nullValue(propNode.toString());
|
||||
iterator.remove();
|
||||
} else if (propName.equals("ignore_above")) {
|
||||
builder.ignoreAbove(XContentMapValues.nodeIntegerValue(propNode, -1));
|
||||
iterator.remove();
|
||||
} else if (propName.equals("norms")) {
|
||||
TypeParsers.parseNorms(builder, name, propNode);
|
||||
iterator.remove();
|
||||
} else if (propName.equals("eager_global_ordinals")) {
|
||||
builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(propNode, "eager_global_ordinals"));
|
||||
iterator.remove();
|
||||
} else if (propName.equals("normalizer")) {
|
||||
if (propNode != null) {
|
||||
builder.normalizer(parserContext.getIndexAnalyzers(), propNode.toString());
|
||||
}
|
||||
iterator.remove();
|
||||
} else if (propName.equals("split_queries_on_whitespace")) {
|
||||
builder.splitQueriesOnWhitespace(XContentMapValues.nodeBooleanValue(propNode, "split_queries_on_whitespace"));
|
||||
iterator.remove();
|
||||
} else if (propName.equals("similarity")) {
|
||||
SimilarityProvider similarityProvider = TypeParsers.resolveSimilarity(parserContext, name, propNode.toString());
|
||||
builder.similarity(similarityProvider);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
parseField(builder, name, node, parserContext);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
public static final TypeParser PARSER
|
||||
= new TypeParser((n, c) -> new Builder(n, c.getIndexAnalyzers()));
|
||||
|
||||
public static final class KeywordFieldType extends StringFieldType {
|
||||
|
||||
@ -234,7 +202,7 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||
|
||||
public KeywordFieldType(String name, boolean hasDocValues, FieldType fieldType,
|
||||
boolean eagerGlobalOrdinals, NamedAnalyzer normalizer, NamedAnalyzer searchAnalyzer,
|
||||
SimilarityProvider similarity, Map<String, String> meta, float boost) {
|
||||
SimilarityProvider similarity, float boost, Map<String, String> meta) {
|
||||
super(name, fieldType.indexOptions() != IndexOptions.NONE,
|
||||
hasDocValues, new TextSearchInfo(fieldType, similarity, searchAnalyzer, searchAnalyzer), meta);
|
||||
this.hasNorms = fieldType.omitNorms() == false;
|
||||
@ -250,7 +218,7 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||
|
||||
public KeywordFieldType(String name) {
|
||||
this(name, true, Defaults.FIELD_TYPE, false,
|
||||
Lucene.KEYWORD_ANALYZER, Lucene.KEYWORD_ANALYZER, null, Collections.emptyMap(), 1f);
|
||||
Lucene.KEYWORD_ANALYZER, Lucene.KEYWORD_ANALYZER, null, 1.0f, Collections.emptyMap());
|
||||
}
|
||||
|
||||
public KeywordFieldType(String name, NamedAnalyzer analyzer) {
|
||||
@ -314,18 +282,35 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||
}
|
||||
}
|
||||
|
||||
private int ignoreAbove;
|
||||
private boolean splitQueriesOnWhitespace;
|
||||
private String nullValue;
|
||||
private final boolean indexed;
|
||||
private final boolean hasDocValues;
|
||||
private final String nullValue;
|
||||
private final boolean eagerGlobalOrdinals;
|
||||
private final int ignoreAbove;
|
||||
private final String indexOptions;
|
||||
private final FieldType fieldType;
|
||||
private final SimilarityProvider similarity;
|
||||
private final String normalizerName;
|
||||
private final boolean splitQueriesOnWhitespace;
|
||||
|
||||
private final IndexAnalyzers indexAnalyzers;
|
||||
|
||||
protected KeywordFieldMapper(String simpleName, FieldType fieldType, MappedFieldType mappedFieldType,
|
||||
int ignoreAbove, boolean splitQueriesOnWhitespace, String nullValue,
|
||||
MultiFields multiFields, CopyTo copyTo) {
|
||||
super(simpleName, fieldType, mappedFieldType, multiFields, copyTo);
|
||||
MultiFields multiFields, CopyTo copyTo, Builder builder) {
|
||||
super(simpleName, mappedFieldType, multiFields, copyTo);
|
||||
assert fieldType.indexOptions().compareTo(IndexOptions.DOCS_AND_FREQS) <= 0;
|
||||
this.ignoreAbove = ignoreAbove;
|
||||
this.splitQueriesOnWhitespace = splitQueriesOnWhitespace;
|
||||
this.nullValue = nullValue;
|
||||
this.indexed = builder.indexed.getValue();
|
||||
this.hasDocValues = builder.hasDocValues.getValue();
|
||||
this.nullValue = builder.nullValue.getValue();
|
||||
this.eagerGlobalOrdinals = builder.eagerGlobalOrdinals.getValue();
|
||||
this.ignoreAbove = builder.ignoreAbove.getValue();
|
||||
this.indexOptions = builder.indexOptions.getValue();
|
||||
this.fieldType = fieldType;
|
||||
this.similarity = builder.similarity.getValue();
|
||||
this.normalizerName = builder.normalizer.getValue();
|
||||
this.splitQueriesOnWhitespace = builder.splitQueriesOnWhitespace.getValue();
|
||||
|
||||
this.indexAnalyzers = builder.indexAnalyzers;
|
||||
}
|
||||
|
||||
/** Values that have more chars than the return value of this method will
|
||||
@ -437,56 +422,7 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
|
||||
KeywordFieldMapper k = (KeywordFieldMapper) other;
|
||||
if (Objects.equals(fieldType().indexAnalyzer(), k.fieldType().indexAnalyzer()) == false) {
|
||||
conflicts.add("mapper [" + name() + "] has different [normalizer]");
|
||||
}
|
||||
if (Objects.equals(mappedFieldType.getTextSearchInfo().getSimilarity(),
|
||||
k.fieldType().getTextSearchInfo().getSimilarity()) == false) {
|
||||
conflicts.add("mapper [" + name() + "] has different [similarity]");
|
||||
}
|
||||
this.ignoreAbove = k.ignoreAbove;
|
||||
this.splitQueriesOnWhitespace = k.splitQueriesOnWhitespace;
|
||||
this.fieldType().setBoost(k.fieldType().boost());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
|
||||
super.doXContentBody(builder, includeDefaults, params);
|
||||
|
||||
if (fieldType.indexOptions() != IndexOptions.NONE
|
||||
&& (includeDefaults || fieldType.indexOptions() != Defaults.FIELD_TYPE.indexOptions())) {
|
||||
builder.field("index_options", indexOptionToString(fieldType.indexOptions()));
|
||||
}
|
||||
if (nullValue != null) {
|
||||
builder.field("null_value", nullValue);
|
||||
}
|
||||
if (includeDefaults || ignoreAbove != Defaults.IGNORE_ABOVE) {
|
||||
builder.field("ignore_above", ignoreAbove);
|
||||
}
|
||||
if (includeDefaults || fieldType.omitNorms() != Defaults.FIELD_TYPE.omitNorms()) {
|
||||
builder.field("norms", fieldType.omitNorms() == false);
|
||||
}
|
||||
if (includeDefaults || fieldType().eagerGlobalOrdinals() != false) {
|
||||
builder.field("eager_global_ordinals", fieldType().eagerGlobalOrdinals());
|
||||
}
|
||||
|
||||
if (fieldType().normalizer() != null && fieldType().normalizer() != Lucene.KEYWORD_ANALYZER) {
|
||||
builder.field("normalizer", fieldType().normalizer().name());
|
||||
}
|
||||
else if (includeDefaults) {
|
||||
builder.field("normalizer", "default");
|
||||
}
|
||||
|
||||
if (fieldType().getTextSearchInfo().getSimilarity() != null) {
|
||||
builder.field("similarity", fieldType().getTextSearchInfo().getSimilarity().name());
|
||||
} else if (includeDefaults) {
|
||||
builder.field("similarity", SimilarityService.DEFAULT_SIMILARITY);
|
||||
}
|
||||
|
||||
if (includeDefaults || splitQueriesOnWhitespace) {
|
||||
builder.field("split_queries_on_whitespace", splitQueriesOnWhitespace);
|
||||
}
|
||||
public ParametrizedFieldMapper.Builder getMergeBuilder() {
|
||||
return new Builder(simpleName(), indexAnalyzers).init(this);
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -318,6 +319,28 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
|
||||
}, initializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a parameter that takes one of a restricted set of string values
|
||||
* @param name the parameter name
|
||||
* @param updateable whether the parameter can be changed by a mapping update
|
||||
* @param initializer a function that reads the parameter value from an existing mapper
|
||||
* @param values the set of values that the parameter can take. The first value in the list
|
||||
* is the default value, to be used if the parameter is undefined in a mapping
|
||||
*/
|
||||
public static Parameter<String> restrictedStringParam(String name, boolean updateable,
|
||||
Function<FieldMapper, String> initializer, String... values) {
|
||||
assert values.length > 0;
|
||||
Set<String> acceptedValues = new LinkedHashSet<>(Arrays.asList(values));
|
||||
return stringParam(name, updateable, initializer, values[0])
|
||||
.setValidator(v -> {
|
||||
if (acceptedValues.contains(v)) {
|
||||
return;
|
||||
}
|
||||
throw new MapperParsingException("Unknown value [" + v + "] for field [" + name +
|
||||
"] - accepted values are " + acceptedValues.toString());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a parameter that takes an analyzer name
|
||||
* @param name the parameter name
|
||||
|
@ -388,10 +388,11 @@ public class RootObjectMapper extends ObjectMapper {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, Object> fieldTypeConfig = dynamicTemplate.mappingForName("__dummy__", defaultDynamicType);
|
||||
fieldTypeConfig.remove("type");
|
||||
String templateName = "__dynamic__" + dynamicTemplate.name();
|
||||
Map<String, Object> fieldTypeConfig = dynamicTemplate.mappingForName(templateName, defaultDynamicType);
|
||||
try {
|
||||
Mapper.Builder<?> dummyBuilder = typeParser.parse("__dummy__", fieldTypeConfig, parserContext);
|
||||
Mapper.Builder<?> dummyBuilder = typeParser.parse(templateName, fieldTypeConfig, parserContext);
|
||||
fieldTypeConfig.remove("type");
|
||||
if (fieldTypeConfig.isEmpty()) {
|
||||
Settings indexSettings = parserContext.mapperService().getIndexSettings().getSettings();
|
||||
BuilderContext builderContext = new BuilderContext(indexSettings, new ContentPath(1));
|
||||
|
@ -127,7 +127,7 @@ public class IndicesModule extends AbstractModule {
|
||||
mappers.put(nanoseconds.type(), DateFieldMapper.NANOS_PARSER);
|
||||
mappers.put(IpFieldMapper.CONTENT_TYPE, IpFieldMapper.PARSER);
|
||||
mappers.put(TextFieldMapper.CONTENT_TYPE, new TextFieldMapper.TypeParser());
|
||||
mappers.put(KeywordFieldMapper.CONTENT_TYPE, new KeywordFieldMapper.TypeParser());
|
||||
mappers.put(KeywordFieldMapper.CONTENT_TYPE, KeywordFieldMapper.PARSER);
|
||||
mappers.put(ObjectMapper.CONTENT_TYPE, new ObjectMapper.TypeParser());
|
||||
mappers.put(ObjectMapper.NESTED_CONTENT_TYPE, new ObjectMapper.TypeParser());
|
||||
mappers.put(CompletionFieldMapper.CONTENT_TYPE, CompletionFieldMapper.PARSER);
|
||||
|
@ -115,7 +115,7 @@ public class ExternalFieldMapperTests extends ESSingleNodeTestCase {
|
||||
Map<String, Mapper.TypeParser> mapperParsers = new HashMap<>();
|
||||
mapperParsers.put(ExternalMapperPlugin.EXTERNAL, new ExternalMapper.TypeParser(ExternalMapperPlugin.EXTERNAL, "foo"));
|
||||
mapperParsers.put(TextFieldMapper.CONTENT_TYPE, new TextFieldMapper.TypeParser());
|
||||
mapperParsers.put(KeywordFieldMapper.CONTENT_TYPE, new KeywordFieldMapper.TypeParser());
|
||||
mapperParsers.put(KeywordFieldMapper.CONTENT_TYPE, KeywordFieldMapper.PARSER);
|
||||
MapperRegistry mapperRegistry = new MapperRegistry(mapperParsers, Collections.emptyMap(), MapperPlugin.NOOP_FIELD_FILTER);
|
||||
|
||||
Supplier<QueryShardContext> queryShardContext = () -> {
|
||||
|
@ -26,8 +26,6 @@ import org.apache.lucene.index.DocValuesType;
|
||||
import org.apache.lucene.index.IndexOptions;
|
||||
import org.apache.lucene.index.IndexableField;
|
||||
import org.apache.lucene.index.IndexableFieldType;
|
||||
import org.apache.lucene.search.similarities.BM25Similarity;
|
||||
import org.apache.lucene.search.similarities.BooleanSimilarity;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
||||
@ -41,12 +39,12 @@ import org.elasticsearch.index.IndexService;
|
||||
import org.elasticsearch.index.analysis.PreConfiguredTokenFilter;
|
||||
import org.elasticsearch.index.analysis.TokenizerFactory;
|
||||
import org.elasticsearch.index.mapper.MapperService.MergeReason;
|
||||
import org.elasticsearch.index.similarity.SimilarityProvider;
|
||||
import org.elasticsearch.index.termvectors.TermVectorsService;
|
||||
import org.elasticsearch.indices.analysis.AnalysisModule;
|
||||
import org.elasticsearch.plugins.AnalysisPlugin;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.search.lookup.SourceLookup;
|
||||
import org.elasticsearch.test.ESSingleNodeTestCase;
|
||||
import org.elasticsearch.test.InternalSettingsPlugin;
|
||||
import org.junit.Before;
|
||||
|
||||
@ -56,7 +54,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
@ -65,17 +62,7 @@ import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
public class KeywordFieldMapperTests extends FieldMapperTestCase<KeywordFieldMapper.Builder> {
|
||||
|
||||
@Override
|
||||
protected KeywordFieldMapper.Builder newBuilder() {
|
||||
return new KeywordFieldMapper.Builder("keyword");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> unsupportedProperties() {
|
||||
return org.elasticsearch.common.collect.Set.of("analyzer");
|
||||
}
|
||||
public class KeywordFieldMapperTests extends ESSingleNodeTestCase {
|
||||
|
||||
/**
|
||||
* Creates a copy of the lowercase token filter which we use for testing merge errors.
|
||||
@ -99,11 +86,6 @@ public class KeywordFieldMapperTests extends FieldMapperTestCase<KeywordFieldMap
|
||||
return pluginList(InternalSettingsPlugin.class, MockAnalysisPlugin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings getIndexMapperSettings() {
|
||||
return mapperSettings;
|
||||
}
|
||||
|
||||
private static final Settings mapperSettings = Settings.builder()
|
||||
.put("index.analysis.normalizer.my_lowercase.type", "custom")
|
||||
.putList("index.analysis.normalizer.my_lowercase.filter", "lowercase")
|
||||
@ -117,18 +99,6 @@ public class KeywordFieldMapperTests extends FieldMapperTestCase<KeywordFieldMap
|
||||
public void setup() {
|
||||
indexService = createIndex("test", mapperSettings);
|
||||
parser = indexService.mapperService().documentMapperParser();
|
||||
addModifier("normalizer", false, (a, b) -> {
|
||||
a.normalizer(indexService.getIndexAnalyzers(), "my_lowercase");
|
||||
});
|
||||
addBooleanModifier("split_queries_on_whitespace", true, KeywordFieldMapper.Builder::splitQueriesOnWhitespace);
|
||||
addModifier("index_options", false, (a, b) -> {
|
||||
a.indexOptions(IndexOptions.DOCS);
|
||||
b.indexOptions(IndexOptions.DOCS_AND_FREQS);
|
||||
});
|
||||
addModifier("similarity", false, (a, b) -> {
|
||||
a.similarity(new SimilarityProvider("BM25", new BM25Similarity()));
|
||||
b.similarity(new SimilarityProvider("boolean", new BooleanSimilarity()));
|
||||
});
|
||||
}
|
||||
|
||||
public void testDefaults() throws Exception {
|
||||
@ -339,16 +309,17 @@ public class KeywordFieldMapperTests extends FieldMapperTestCase<KeywordFieldMap
|
||||
.startObject("properties").startObject("field").field("type", "keyword")
|
||||
.field("index_options", indexOptions).endObject().endObject()
|
||||
.endObject().endObject());
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class,
|
||||
() -> parser.parse("type", new CompressedXContent(mapping2)));
|
||||
assertEquals("The [keyword] field does not support positions, got [index_options]=" + indexOptions, e.getMessage());
|
||||
assertEquals("Unknown value [" + indexOptions + "] for field [index_options] - accepted values are [docs, freqs]",
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testBoost() throws IOException {
|
||||
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startObject("properties").startObject("field").field("type", "keyword").field("boost", 2f).endObject().endObject()
|
||||
.endObject().endObject());
|
||||
.startObject("properties").startObject("field").field("type", "keyword").field("boost", 2f).endObject().endObject()
|
||||
.endObject().endObject());
|
||||
|
||||
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
|
||||
@ -524,8 +495,8 @@ public class KeywordFieldMapperTests extends FieldMapperTestCase<KeywordFieldMap
|
||||
() -> indexService.mapperService().merge("type",
|
||||
new CompressedXContent(mapping2), MergeReason.MAPPING_UPDATE));
|
||||
assertEquals(
|
||||
"Mapper for [field] conflicts with existing mapping:\n" +
|
||||
"[mapper [field] has different [analyzer], mapper [field] has different [normalizer]]",
|
||||
"Mapper for [field] conflicts with existing mapper:\n" +
|
||||
"\tCannot update parameter [normalizer] from [my_lowercase] to [my_other_lowercase]",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
@ -650,8 +621,8 @@ public class KeywordFieldMapperTests extends FieldMapperTestCase<KeywordFieldMap
|
||||
assertEquals("42", ignoreAboveMapper.parseSourceValue(42L, null));
|
||||
assertEquals("true", ignoreAboveMapper.parseSourceValue(true, null));
|
||||
|
||||
KeywordFieldMapper normalizerMapper = new KeywordFieldMapper.Builder("field")
|
||||
.normalizer(indexService.getIndexAnalyzers(), "lowercase")
|
||||
KeywordFieldMapper normalizerMapper = new KeywordFieldMapper.Builder("field", indexService.getIndexAnalyzers())
|
||||
.normalizer("lowercase")
|
||||
.build(context);
|
||||
assertEquals("value", normalizerMapper.parseSourceValue("VALUE", null));
|
||||
assertEquals("42", normalizerMapper.parseSourceValue(42L, null));
|
||||
|
@ -122,6 +122,8 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
|
||||
throw new IllegalArgumentException("field [required] must be specified");
|
||||
}
|
||||
});
|
||||
final Parameter<String> restricted
|
||||
= Parameter.restrictedStringParam("restricted", true, m -> toType(m).restricted, "foo", "bar");
|
||||
|
||||
protected Builder(String name) {
|
||||
super(name);
|
||||
@ -129,7 +131,7 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
|
||||
|
||||
@Override
|
||||
protected List<Parameter<?>> getParameters() {
|
||||
return Arrays.asList(fixed, fixed2, variable, index, wrapper, intValue, analyzer, searchAnalyzer, required);
|
||||
return Arrays.asList(fixed, fixed2, variable, index, wrapper, intValue, analyzer, searchAnalyzer, required, restricted);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -160,6 +162,7 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
|
||||
private final NamedAnalyzer searchAnalyzer;
|
||||
private final boolean index;
|
||||
private final String required;
|
||||
private final String restricted;
|
||||
|
||||
protected TestMapper(String simpleName, String fullName, MultiFields multiFields, CopyTo copyTo,
|
||||
ParametrizedMapperTests.Builder builder) {
|
||||
@ -173,6 +176,7 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
|
||||
this.searchAnalyzer = builder.searchAnalyzer.getValue();
|
||||
this.index = builder.index.getValue();
|
||||
this.required = builder.required.getValue();
|
||||
this.restricted = builder.restricted.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -207,7 +211,7 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
|
||||
when(mapperService.getIndexAnalyzers()).thenReturn(indexAnalyzers);
|
||||
Mapper.TypeParser.ParserContext pc = new Mapper.TypeParser.ParserContext(s -> null, mapperService, s -> {
|
||||
if (Objects.equals("keyword", s)) {
|
||||
return new KeywordFieldMapper.TypeParser();
|
||||
return KeywordFieldMapper.PARSER;
|
||||
}
|
||||
if (Objects.equals("binary", s)) {
|
||||
return BinaryFieldMapper.PARSER;
|
||||
@ -241,7 +245,7 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
|
||||
assertEquals("{\"field\":{\"type\":\"test_mapper\",\"fixed\":true," +
|
||||
"\"fixed2\":false,\"variable\":\"default\",\"index\":true," +
|
||||
"\"wrapper\":\"default\",\"int_value\":5,\"analyzer\":\"_keyword\"," +
|
||||
"\"search_analyzer\":\"_keyword\",\"required\":\"value\"}}",
|
||||
"\"search_analyzer\":\"_keyword\",\"required\":\"value\",\"restricted\":\"foo\"}}",
|
||||
Strings.toString(builder));
|
||||
}
|
||||
|
||||
@ -439,4 +443,22 @@ public class ParametrizedMapperTests extends ESSingleNodeTestCase {
|
||||
assertEquals("[required] on mapper [field] of type [test_mapper] must not have a [null] value", exc.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testRestrictedField() {
|
||||
{
|
||||
String mapping = "{\"type\":\"test_mapper\",\"required\":\"a\",\"restricted\":\"baz\"}";
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class, () -> fromMapping(mapping));
|
||||
assertEquals("Unknown value [baz] for field [restricted] - accepted values are [foo, bar]", e.getMessage());
|
||||
}
|
||||
{
|
||||
String mapping = "{\"type\":\"test_mapper\",\"required\":\"a\",\"restricted\":\"bar\"}";
|
||||
TestMapper mapper = fromMapping(mapping);
|
||||
assertEquals("bar", mapper.restricted);
|
||||
}
|
||||
{
|
||||
String mapping = "{\"type\":\"test_mapper\",\"required\":\"a\"}";
|
||||
TestMapper mapper = fromMapping(mapping);
|
||||
assertEquals("foo", mapper.restricted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +339,8 @@ public class RootObjectMapperTests extends ESSingleNodeTestCase {
|
||||
DocumentMapper mapper = mapperService.merge("type", new CompressedXContent(Strings.toString(mapping)), MergeReason.MAPPING_UPDATE);
|
||||
assertThat(mapper.mappingSource().toString(), containsString("\"foo\":\"bar\""));
|
||||
assertWarnings("dynamic template [my_template] has invalid content [{\"match_mapping_type\":\"string\",\"mapping\":{" +
|
||||
"\"foo\":\"bar\",\"type\":\"keyword\"}}], caused by [Unused mapping attributes [{foo=bar}]]");
|
||||
"\"foo\":\"bar\",\"type\":\"keyword\"}}], " +
|
||||
"caused by [unknown parameter [foo] on mapper [__dynamic__my_template] of type [keyword]]");
|
||||
}
|
||||
|
||||
public void testIllegalDynamicTemplateInvalidAttribute() throws Exception {
|
||||
@ -367,7 +368,7 @@ public class RootObjectMapperTests extends ESSingleNodeTestCase {
|
||||
DocumentMapper mapper = mapperService.merge("type", new CompressedXContent(Strings.toString(mapping)), MergeReason.MAPPING_UPDATE);
|
||||
assertThat(mapper.mappingSource().toString(), containsString("\"analyzer\":\"foobar\""));
|
||||
assertWarnings("dynamic template [my_template] has invalid content [{\"match_mapping_type\":\"string\",\"mapping\":{" +
|
||||
"\"analyzer\":\"foobar\",\"type\":\"text\"}}], caused by [analyzer [foobar] not found for field [__dummy__]]");
|
||||
"\"analyzer\":\"foobar\",\"type\":\"text\"}}], caused by [analyzer [foobar] not found for field [__dynamic__my_template]]");
|
||||
}
|
||||
|
||||
public void testIllegalDynamicTemplateNoMappingType() throws Exception {
|
||||
@ -436,11 +437,11 @@ public class RootObjectMapperTests extends ESSingleNodeTestCase {
|
||||
if (useMatchMappingType) {
|
||||
assertWarnings("dynamic template [my_template] has invalid content [{\"match_mapping_type\":\"*\",\"mapping\":{" +
|
||||
"\"foo\":\"bar\",\"type\":\"{dynamic_type}\"}}], " +
|
||||
"caused by [unknown parameter [foo] on mapper [__dummy__] of type [null]]");
|
||||
"caused by [unknown parameter [foo] on mapper [__dynamic__my_template] of type [binary]]");
|
||||
} else {
|
||||
assertWarnings("dynamic template [my_template] has invalid content [{\"match\":\"string_*\",\"mapping\":{" +
|
||||
"\"foo\":\"bar\",\"type\":\"{dynamic_type}\"}}], " +
|
||||
"caused by [unknown parameter [foo] on mapper [__dummy__] of type [null]]");
|
||||
"caused by [unknown parameter [foo] on mapper [__dynamic__my_template] of type [binary]]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,19 +182,23 @@ public class TypeParsersTests extends ESTestCase {
|
||||
.endObject()
|
||||
.endObject();
|
||||
|
||||
Mapper.TypeParser typeParser = KeywordFieldMapper.PARSER;
|
||||
|
||||
Map<String, Object> fieldNode = XContentHelper.convertToMap(
|
||||
BytesReference.bytes(mapping), true, mapping.contentType()).v2();
|
||||
|
||||
Mapper.TypeParser typeParser = new KeywordFieldMapper.TypeParser();
|
||||
Mapper.TypeParser.ParserContext parserContext = new Mapper.TypeParser.ParserContext(
|
||||
null, null, type -> typeParser, Version.CURRENT, null, null);
|
||||
IndexAnalyzers indexAnalyzers = new IndexAnalyzers(defaultAnalyzers(), Collections.emptyMap(), Collections.emptyMap());
|
||||
MapperService mapperService = mock(MapperService.class);
|
||||
when(mapperService.getIndexAnalyzers()).thenReturn(indexAnalyzers);
|
||||
Mapper.TypeParser.ParserContext olderContext = new Mapper.TypeParser.ParserContext(
|
||||
null, mapperService, type -> typeParser, Version.CURRENT, null, null);
|
||||
|
||||
TypeParsers.parseField(builder, "some-field", fieldNode, parserContext);
|
||||
assertWarnings("At least one multi-field, [sub-field], was " +
|
||||
"encountered that itself contains a multi-field. Defining multi-fields within a multi-field is deprecated and will " +
|
||||
"no longer be supported in 8.0. To resolve the issue, all instances of [fields] that occur within a [fields] block " +
|
||||
"should be removed from the mappings, either by flattening the chained [fields] blocks into a single level, or " +
|
||||
"switching to [copy_to] if appropriate.");
|
||||
TypeParsers.parseField(builder, "some-field", fieldNode, olderContext);
|
||||
assertWarnings("At least one multi-field, [sub-field], " +
|
||||
"was encountered that itself contains a multi-field. Defining multi-fields within a multi-field is deprecated " +
|
||||
"and will no longer be supported in 8.0. To resolve the issue, all instances of [fields] " +
|
||||
"that occur within a [fields] block should be removed from the mappings, either by flattening the chained " +
|
||||
"[fields] blocks into a single level, or switching to [copy_to] if appropriate.");
|
||||
}
|
||||
|
||||
private Analyzer createAnalyzerWithMode(String name, AnalysisMode mode) {
|
||||
@ -214,21 +218,15 @@ public class TypeParsersTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testParseMeta() {
|
||||
FieldMapper.Builder<?> builder = new KeywordFieldMapper.Builder("foo");
|
||||
Mapper.TypeParser.ParserContext parserContext = new Mapper.TypeParser.ParserContext(null, null, null, null, null, null);
|
||||
|
||||
{
|
||||
Map<String, Object> mapping = new HashMap<>(Collections.singletonMap("meta", 3));
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class,
|
||||
() -> TypeParsers.parseField(builder, builder.name, mapping, parserContext));
|
||||
() -> TypeParsers.parseMeta("foo", 3));
|
||||
assertEquals("[meta] must be an object, got Integer[3] for field [foo]", e.getMessage());
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> mapping = new HashMap<>(Collections.singletonMap("meta",
|
||||
Collections.singletonMap("veryloooooooooooongkey", 3L)));
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class,
|
||||
() -> TypeParsers.parseField(builder, builder.name, mapping, parserContext));
|
||||
() -> TypeParsers.parseMeta("foo", Collections.singletonMap("veryloooooooooooongkey", 3L)));
|
||||
assertEquals("[meta] keys can't be longer than 20 chars, but got [veryloooooooooooongkey] for field [foo]",
|
||||
e.getMessage());
|
||||
}
|
||||
@ -241,18 +239,16 @@ public class TypeParsersTests extends ESTestCase {
|
||||
meta.put("foo4", "3");
|
||||
meta.put("foo5", "3");
|
||||
meta.put("foo6", "3");
|
||||
Map<String, Object> mapping = new HashMap<>(Collections.singletonMap("meta", meta));
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class,
|
||||
() -> TypeParsers.parseField(builder, builder.name, mapping, parserContext));
|
||||
() -> TypeParsers.parseMeta("foo", meta));
|
||||
assertEquals("[meta] can't have more than 5 entries, but got 6 on field [foo]",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> mapping = new HashMap<>(Collections.singletonMap("meta",
|
||||
Collections.singletonMap("foo", Collections.singletonMap("bar", "baz"))));
|
||||
Map<String, Object> mapping = Collections.singletonMap("foo", Collections.singletonMap("bar", "baz"));
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class,
|
||||
() -> TypeParsers.parseField(builder, builder.name, mapping, parserContext));
|
||||
() -> TypeParsers.parseMeta("foo", mapping));
|
||||
assertEquals("[meta] values can only be strings, but got SingletonMap[{bar=baz}] for field [foo]",
|
||||
e.getMessage());
|
||||
}
|
||||
@ -261,9 +257,8 @@ public class TypeParsersTests extends ESTestCase {
|
||||
Map<String, Object> inner = new HashMap<>();
|
||||
inner.put("bar", "baz");
|
||||
inner.put("foo", 3);
|
||||
Map<String, Object> mapping = new HashMap<>(Collections.singletonMap("meta", inner));
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class,
|
||||
() -> TypeParsers.parseField(builder, builder.name, mapping, parserContext));
|
||||
() -> TypeParsers.parseMeta("foo", inner));
|
||||
assertEquals("[meta] values can only be strings, but got Integer[3] for field [foo]",
|
||||
e.getMessage());
|
||||
}
|
||||
@ -271,9 +266,8 @@ public class TypeParsersTests extends ESTestCase {
|
||||
{
|
||||
Map<String, String> meta = new HashMap<>();
|
||||
meta.put("foo", null);
|
||||
Map<String, Object> mapping = new HashMap<>(Collections.singletonMap("meta", meta));
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class,
|
||||
() -> TypeParsers.parseField(builder, builder.name, mapping, parserContext));
|
||||
() -> TypeParsers.parseMeta("foo", meta));
|
||||
assertEquals("[meta] values can't be null (field [foo])",
|
||||
e.getMessage());
|
||||
}
|
||||
@ -282,9 +276,8 @@ public class TypeParsersTests extends ESTestCase {
|
||||
String longString = IntStream.range(0, 51)
|
||||
.mapToObj(Integer::toString)
|
||||
.collect(Collectors.joining());
|
||||
Map<String, Object> mapping = new HashMap<>(Collections.singletonMap("meta", Collections.singletonMap("foo", longString)));
|
||||
MapperParsingException e = expectThrows(MapperParsingException.class,
|
||||
() -> TypeParsers.parseField(builder, builder.name, mapping, parserContext));
|
||||
() -> TypeParsers.parseMeta("foo", Collections.singletonMap("foo", longString)));
|
||||
assertThat(e.getMessage(), Matchers.startsWith("[meta] values can't be longer than 50 chars"));
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ public class IndicesServiceTests extends ESSingleNodeTestCase {
|
||||
|
||||
@Override
|
||||
public Map<String, Mapper.TypeParser> getMappers() {
|
||||
return Collections.singletonMap("fake-mapper", new KeywordFieldMapper.TypeParser());
|
||||
return Collections.singletonMap("fake-mapper", KeywordFieldMapper.PARSER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user