Convert NumberFieldMapper to parametrized form (#61092) (#61376)

In addition, this commit converts ScaledFloatFieldMapper as it was relying
on a number of static values taken from NumberFieldMapper that had changed
or been removed.
This commit is contained in:
Alan Woodward 2020-08-20 16:43:26 +01:00 committed by GitHub
parent 039b306e7d
commit a3a0c63ccf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 251 additions and 462 deletions

View File

@ -35,7 +35,7 @@ public class MapperExtrasPlugin extends Plugin implements MapperPlugin, SearchPl
@Override
public Map<String, Mapper.TypeParser> getMappers() {
Map<String, Mapper.TypeParser> mappers = new LinkedHashMap<>();
mappers.put(ScaledFloatFieldMapper.CONTENT_TYPE, new ScaledFloatFieldMapper.TypeParser());
mappers.put(ScaledFloatFieldMapper.CONTENT_TYPE, ScaledFloatFieldMapper.PARSER);
mappers.put(TokenCountFieldMapper.CONTENT_TYPE, new TokenCountFieldMapper.TypeParser());
mappers.put(RankFeatureFieldMapper.CONTENT_TYPE, new RankFeatureFieldMapper.TypeParser());
mappers.put(RankFeaturesFieldMapper.CONTENT_TYPE, new RankFeaturesFieldMapper.TypeParser());

View File

@ -20,9 +20,7 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.SortedNumericDocValues;
@ -34,13 +32,12 @@ import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParser.Token;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.fielddata.FieldData;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
import org.elasticsearch.index.fielddata.NumericDoubleValues;
@ -48,9 +45,7 @@ import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
import org.elasticsearch.index.mapper.NumberFieldMapper.Defaults;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
@ -58,125 +53,84 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/** A {@link FieldMapper} for scaled floats. Values are internally multiplied
* by a scaling factor and rounded to the closest long. */
public class ScaledFloatFieldMapper extends FieldMapper {
public class ScaledFloatFieldMapper extends ParametrizedFieldMapper {
public static final String CONTENT_TYPE = "scaled_float";
// use the same default as numbers
private static final Setting<Boolean> COERCE_SETTING = NumberFieldMapper.COERCE_SETTING;
private static final FieldType FIELD_TYPE = new FieldType();
static {
FIELD_TYPE.setIndexOptions(IndexOptions.DOCS);
private static ScaledFloatFieldMapper toType(FieldMapper in) {
return (ScaledFloatFieldMapper) in;
}
public static class Builder extends FieldMapper.Builder<Builder> {
public static class Builder extends ParametrizedFieldMapper.Builder {
private boolean scalingFactorSet = false;
private double scalingFactor;
private Boolean ignoreMalformed;
private Boolean coerce;
private Double nullValue;
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).stored, false);
public Builder(String name) {
super(name, FIELD_TYPE);
builder = this;
private final Parameter<Explicit<Boolean>> ignoreMalformed;
private final Parameter<Explicit<Boolean>> coerce;
private final Parameter<Double> scalingFactor = new Parameter<>("scaling_factor", false, () -> null,
(n, c, o) -> XContentMapValues.nodeDoubleValue(o), m -> toType(m).scalingFactor)
.setValidator(v -> {
if (v == null) {
throw new IllegalArgumentException("Field [scaling_factor] is required");
}
if (Double.isFinite(v) == false || v <= 0) {
throw new IllegalArgumentException("[scaling_factor] must be a positive number, got [" + v + "]");
}
});
private final Parameter<Double> nullValue = new Parameter<>("null_value", false, () -> null,
(n, c, o) -> XContentMapValues.nodeDoubleValue(o), m -> toType(m).nullValue);
private final Parameter<Map<String, String>> meta = Parameter.metaParam();
public Builder(String name, Settings settings) {
this(name, IGNORE_MALFORMED_SETTING.get(settings), COERCE_SETTING.get(settings));
}
public Builder ignoreMalformed(boolean ignoreMalformed) {
this.ignoreMalformed = ignoreMalformed;
return builder;
public Builder(String name, boolean ignoreMalformedByDefault, boolean coerceByDefault) {
super(name);
this.ignoreMalformed
= Parameter.explicitBoolParam("ignore_malformed", true, m -> toType(m).ignoreMalformed, ignoreMalformedByDefault);
this.coerce
= Parameter.explicitBoolParam("coerce", true, m -> toType(m).coerce, coerceByDefault);
}
Builder scalingFactor(double scalingFactor) {
this.scalingFactor.setValue(scalingFactor);
return this;
}
Builder nullValue(double nullValue) {
this.nullValue.setValue(nullValue);
return this;
}
@Override
public Builder indexOptions(IndexOptions indexOptions) {
throw new MapperParsingException(
"index_options not allowed in field [" + name + "] of type [" + CONTENT_TYPE + "]");
}
protected Explicit<Boolean> ignoreMalformed(BuilderContext context) {
if (ignoreMalformed != null) {
return new Explicit<>(ignoreMalformed, true);
}
if (context.indexSettings() != null) {
return new Explicit<>(IGNORE_MALFORMED_SETTING.get(context.indexSettings()), false);
}
return Defaults.IGNORE_MALFORMED;
}
public Builder coerce(boolean coerce) {
this.coerce = coerce;
return builder;
}
public Builder scalingFactor(double scalingFactor) {
this.scalingFactor = scalingFactor;
scalingFactorSet = true;
return this;
}
public Builder nullValue(Double nullValue) {
this.nullValue = nullValue;
return this;
}
protected Explicit<Boolean> coerce(BuilderContext context) {
if (coerce != null) {
return new Explicit<>(coerce, true);
}
if (context.indexSettings() != null) {
return new Explicit<>(COERCE_SETTING.get(context.indexSettings()), false);
}
return Defaults.COERCE;
protected List<Parameter<?>> getParameters() {
return Arrays.asList(indexed, hasDocValues, stored, ignoreMalformed, meta, scalingFactor, coerce, nullValue);
}
@Override
public ScaledFloatFieldMapper build(BuilderContext context) {
if (scalingFactorSet == false) {
throw new IllegalArgumentException("Field [" + name + "] misses required parameter [scaling_factor]");
}
ScaledFloatFieldType type = new ScaledFloatFieldType(buildFullName(context), indexed, hasDocValues, meta, scalingFactor);
return new ScaledFloatFieldMapper(name, fieldType, type, ignoreMalformed(context),
coerce(context), multiFieldsBuilder.build(this, context), copyTo, nullValue);
ScaledFloatFieldType type = new ScaledFloatFieldType(buildFullName(context), indexed.getValue(), hasDocValues.getValue(),
meta.getValue(), scalingFactor.getValue());
return new ScaledFloatFieldMapper(name, type, 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 {
Builder builder = new Builder(name);
TypeParsers.parseField(builder, name, node, parserContext);
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();
if (propName.equals("null_value")) {
if (propNode == null) {
throw new MapperParsingException("Property [null_value] cannot be null.");
}
builder.nullValue(ScaledFloatFieldMapper.parse(propNode));
iterator.remove();
} else if (propName.equals("ignore_malformed")) {
builder.ignoreMalformed(XContentMapValues.nodeBooleanValue(propNode, name + ".ignore_malformed"));
iterator.remove();
} else if (propName.equals("coerce")) {
builder.coerce(XContentMapValues.nodeBooleanValue(propNode, name + ".coerce"));
iterator.remove();
} else if (propName.equals("scaling_factor")) {
builder.scalingFactor(ScaledFloatFieldMapper.parse(propNode));
iterator.remove();
}
}
return builder;
}
}
public static final TypeParser PARSER = new TypeParser((n, c) -> new Builder(n, c.getSettings()));
public static final class ScaledFloatFieldType extends SimpleMappedFieldType {
@ -264,19 +218,12 @@ public class ScaledFloatFieldMapper extends FieldMapper {
@Override
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName) {
failIfNoDocValues();
return new IndexFieldData.Builder() {
@Override
public IndexFieldData<?> build(
IndexFieldDataCache cache,
CircuitBreakerService breakerService,
MapperService mapperService
) {
final IndexNumericFieldData scaledValues = new SortedNumericIndexFieldData.Builder(
name(),
IndexNumericFieldData.NumericType.LONG
).build(cache, breakerService, mapperService);
return new ScaledFloatIndexFieldData(scaledValues, scalingFactor);
}
return (cache, breakerService, mapperService) -> {
final IndexNumericFieldData scaledValues = new SortedNumericIndexFieldData.Builder(
name(),
IndexNumericFieldData.NumericType.LONG
).build(cache, breakerService, mapperService);
return new ScaledFloatIndexFieldData(scaledValues, scalingFactor);
};
}
@ -315,30 +262,33 @@ public class ScaledFloatFieldMapper extends FieldMapper {
}
}
private Explicit<Boolean> ignoreMalformed;
private Explicit<Boolean> coerce;
private final Explicit<Boolean> ignoreMalformed;
private final Explicit<Boolean> coerce;
private final boolean indexed;
private final boolean hasDocValues;
private final boolean stored;
private final Double nullValue;
private final double scalingFactor;
private final boolean ignoreMalformedByDefault;
private final boolean coerceByDefault;
private ScaledFloatFieldMapper(
String simpleName,
FieldType fieldType,
ScaledFloatFieldType mappedFieldType,
Explicit<Boolean> ignoreMalformed,
Explicit<Boolean> coerce,
MultiFields multiFields,
CopyTo copyTo,
Double nullValue) {
super(simpleName, fieldType, mappedFieldType, multiFields, copyTo);
this.scalingFactor = mappedFieldType.scalingFactor;
this.nullValue = nullValue;
if (Double.isFinite(scalingFactor) == false || scalingFactor <= 0) {
throw new IllegalArgumentException("[scaling_factor] must be a positive number, got [" + scalingFactor + "]");
}
this.ignoreMalformed = ignoreMalformed;
this.coerce = coerce;
Builder builder) {
super(simpleName, mappedFieldType, multiFields, copyTo);
this.indexed = builder.indexed.getValue();
this.hasDocValues = builder.hasDocValues.getValue();
this.stored = builder.stored.getValue();
this.scalingFactor = builder.scalingFactor.getValue();
this.nullValue = builder.nullValue.getValue();
this.ignoreMalformed = builder.ignoreMalformed.getValue();
this.coerce = builder.coerce.getValue();
this.ignoreMalformedByDefault = builder.ignoreMalformed.getDefaultValue().value();
this.coerceByDefault = builder.coerce.getDefaultValue().value();
}
@Override
@ -351,6 +301,11 @@ public class ScaledFloatFieldMapper extends FieldMapper {
return CONTENT_TYPE;
}
@Override
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder(simpleName(), ignoreMalformedByDefault, coerceByDefault).init(this);
}
@Override
protected ScaledFloatFieldMapper clone() {
return (ScaledFloatFieldMapper) super.clone();
@ -411,49 +366,15 @@ public class ScaledFloatFieldMapper extends FieldMapper {
}
long scaledValue = Math.round(doubleValue * scalingFactor);
boolean indexed = fieldType().isSearchable();
boolean docValued = fieldType().hasDocValues();
boolean stored = fieldType.stored();
List<Field> fields = NumberFieldMapper.NumberType.LONG.createFields(fieldType().name(), scaledValue, indexed, docValued, stored);
List<Field> fields
= NumberFieldMapper.NumberType.LONG.createFields(fieldType().name(), scaledValue, indexed, hasDocValues, stored);
context.doc().addAll(fields);
if (docValued == false && (indexed || stored)) {
if (hasDocValues == false && (indexed || stored)) {
createFieldNamesField(context);
}
}
@Override
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
ScaledFloatFieldMapper mergeWith = (ScaledFloatFieldMapper) other;
ScaledFloatFieldType ft = (ScaledFloatFieldType) other.fieldType();
if (fieldType().scalingFactor != ft.scalingFactor) {
conflicts.add("mapper [" + name() + "] has different [scaling_factor] values");
}
if (mergeWith.ignoreMalformed.explicit()) {
this.ignoreMalformed = mergeWith.ignoreMalformed;
}
if (mergeWith.coerce.explicit()) {
this.coerce = mergeWith.coerce;
}
}
@Override
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
builder.field("scaling_factor", scalingFactor);
if (includeDefaults || ignoreMalformed.explicit()) {
builder.field("ignore_malformed", ignoreMalformed.value());
}
if (includeDefaults || coerce.explicit()) {
builder.field("coerce", coerce.value());
}
if (nullValue != null) {
builder.field("null_value", nullValue);
}
}
static Double parse(Object value) {
return objectToDouble(value);
}

View File

@ -31,45 +31,26 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.search.lookup.SourceLookup;
import org.junit.Before;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static java.util.Collections.singletonList;
import static org.hamcrest.Matchers.containsString;
public class ScaledFloatFieldMapperTests extends FieldMapperTestCase2<ScaledFloatFieldMapper.Builder> {
@Before
public void setup() {
addModifier("scaling_factor", false, (a, b) -> {
a.scalingFactor(10);
b.scalingFactor(100);
});
}
@Override
protected Set<String> unsupportedProperties() {
return org.elasticsearch.common.collect.Set.of("analyzer", "similarity");
}
public class ScaledFloatFieldMapperTests extends MapperTestCase {
@Override
protected Collection<? extends Plugin> getPlugins() {
return singletonList(new MapperExtrasPlugin());
}
@Override
protected ScaledFloatFieldMapper.Builder newBuilder() {
return new ScaledFloatFieldMapper.Builder("scaled-float").scalingFactor(1);
}
@Override
protected void minimalMapping(XContentBuilder b) throws IOException {
b.field("type", "scaled_float").field("scaling_factor", 10.0);
b.field("type", "scaled_float").field("scaling_factor", 10.0);
}
public void testDefaults() throws Exception {
@ -96,15 +77,15 @@ public class ScaledFloatFieldMapperTests extends FieldMapperTestCase2<ScaledFloa
assertFalse(dvField.fieldType().stored());
}
public void testMissingScalingFactor() throws IOException {
public void testMissingScalingFactor() {
Exception e = expectThrows(
MapperParsingException.class,
() -> createMapperService(fieldMapping(b -> b.field("type", "scaled_float")))
);
assertThat(e.getMessage(), containsString("Field [field] misses required parameter [scaling_factor]"));
assertThat(e.getMessage(), containsString("Failed to parse mapping [_doc]: Field [scaling_factor] is required"));
}
public void testIllegalScalingFactor() throws IOException {
public void testIllegalScalingFactor() {
Exception e = expectThrows(
MapperParsingException.class,
() -> createMapperService(fieldMapping(b -> b.field("type", "scaled_float").field("scaling_factor", -1)))
@ -270,26 +251,28 @@ public class ScaledFloatFieldMapperTests extends FieldMapperTestCase2<ScaledFloa
/**
* `index_options` was deprecated and is rejected as of 7.0
*/
public void testRejectIndexOptions() throws IOException {
public void testRejectIndexOptions() {
MapperParsingException e = expectThrows(
MapperParsingException.class,
() -> createMapperService(fieldMapping(b -> b.field("type", "scaled_float").field("index_options", randomIndexOptions())))
);
assertThat(e.getMessage(), containsString("index_options not allowed in field [field] of type [scaled_float]"));
assertThat(e.getMessage(),
containsString("Failed to parse mapping [_doc]: Field [scaling_factor] is required"));
assertWarnings("Parameter [index_options] has no effect on type [scaled_float] and will be removed in future");
}
public void testParseSourceValue() {
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT.id).build();
Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath());
ScaledFloatFieldMapper mapper = new ScaledFloatFieldMapper.Builder("field")
ScaledFloatFieldMapper mapper = new ScaledFloatFieldMapper.Builder("field", false, false)
.scalingFactor(100)
.build(context);
assertEquals(3.14, mapper.parseSourceValue(3.1415926, null), 0.00001);
assertEquals(3.14, mapper.parseSourceValue("3.1415", null), 0.00001);
assertNull(mapper.parseSourceValue("", null));
ScaledFloatFieldMapper nullValueMapper = new ScaledFloatFieldMapper.Builder("field")
ScaledFloatFieldMapper nullValueMapper = new ScaledFloatFieldMapper.Builder("field", false, false)
.scalingFactor(100)
.nullValue(2.71)
.build(context);

View File

@ -170,10 +170,7 @@ public class PercolatorFieldMapper extends FieldMapper {
static NumberFieldMapper createMinimumShouldMatchField(BuilderContext context) {
NumberFieldMapper.Builder builder =
new NumberFieldMapper.Builder(MINIMUM_SHOULD_MATCH_FIELD_NAME, NumberFieldMapper.NumberType.INTEGER);
builder.index(false);
builder.store(false);
builder.docValues(true);
NumberFieldMapper.Builder.docValuesOnly(MINIMUM_SHOULD_MATCH_FIELD_NAME, NumberFieldMapper.NumberType.INTEGER);
return builder.build(context);
}

View File

@ -25,6 +25,7 @@ import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateFormatter;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.XContentHelper;
@ -638,12 +639,12 @@ final class DocumentParser {
}
}
private static Mapper.Builder<?> newLongBuilder(String name, Version indexCreated) {
return new NumberFieldMapper.Builder(name, NumberFieldMapper.NumberType.LONG);
private static Mapper.Builder<?> newLongBuilder(String name, Settings settings) {
return new NumberFieldMapper.Builder(name, NumberFieldMapper.NumberType.LONG, settings);
}
private static Mapper.Builder<?> newFloatBuilder(String name, Version indexCreated) {
return new NumberFieldMapper.Builder(name, NumberFieldMapper.NumberType.FLOAT);
private static Mapper.Builder<?> newFloatBuilder(String name, Settings settings) {
return new NumberFieldMapper.Builder(name, NumberFieldMapper.NumberType.FLOAT, settings);
}
private static Mapper.Builder<?> createBuilderFromDynamicValue(final ParseContext context,
@ -671,13 +672,13 @@ final class DocumentParser {
if (parseableAsLong && context.root().numericDetection()) {
Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, XContentFieldType.LONG);
if (builder == null) {
builder = newLongBuilder(currentFieldName, context.indexSettings().getIndexVersionCreated());
builder = newLongBuilder(currentFieldName, context.indexSettings().getSettings());
}
return builder;
} else if (parseableAsDouble && context.root().numericDetection()) {
Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, XContentFieldType.DOUBLE);
if (builder == null) {
builder = newFloatBuilder(currentFieldName, context.indexSettings().getIndexVersionCreated());
builder = newFloatBuilder(currentFieldName, context.indexSettings().getSettings());
}
return builder;
} else if (parseableAsLong == false && parseableAsDouble == false && context.root().dateDetection()) {
@ -717,7 +718,7 @@ final class DocumentParser {
|| numberType == XContentParser.NumberType.BIG_INTEGER) {
Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, XContentFieldType.LONG);
if (builder == null) {
builder = newLongBuilder(currentFieldName, context.indexSettings().getIndexVersionCreated());
builder = newLongBuilder(currentFieldName, context.indexSettings().getSettings());
}
return builder;
} else if (numberType == XContentParser.NumberType.FLOAT
@ -728,7 +729,7 @@ final class DocumentParser {
// no templates are defined, we use float by default instead of double
// since this is much more space-efficient and should be enough most of
// the time
builder = newFloatBuilder(currentFieldName, context.indexSettings().getIndexVersionCreated());
builder = newFloatBuilder(currentFieldName, context.indexSettings().getSettings());
}
return builder;
}

View File

@ -23,14 +23,12 @@ import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.exc.InputCoercionException;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.HalfFloatPoint;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.SortedNumericDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.DocValuesFieldExistsQuery;
@ -47,10 +45,9 @@ import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParser.Token;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData.NumericType;
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
@ -62,123 +59,77 @@ import java.time.ZoneId;
import java.util.ArrayList;
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 java.util.function.Function;
/** A {@link FieldMapper} for numeric types: byte, short, int, long, float and double. */
public class NumberFieldMapper extends FieldMapper {
public class NumberFieldMapper extends ParametrizedFieldMapper {
public static final Setting<Boolean> COERCE_SETTING =
Setting.boolSetting("index.mapping.coerce", true, Property.IndexScope);
public static class Defaults {
public static final Explicit<Boolean> IGNORE_MALFORMED = new Explicit<>(false, false);
public static final Explicit<Boolean> COERCE = new Explicit<>(true, false);
public static final FieldType FIELD_TYPE = new FieldType();
static {
FIELD_TYPE.setStored(false);
FIELD_TYPE.setIndexOptions(IndexOptions.DOCS);
FIELD_TYPE.freeze();
}
private static NumberFieldMapper toType(FieldMapper in) {
return (NumberFieldMapper) in;
}
public static class Builder extends FieldMapper.Builder<Builder> {
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).stored, false);
private final Parameter<Explicit<Boolean>> ignoreMalformed;
private final Parameter<Explicit<Boolean>> coerce;
private final Parameter<Number> nullValue;
private final Parameter<Map<String, String>> meta = Parameter.metaParam();
private Boolean ignoreMalformed;
private Boolean coerce;
private Number nullValue;
private final NumberType type;
public Builder(String name, NumberType type) {
super(name, Defaults.FIELD_TYPE);
public Builder(String name, NumberType type, Settings settings) {
this(name, type, IGNORE_MALFORMED_SETTING.get(settings), COERCE_SETTING.get(settings));
}
public static Builder docValuesOnly(String name, NumberType type) {
Builder builder = new Builder(name, type, false, false);
builder.indexed.setValue(false);
return builder;
}
public Builder(String name, NumberType type, boolean ignoreMalformedByDefault, boolean coerceByDefault) {
super(name);
this.type = type;
builder = this;
this.ignoreMalformed
= Parameter.explicitBoolParam("ignore_malformed", true, m -> toType(m).ignoreMalformed, ignoreMalformedByDefault);
this.coerce
= Parameter.explicitBoolParam("coerce", true, m -> toType(m).coerce, coerceByDefault);
this.nullValue = new Parameter<>("null_value", false, () -> null,
(n, c, o) -> type.parse(o, false), m -> toType(m).nullValue);
}
public Builder ignoreMalformed(boolean ignoreMalformed) {
this.ignoreMalformed = ignoreMalformed;
return builder;
Builder nullValue(Number number) {
this.nullValue.setValue(number);
return this;
}
public Builder nullValue(Number nullValue) {
this.nullValue = nullValue;
return builder;
public Builder docValues(boolean hasDocValues) {
this.hasDocValues.setValue(hasDocValues);
return this;
}
@Override
public Builder indexOptions(IndexOptions indexOptions) {
throw new MapperParsingException(
"index_options not allowed in field [" + name + "] of type [" + type.typeName() + "]");
}
protected Explicit<Boolean> ignoreMalformed(BuilderContext context) {
if (ignoreMalformed != null) {
return new Explicit<>(ignoreMalformed, true);
}
if (context.indexSettings() != null) {
return new Explicit<>(IGNORE_MALFORMED_SETTING.get(context.indexSettings()), false);
}
return Defaults.IGNORE_MALFORMED;
}
public Builder coerce(boolean coerce) {
this.coerce = coerce;
return builder;
}
protected Explicit<Boolean> coerce(BuilderContext context) {
if (coerce != null) {
return new Explicit<>(coerce, true);
}
if (context.indexSettings() != null) {
return new Explicit<>(COERCE_SETTING.get(context.indexSettings()), false);
}
return Defaults.COERCE;
protected List<Parameter<?>> getParameters() {
return Arrays.asList(indexed, hasDocValues, stored, ignoreMalformed, coerce, nullValue, meta);
}
@Override
public NumberFieldMapper build(BuilderContext context) {
return new NumberFieldMapper(name, fieldType, new NumberFieldType(buildFullName(context), type, indexed, hasDocValues, meta),
ignoreMalformed(context), coerce(context), nullValue,
multiFieldsBuilder.build(this, context), copyTo);
}
}
public static class TypeParser implements Mapper.TypeParser {
final NumberType type;
public TypeParser(NumberType type) {
this.type = type;
}
@Override
public Mapper.Builder<?> parse(String name, Map<String, Object> node,
ParserContext parserContext) throws MapperParsingException {
Builder builder = new Builder(name, type);
TypeParsers.parseField(builder, name, node, parserContext);
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();
if (propName.equals("null_value")) {
if (propNode == null) {
throw new MapperParsingException("Property [null_value] cannot be null.");
}
builder.nullValue(type.parse(propNode, false));
iterator.remove();
} else if (propName.equals("ignore_malformed")) {
builder.ignoreMalformed(XContentMapValues.nodeBooleanValue(propNode, name + ".ignore_malformed"));
iterator.remove();
} else if (propName.equals("coerce")) {
builder.coerce(XContentMapValues.nodeBooleanValue(propNode, name + ".coerce"));
iterator.remove();
}
}
return builder;
return new NumberFieldMapper(name,
new NumberFieldType(buildFullName(context), type, indexed.getValue(), hasDocValues.getValue(), meta.getValue()),
multiFieldsBuilder.build(this, context), copyTo.build(), this);
}
}
@ -823,10 +774,12 @@ public class NumberFieldMapper extends FieldMapper {
private final String name;
private final NumericType numericType;
private final TypeParser parser;
NumberType(String name, NumericType numericType) {
this.name = name;
this.numericType = numericType;
this.parser = new TypeParser((n, c) -> new Builder(n, this, c.getSettings()));
}
/** Get the associated type name. */
@ -837,6 +790,9 @@ public class NumberFieldMapper extends FieldMapper {
public final NumericType numericType() {
return numericType;
}
public final TypeParser parser() {
return parser;
}
public abstract Query termQuery(String field, Object value);
public abstract Query termsQuery(String field, List<Object> values);
public abstract Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
@ -1002,23 +958,34 @@ public class NumberFieldMapper extends FieldMapper {
}
}
private Explicit<Boolean> ignoreMalformed;
private Explicit<Boolean> coerce;
private final NumberType type;
private final boolean indexed;
private final boolean hasDocValues;
private final boolean stored;
private final Explicit<Boolean> ignoreMalformed;
private final Explicit<Boolean> coerce;
private final Number nullValue;
private final boolean ignoreMalformedByDefault;
private final boolean coerceByDefault;
private NumberFieldMapper(
String simpleName,
FieldType fieldType,
MappedFieldType mappedFieldType,
Explicit<Boolean> ignoreMalformed,
Explicit<Boolean> coerce,
Number nullValue,
MultiFields multiFields,
CopyTo copyTo) {
super(simpleName, fieldType, mappedFieldType, multiFields, copyTo);
this.ignoreMalformed = ignoreMalformed;
this.coerce = coerce;
this.nullValue = nullValue;
CopyTo copyTo,
Builder builder) {
super(simpleName, mappedFieldType, multiFields, copyTo);
this.type = builder.type;
this.indexed = builder.indexed.getValue();
this.hasDocValues = builder.hasDocValues.getValue();
this.stored = builder.stored.getValue();
this.ignoreMalformed = builder.ignoreMalformed.getValue();
this.coerce = builder.coerce.getValue();
this.nullValue = builder.nullValue.getValue();
this.ignoreMalformedByDefault = builder.ignoreMalformed.getDefaultValue().value();
this.coerceByDefault = builder.coerce.getDefaultValue().value();
}
@Override
@ -1080,12 +1047,10 @@ public class NumberFieldMapper extends FieldMapper {
numericValue = fieldType().type.parse(value, coerce.value());
}
boolean docValued = fieldType().hasDocValues();
boolean stored = fieldType.stored();
context.doc().addAll(fieldType().type.createFields(fieldType().name(), numericValue,
fieldType().isSearchable(), docValued, stored));
indexed, hasDocValues, stored));
if (docValued == false && (stored || fieldType().isSearchable())) {
if (hasDocValues == false && (stored || indexed)) {
createFieldNamesField(context);
}
}
@ -1104,34 +1069,7 @@ public class NumberFieldMapper extends FieldMapper {
}
@Override
protected void mergeOptions(FieldMapper other, List<String> conflicts) {
NumberFieldMapper m = (NumberFieldMapper) other;
if (fieldType().type != m.fieldType().type) {
conflicts.add("mapper [" + name() + "] cannot be changed from type [" + fieldType().type.name +
"] to [" + m.fieldType().type.name + "]");
} else {
if (m.ignoreMalformed.explicit()) {
this.ignoreMalformed = m.ignoreMalformed;
}
if (m.coerce.explicit()) {
this.coerce = m.coerce;
}
}
}
@Override
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || ignoreMalformed.explicit()) {
builder.field("ignore_malformed", ignoreMalformed.value());
}
if (includeDefaults || coerce.explicit()) {
builder.field("coerce", coerce.value());
}
if (nullValue != null) {
builder.field("null_value", nullValue);
}
public ParametrizedFieldMapper.Builder getMergeBuilder() {
return new Builder(simpleName(), type, ignoreMalformedByDefault, coerceByDefault).init(this);
}
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.index.mapper;
import org.apache.logging.log4j.LogManager;
import org.apache.lucene.document.FieldType;
import org.elasticsearch.Version;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.TriFunction;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Settings;
@ -84,9 +85,14 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
throw new IllegalArgumentException("mapper [" + name() + "] cannot be changed from type ["
+ contentType() + "] to [" + mergeWith.getClass().getSimpleName() + "]");
}
String mergeWithContentType = ((FieldMapper)mergeWith).contentType();
if (Objects.equals(this.getClass(), mergeWith.getClass()) == false) {
throw new IllegalArgumentException("mapper [" + name() + "] cannot be changed from type ["
+ contentType() + "] to [" + ((FieldMapper) mergeWith).contentType() + "]");
+ contentType() + "] to [" + mergeWithContentType + "]");
}
if (Objects.equals(contentType(), mergeWithContentType) == false) {
throw new IllegalArgumentException("mapper [" + name() + "] cannot be changed from type ["
+ contentType() + "] to [" + mergeWithContentType + "]");
}
ParametrizedFieldMapper.Builder builder = getMergeBuilder();
@ -268,6 +274,35 @@ public abstract class ParametrizedFieldMapper extends FieldMapper {
return new Parameter<>(name, updateable, () -> defaultValue, (n, c, o) -> XContentMapValues.nodeBooleanValue(o), initializer);
}
/**
* Defines a parameter that takes the values {@code true} or {@code false}, and will always serialize
* its value if configured.
* @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 defaultValue the default value, to be used if the parameter is undefined in a mapping
*/
public static Parameter<Explicit<Boolean>> explicitBoolParam(String name, boolean updateable,
Function<FieldMapper, Explicit<Boolean>> initializer,
boolean defaultValue) {
Explicit<Boolean> defaultExplicit = new Explicit<>(defaultValue, false);
return new Parameter<>(name, updateable, () -> 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()));
}
/**
* Defines a parameter that takes a double value
* @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 defaultValue the default value, to be used if the parameter is undefined in a mapping
*/
public static Parameter<Double> doubleParam(String name, boolean updateable,
Function<FieldMapper, Double> initializer, double defaultValue) {
return new Parameter<>(name, updateable, () -> defaultValue, (n, c, o) -> XContentMapValues.nodeDoubleValue(o), initializer);
}
/**
* Defines a parameter that takes a float value
* @param name the parameter name

View File

@ -34,9 +34,8 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.elasticsearch.common.xcontent.support.XContentMapValues.isArray;
import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeFloatValue;
@ -214,10 +213,11 @@ public class TypeParsers {
value.getClass().getSimpleName() + "[" + value + "] for field [" + name + "]");
}
}
final Function<Map.Entry<String, ?>, Object> entryValueFunction = Map.Entry::getValue;
final Function<Object, String> stringCast = String.class::cast;
return Collections.unmodifiableMap(meta.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entryValueFunction.andThen(stringCast))));
Map<String, String> sortedMeta = new TreeMap<>();
for (Map.Entry<String, ?> entry : meta.entrySet()) {
sortedMeta.put(entry.getKey(), (String) entry.getValue());
}
return Collections.unmodifiableMap(sortedMeta);
}

View File

@ -114,7 +114,7 @@ public class IndicesModule extends AbstractModule {
// builtin mappers
for (NumberFieldMapper.NumberType type : NumberFieldMapper.NumberType.values()) {
mappers.put(type.typeName(), new NumberFieldMapper.TypeParser(type));
mappers.put(type.typeName(), type.parser());
}
for (RangeType type : RangeType.values()) {
mappers.put(type.typeName(), new RangeFieldMapper.TypeParser(type));

View File

@ -102,22 +102,22 @@ public abstract class AbstractFieldDataTestCase extends ESSingleNodeTestCase {
fieldType = new TextFieldMapper.Builder(fieldName).fielddata(true).build(context).fieldType();
}
} else if (type.equals("float")) {
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.FLOAT)
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.FLOAT, false, true)
.docValues(docValues).build(context).fieldType();
} else if (type.equals("double")) {
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.DOUBLE)
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.DOUBLE, false, true)
.docValues(docValues).build(context).fieldType();
} else if (type.equals("long")) {
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.LONG)
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.LONG, false, true)
.docValues(docValues).build(context).fieldType();
} else if (type.equals("int")) {
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.INTEGER)
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.INTEGER, false, true)
.docValues(docValues).build(context).fieldType();
} else if (type.equals("short")) {
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.SHORT)
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.SHORT, false, true)
.docValues(docValues).build(context).fieldType();
} else if (type.equals("byte")) {
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.BYTE)
fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.BYTE, false, true)
.docValues(docValues).build(context).fieldType();
} else if (type.equals("geo_point")) {
fieldType = new GeoPointFieldMapper.Builder(fieldName).docValues(docValues).build(context).fieldType();

View File

@ -78,23 +78,23 @@ public class IndexFieldDataServiceTests extends ESSingleNodeTestCase {
assertTrue(fd instanceof SortedSetOrdinalsIndexFieldData);
for (MappedFieldType mapper : Arrays.asList(
new NumberFieldMapper.Builder("int", NumberFieldMapper.NumberType.BYTE).build(ctx).fieldType(),
new NumberFieldMapper.Builder("int", NumberFieldMapper.NumberType.SHORT).build(ctx).fieldType(),
new NumberFieldMapper.Builder("int", NumberFieldMapper.NumberType.INTEGER).build(ctx).fieldType(),
new NumberFieldMapper.Builder("long", NumberFieldMapper.NumberType.LONG).build(ctx).fieldType()
new NumberFieldMapper.Builder("int", NumberFieldMapper.NumberType.BYTE, false, true).build(ctx).fieldType(),
new NumberFieldMapper.Builder("int", NumberFieldMapper.NumberType.SHORT, false, true).build(ctx).fieldType(),
new NumberFieldMapper.Builder("int", NumberFieldMapper.NumberType.INTEGER, false, true).build(ctx).fieldType(),
new NumberFieldMapper.Builder("long", NumberFieldMapper.NumberType.LONG, false, true).build(ctx).fieldType()
)) {
ifdService.clear();
fd = ifdService.getForField(mapper);
assertTrue(fd instanceof SortedNumericIndexFieldData);
}
final MappedFieldType floatMapper = new NumberFieldMapper.Builder("float", NumberFieldMapper.NumberType.FLOAT)
final MappedFieldType floatMapper = new NumberFieldMapper.Builder("float", NumberFieldMapper.NumberType.FLOAT, false, true)
.build(ctx).fieldType();
ifdService.clear();
fd = ifdService.getForField(floatMapper);
assertTrue(fd instanceof SortedNumericIndexFieldData);
final MappedFieldType doubleMapper = new NumberFieldMapper.Builder("double", NumberFieldMapper.NumberType.DOUBLE)
final MappedFieldType doubleMapper = new NumberFieldMapper.Builder("double", NumberFieldMapper.NumberType.DOUBLE, false, true)
.build(ctx).fieldType();
ifdService.clear();
fd = ifdService.getForField(doubleMapper);

View File

@ -31,7 +31,6 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
@ -43,16 +42,16 @@ import org.elasticsearch.search.lookup.SourceLookup;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.containsString;
public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase<NumberFieldMapper.Builder> {
public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase {
@Override
protected void setTypeList() {
@ -60,11 +59,6 @@ public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase<N
WHOLE_TYPES = new HashSet<>(Arrays.asList("byte", "short", "integer", "long"));
}
@Override
protected Set<String> unsupportedProperties() {
return org.elasticsearch.common.collect.Set.of("analyzer", "similarity");
}
@Override
public void doTestDefaults(String type) throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
@ -274,12 +268,7 @@ public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase<N
*/
public void testIgnoreMalformedWithObject() throws Exception {
for (String type : TYPES) {
Object malformedValue = new ToXContentObject() {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().field("foo", "bar").endObject();
}
};
Object malformedValue = (ToXContentObject) (builder, params) -> builder.startObject().field("foo", "bar").endObject();
for (Boolean ignoreMalformed : new Boolean[] { true, false }) {
String mapping = Strings.toString(
jsonBuilder().startObject().startObject("type").startObject("properties").startObject("field").field("type", type)
@ -297,42 +286,6 @@ public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase<N
}
}
public void testRejectNorms() throws IOException {
// not supported as of 5.0
for (String type : TYPES) {
DocumentMapperParser parser = createIndex("index-" + type).mapperService().documentMapperParser();
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties")
.startObject("foo")
.field("type", type)
.field("norms", random().nextBoolean())
.endObject()
.endObject().endObject().endObject());
MapperParsingException e = expectThrows(MapperParsingException.class,
() -> parser.parse("type", new CompressedXContent(mapping)));
assertThat(e.getMessage(), containsString("Mapping definition for [foo] has unsupported parameters: [norms"));
}
}
/**
* `index_options` was deprecated and is rejected as of 7.0
*/
public void testRejectIndexOptions() throws IOException {
for (String type : TYPES) {
DocumentMapperParser parser = createIndex("index-" + type).mapperService().documentMapperParser();
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties")
.startObject("foo")
.field("type", type)
.field("index_options", randomFrom(new String[] { "docs", "freqs", "positions", "offsets" }))
.endObject()
.endObject().endObject().endObject());
MapperParsingException e = expectThrows(MapperParsingException.class,
() -> parser.parse("type", new CompressedXContent(mapping)));
assertThat(e.getMessage(), containsString("index_options not allowed in field [foo] of type [" + type +"]"));
}
}
@Override
protected void doTestNullValue(String type) throws IOException {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
@ -410,11 +363,11 @@ public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase<N
Settings settings = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT.id).build();
Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath());
NumberFieldMapper mapper = new NumberFieldMapper.Builder("field", NumberType.INTEGER).build(context);
NumberFieldMapper mapper = new NumberFieldMapper.Builder("field", NumberType.INTEGER, false, true).build(context);
assertEquals(3, mapper.parseSourceValue(3.14, null));
assertEquals(42, mapper.parseSourceValue("42.9", null));
NumberFieldMapper nullValueMapper = new NumberFieldMapper.Builder("field", NumberType.FLOAT)
NumberFieldMapper nullValueMapper = new NumberFieldMapper.Builder("field", NumberType.FLOAT, false, true)
.nullValue(2.71f)
.build(context);
assertEquals(2.71f, (float) nullValueMapper.parseSourceValue("", null), 0.00001);
@ -499,18 +452,7 @@ public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase<N
.setType("_doc").setSource(mapping, XContentType.JSON).get();
String doc = "{\"number\" : 9223372036854775808}";
IndexResponse response = client().index(new IndexRequest("test57287").source(doc, XContentType.JSON)).get();
assertTrue(response.status() == RestStatus.CREATED);
}
public void testDeprecatedSimilarityParameter() throws Exception {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
.startObject("field")
.field("type", "long")
.field("similarity", "bm25")
.endObject().endObject().endObject().endObject());
parser.parse("type", new CompressedXContent(mapping));
assertWarnings("The [similarity] parameter has no effect on field [field] and will be removed in 8.0");
assertSame(response.status(), RestStatus.CREATED);
}
private void parseRequest(NumberType type, BytesReference content) throws IOException {
@ -537,15 +479,11 @@ public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase<N
if (value instanceof BigInteger) {
return BytesReference.bytes(XContentFactory.jsonBuilder()
.startObject()
.rawField("field", new ByteArrayInputStream(value.toString().getBytes("UTF-8")), XContentType.JSON)
.rawField("field", new ByteArrayInputStream(value.toString().getBytes(StandardCharsets.UTF_8)), XContentType.JSON)
.endObject());
} else {
return BytesReference.bytes(XContentFactory.jsonBuilder().startObject().field("field", value).endObject());
}
}
@Override
protected NumberFieldMapper.Builder newBuilder() {
return new NumberFieldMapper.Builder("number", NumberType.LONG);
}
}

View File

@ -35,7 +35,6 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.InternalSettingsPlugin;
import org.junit.Before;
import java.io.IOException;
import java.net.InetAddress;
@ -44,7 +43,6 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.index.query.RangeQueryBuilder.GTE_FIELD;
import static org.elasticsearch.index.query.RangeQueryBuilder.GT_FIELD;
@ -54,30 +52,7 @@ import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase<RangeFieldMapper.Builder> {
@Override
protected RangeFieldMapper.Builder newBuilder() {
return new RangeFieldMapper.Builder("range", RangeType.DATE)
.format("iso8601");
}
@Override
protected Set<String> unsupportedProperties() {
return org.elasticsearch.common.collect.Set.of("analyzer", "similarity");
}
@Before
public void addModifiers() {
addModifier("format", true, (a, b) -> {
a.format("basic_week_date");
b.format("strict_week_date");
});
addModifier("locale", true, (a, b) -> {
a.locale(Locale.CANADA);
b.locale(Locale.JAPAN);
});
}
public class RangeFieldMapperTests extends AbstractNumericFieldMapperTestCase {
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.mapper.MapperService.MergeReason;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.elasticsearch.test.InternalSettingsPlugin;
import org.junit.Before;
@ -34,7 +35,7 @@ import java.util.Set;
import static org.hamcrest.Matchers.containsString;
public abstract class AbstractNumericFieldMapperTestCase<T extends FieldMapper.Builder<?>> extends FieldMapperTestCase<T> {
public abstract class AbstractNumericFieldMapperTestCase extends ESSingleNodeTestCase {
protected Set<String> TYPES;
protected Set<String> WHOLE_TYPES;
protected IndexService indexService;

View File

@ -551,7 +551,7 @@ public class RollupIndexerIndexingTests extends AggregatorTestCase {
if (job.getGroupConfig().getHistogram() != null) {
for (String field : job.getGroupConfig().getHistogram().getFields()) {
MappedFieldType ft = new NumberFieldMapper.Builder(field, NumberFieldMapper.NumberType.LONG)
MappedFieldType ft = new NumberFieldMapper.Builder(field, NumberFieldMapper.NumberType.LONG, false, false)
.build(new Mapper.BuilderContext(settings.getSettings(), new ContentPath(0)))
.fieldType();
fieldTypes.put(ft.name(), ft);
@ -569,7 +569,7 @@ public class RollupIndexerIndexingTests extends AggregatorTestCase {
if (job.getMetricsConfig() != null) {
for (MetricConfig metric : job.getMetricsConfig()) {
MappedFieldType ft = new NumberFieldMapper.Builder(metric.getField(), NumberFieldMapper.NumberType.LONG)
MappedFieldType ft = new NumberFieldMapper.Builder(metric.getField(), NumberFieldMapper.NumberType.LONG, false, false)
.build(new Mapper.BuilderContext(settings.getSettings(), new ContentPath(0)))
.fieldType();
fieldTypes.put(ft.name(), ft);