|
@@ -13,7 +13,6 @@ import org.apache.lucene.index.IndexableField;
|
|
|
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
|
|
import org.elasticsearch.common.Strings;
|
|
|
import org.elasticsearch.common.bytes.BytesReference;
|
|
|
-import org.elasticsearch.core.Tuple;
|
|
|
import org.elasticsearch.index.IndexMode;
|
|
|
import org.elasticsearch.index.IndexSettings;
|
|
|
import org.elasticsearch.index.mapper.DocumentMapper;
|
|
@@ -38,7 +37,10 @@ import java.io.IOException;
|
|
|
import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
import java.util.function.Function;
|
|
|
+import java.util.function.Supplier;
|
|
|
+import java.util.stream.Stream;
|
|
|
|
|
|
import static java.util.Collections.singletonList;
|
|
|
import static org.hamcrest.Matchers.containsString;
|
|
@@ -239,7 +241,8 @@ public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests {
|
|
|
exampleMalformedValue("a").errorMatches("For input string: \"a\""),
|
|
|
exampleMalformedValue("NaN").errorMatches("[scaled_float] only supports finite values, but got [NaN]"),
|
|
|
exampleMalformedValue("Infinity").errorMatches("[scaled_float] only supports finite values, but got [Infinity]"),
|
|
|
- exampleMalformedValue("-Infinity").errorMatches("[scaled_float] only supports finite values, but got [-Infinity]")
|
|
|
+ exampleMalformedValue("-Infinity").errorMatches("[scaled_float] only supports finite values, but got [-Infinity]"),
|
|
|
+ exampleMalformedValue(b -> b.value(true)).errorMatches("Current token (VALUE_TRUE) not numeric")
|
|
|
);
|
|
|
}
|
|
|
|
|
@@ -361,35 +364,63 @@ public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests {
|
|
|
|
|
|
@Override
|
|
|
protected SyntheticSourceSupport syntheticSourceSupport(boolean ignoreMalformed) {
|
|
|
- assumeFalse("scaled_float doesn't support ignore_malformed with synthetic _source", ignoreMalformed);
|
|
|
- return new ScaledFloatSyntheticSourceSupport();
|
|
|
+ return new ScaledFloatSyntheticSourceSupport(ignoreMalformed);
|
|
|
}
|
|
|
|
|
|
private static class ScaledFloatSyntheticSourceSupport implements SyntheticSourceSupport {
|
|
|
+ private final boolean ignoreMalformedEnabled;
|
|
|
private final double scalingFactor = randomDoubleBetween(0, Double.MAX_VALUE, false);
|
|
|
private final Double nullValue = usually() ? null : round(randomValue());
|
|
|
|
|
|
+ private ScaledFloatSyntheticSourceSupport(boolean ignoreMalformedEnabled) {
|
|
|
+ this.ignoreMalformedEnabled = ignoreMalformedEnabled;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public SyntheticSourceExample example(int maxValues) {
|
|
|
if (randomBoolean()) {
|
|
|
- Tuple<Double, Double> v = generateValue();
|
|
|
- return new SyntheticSourceExample(v.v1(), v.v2(), roundDocValues(v.v2()), this::mapping);
|
|
|
+ Value v = generateValue();
|
|
|
+ if (v.malformedOutput == null) {
|
|
|
+ return new SyntheticSourceExample(v.input, v.output, roundDocValues(v.output), this::mapping);
|
|
|
+ }
|
|
|
+ return new SyntheticSourceExample(v.input, v.malformedOutput, null, this::mapping);
|
|
|
}
|
|
|
- List<Tuple<Double, Double>> values = randomList(1, maxValues, this::generateValue);
|
|
|
- List<Double> in = values.stream().map(Tuple::v1).toList();
|
|
|
- List<Double> outList = values.stream().map(Tuple::v2).sorted().toList();
|
|
|
+ List<Value> values = randomList(1, maxValues, this::generateValue);
|
|
|
+ List<Object> in = values.stream().map(Value::input).toList();
|
|
|
+
|
|
|
+ List<Double> outputFromDocValues = values.stream().filter(v -> v.malformedOutput == null).map(Value::output).sorted().toList();
|
|
|
+ Stream<Object> malformedOutput = values.stream().filter(v -> v.malformedOutput != null).map(Value::malformedOutput);
|
|
|
+
|
|
|
+ // Malformed values are always last in the implementation.
|
|
|
+ List<Object> outList = Stream.concat(outputFromDocValues.stream(), malformedOutput).toList();
|
|
|
Object out = outList.size() == 1 ? outList.get(0) : outList;
|
|
|
- List<Double> outBlockList = values.stream().map(v -> roundDocValues(v.v2())).sorted().toList();
|
|
|
+
|
|
|
+ List<Double> outBlockList = outputFromDocValues.stream().map(this::roundDocValues).sorted().toList();
|
|
|
Object outBlock = outBlockList.size() == 1 ? outBlockList.get(0) : outBlockList;
|
|
|
return new SyntheticSourceExample(in, out, outBlock, this::mapping);
|
|
|
}
|
|
|
|
|
|
- private Tuple<Double, Double> generateValue() {
|
|
|
+ private record Value(Object input, Double output, Object malformedOutput) {}
|
|
|
+
|
|
|
+ private Value generateValue() {
|
|
|
if (nullValue != null && randomBoolean()) {
|
|
|
- return Tuple.tuple(null, nullValue);
|
|
|
+ return new Value(null, nullValue, null);
|
|
|
+ }
|
|
|
+ // Examples in #exampleMalformedValues() are also tested with synthetic source
|
|
|
+ // so this is not an exhaustive list.
|
|
|
+ // Here we mostly want to verify behavior of arrays that contain malformed
|
|
|
+ // values since there are modifications specific to synthetic source.
|
|
|
+ if (ignoreMalformedEnabled && randomBoolean()) {
|
|
|
+ List<Supplier<Object>> choices = List.of(
|
|
|
+ () -> randomAlphaOfLengthBetween(1, 10),
|
|
|
+ () -> Map.of(randomAlphaOfLengthBetween(1, 10), randomAlphaOfLengthBetween(1, 10)),
|
|
|
+ () -> List.of(randomAlphaOfLengthBetween(1, 10), randomAlphaOfLengthBetween(1, 10))
|
|
|
+ );
|
|
|
+ var malformedInput = randomFrom(choices).get();
|
|
|
+ return new Value(malformedInput, null, malformedInput);
|
|
|
}
|
|
|
double d = randomValue();
|
|
|
- return Tuple.tuple(d, round(d));
|
|
|
+ return new Value(d, round(d), null);
|
|
|
}
|
|
|
|
|
|
private double round(double d) {
|
|
@@ -433,6 +464,9 @@ public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests {
|
|
|
if (rarely()) {
|
|
|
b.field("store", false);
|
|
|
}
|
|
|
+ if (ignoreMalformedEnabled) {
|
|
|
+ b.field("ignore_malformed", true);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -441,10 +475,6 @@ public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests {
|
|
|
new SyntheticSourceInvalidExample(
|
|
|
equalTo("field [field] of type [scaled_float] doesn't support synthetic source because it doesn't have doc values"),
|
|
|
b -> b.field("type", "scaled_float").field("scaling_factor", 10).field("doc_values", false)
|
|
|
- ),
|
|
|
- new SyntheticSourceInvalidExample(
|
|
|
- equalTo("field [field] of type [scaled_float] doesn't support synthetic source because it ignores malformed numbers"),
|
|
|
- b -> b.field("type", "scaled_float").field("scaling_factor", 10).field("ignore_malformed", true)
|
|
|
)
|
|
|
);
|
|
|
}
|