mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-25 01:19:02 +00:00
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:
parent
039b306e7d
commit
a3a0c63ccf
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user