diff --git a/core/src/main/java/org/elasticsearch/search/DocValueFormat.java b/core/src/main/java/org/elasticsearch/search/DocValueFormat.java index 4c32667aa2a..eb76db3be68 100644 --- a/core/src/main/java/org/elasticsearch/search/DocValueFormat.java +++ b/core/src/main/java/org/elasticsearch/search/DocValueFormat.java @@ -393,5 +393,22 @@ public interface DocValueFormat extends NamedWriteable { public BytesRef parseBytesRef(String value) { throw new UnsupportedOperationException(); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Decimal that = (Decimal) o; + return Objects.equals(pattern, that.pattern); + } + + @Override + public int hashCode() { + return Objects.hash(pattern); + } } } diff --git a/core/src/test/java/org/elasticsearch/search/DocValueFormatTests.java b/core/src/test/java/org/elasticsearch/search/DocValueFormatTests.java index 049e133b357..7bf5308eb63 100644 --- a/core/src/test/java/org/elasticsearch/search/DocValueFormatTests.java +++ b/core/src/test/java/org/elasticsearch/search/DocValueFormatTests.java @@ -19,9 +19,6 @@ package org.elasticsearch.search; -import java.util.ArrayList; -import java.util.List; - import org.apache.lucene.document.InetAddressPoint; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.io.stream.BytesStreamOutput; @@ -34,6 +31,9 @@ import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.test.ESTestCase; import org.joda.time.DateTimeZone; +import java.util.ArrayList; +import java.util.List; + public class DocValueFormatTests extends ESTestCase { public void testSerialization() throws Exception { @@ -108,6 +108,18 @@ public class DocValueFormatTests extends ESTestCase { DocValueFormat.IP.format(new BytesRef(InetAddressPoint.encode(InetAddresses.forString("::1"))))); } + public void testDecimalFormat() { + DocValueFormat formatter = new DocValueFormat.Decimal("###.##"); + assertEquals("0", formatter.format(0.0d)); + assertEquals("1", formatter.format(1d)); + formatter = new DocValueFormat.Decimal("000.000"); + assertEquals("-000.500", formatter.format(-0.5)); + formatter = new DocValueFormat.Decimal("###,###.###"); + assertEquals("0.86", formatter.format(0.8598023539251286d)); + formatter = new DocValueFormat.Decimal("###,###.###"); + assertEquals("859,802.354", formatter.format(0.8598023539251286d * 1_000_000)); + } + public void testRawParse() { assertEquals(-1L, DocValueFormat.RAW.parseLong("-1", randomBoolean(), null)); assertEquals(1L, DocValueFormat.RAW.parseLong("1", randomBoolean(), null)); @@ -145,4 +157,16 @@ public class DocValueFormatTests extends ESTestCase { assertEquals(new BytesRef(InetAddressPoint.encode(InetAddresses.forString("::1"))), DocValueFormat.IP.parseBytesRef("::1")); } + + public void testDecimalParse() { + DocValueFormat parser = new DocValueFormat.Decimal("###.##"); + assertEquals(0.0d, parser.parseDouble(randomFrom("0.0", "0", ".0", ".0000"), true, null), 0.0d); + assertEquals(-1.0d, parser.parseDouble(randomFrom("-1.0", "-1", "-1.0", "-1.0000"), true, null), 0.0d); + assertEquals(0.0d, parser.parseLong("0", true, null), 0.0d); + assertEquals(1.0d, parser.parseLong("1", true, null), 0.0d); + parser = new DocValueFormat.Decimal("###,###.###"); + assertEquals(859802.354d, parser.parseDouble("859,802.354", true, null), 0.0d); + assertEquals(0.859d, parser.parseDouble("0.859", true, null), 0.0d); + assertEquals(0.8598023539251286d, parser.parseDouble("0.8598023539251286", true, null), 0.0d); + } } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java index f899fde087c..02abb394d0f 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java @@ -24,6 +24,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.MockBigArrays; import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; import org.elasticsearch.script.ScriptService; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.SearchModule; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import org.elasticsearch.test.AbstractWireSerializingTestCase; @@ -33,6 +34,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import static java.util.Collections.emptyList; @@ -122,4 +124,15 @@ public abstract class InternalAggregationTestCase protected NamedWriteableRegistry getNamedWriteableRegistry() { return namedWriteableRegistry; } + + /** + * @return a random {@link DocValueFormat} that can be used in aggregations which + * compute numbers. + */ + protected static DocValueFormat randomNumericDocValueFormat() { + final List> formats = new ArrayList<>(3); + formats.add(() -> DocValueFormat.RAW); + formats.add(() -> new DocValueFormat.Decimal(randomFrom("###.##", "###,###.##"))); + return randomFrom(formats).get(); + } } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/InternalSingleBucketAggregationTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/InternalSingleBucketAggregationTestCase.java index 6f8dac7eec4..5d2e8affe78 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/InternalSingleBucketAggregationTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/InternalSingleBucketAggregationTestCase.java @@ -19,7 +19,6 @@ package org.elasticsearch.search.aggregations.bucket; -import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.InternalAggregation; import org.elasticsearch.search.aggregations.InternalAggregationTestCase; import org.elasticsearch.search.aggregations.InternalAggregations; @@ -47,14 +46,10 @@ public abstract class InternalSingleBucketAggregationTestCase pipelineAggregators, Map metaData) { List internal = new ArrayList<>(); if (hasInternalMax) { - internal.add(new InternalMax("max", randomDouble(), - randomFrom(DocValueFormat.BOOLEAN, DocValueFormat.GEOHASH, DocValueFormat.IP, DocValueFormat.RAW), emptyList(), - emptyMap())); + internal.add(new InternalMax("max", randomDouble(), randomNumericDocValueFormat(), emptyList(), emptyMap())); } if (hasInternalMin) { - internal.add(new InternalMin("min", randomDouble(), - randomFrom(DocValueFormat.BOOLEAN, DocValueFormat.GEOHASH, DocValueFormat.IP, DocValueFormat.RAW), emptyList(), - emptyMap())); + internal.add(new InternalMin("min", randomDouble(), randomNumericDocValueFormat(), emptyList(), emptyMap())); } // we shouldn't use the full long range here since we sum doc count on reduce, and don't want to overflow the long range there long docCount = between(0, Integer.MAX_VALUE); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/InternalMaxTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/InternalMaxTests.java index de045ff533e..e2149b24549 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/InternalMaxTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/InternalMaxTests.java @@ -20,7 +20,6 @@ package org.elasticsearch.search.aggregations.metrics; import org.elasticsearch.common.io.stream.Writeable.Reader; -import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.InternalAggregationTestCase; import org.elasticsearch.search.aggregations.metrics.max.InternalMax; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; @@ -31,9 +30,7 @@ import java.util.Map; public class InternalMaxTests extends InternalAggregationTestCase { @Override protected InternalMax createTestInstance(String name, List pipelineAggregators, Map metaData) { - return new InternalMax(name, randomDouble(), - randomFrom(DocValueFormat.BOOLEAN, DocValueFormat.GEOHASH, DocValueFormat.IP, DocValueFormat.RAW), pipelineAggregators, - metaData); + return new InternalMax(name, randomDouble(), randomNumericDocValueFormat(), pipelineAggregators, metaData); } @Override diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/avg/InternalAvgTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/avg/InternalAvgTests.java index 0600d7299b4..1cfb93d6dcc 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/avg/InternalAvgTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/avg/InternalAvgTests.java @@ -32,8 +32,7 @@ public class InternalAvgTests extends InternalAggregationTestCase { @Override protected InternalAvg createTestInstance(String name, List pipelineAggregators, Map metaData) { return new InternalAvg(name, randomDoubleBetween(0, 100000, true), randomNonNegativeLong() % 100000, - randomFrom(DocValueFormat.BOOLEAN, DocValueFormat.GEOHASH, DocValueFormat.IP, DocValueFormat.RAW), pipelineAggregators, - metaData); + randomNumericDocValueFormat(), pipelineAggregators, metaData); } @Override diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/min/InternalMinTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/min/InternalMinTests.java index f93e7c5c81e..d75f03a5de3 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/min/InternalMinTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/min/InternalMinTests.java @@ -30,9 +30,7 @@ import java.util.Map; public class InternalMinTests extends InternalAggregationTestCase { @Override protected InternalMin createTestInstance(String name, List pipelineAggregators, Map metaData) { - return new InternalMin(name, randomDouble(), - randomFrom(DocValueFormat.BOOLEAN, DocValueFormat.GEOHASH, DocValueFormat.IP, DocValueFormat.RAW), pipelineAggregators, - metaData); + return new InternalMin(name, randomDouble(), randomNumericDocValueFormat(), pipelineAggregators, metaData); } @Override diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/InternalSimpleValueTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/InternalSimpleValueTests.java index afb5d869d0e..4dae0a8d653 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/InternalSimpleValueTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/InternalSimpleValueTests.java @@ -32,8 +32,7 @@ public class InternalSimpleValueTests extends InternalAggregationTestCase pipelineAggregators, Map metaData) { - DocValueFormat formatter = randomFrom(DocValueFormat.BOOLEAN, DocValueFormat.GEOHASH, - DocValueFormat.IP, DocValueFormat.RAW); + DocValueFormat formatter = randomNumericDocValueFormat(); double value = randomDoubleBetween(0, 100000, true); return new InternalSimpleValue(name, value, formatter, pipelineAggregators, metaData); } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/derivative/InternalDerivativeTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/derivative/InternalDerivativeTests.java index 1889723fa8a..d2e4f3cb720 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/derivative/InternalDerivativeTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/pipeline/derivative/InternalDerivativeTests.java @@ -33,12 +33,10 @@ public class InternalDerivativeTests extends InternalAggregationTestCase pipelineAggregators, Map metaData) { - DocValueFormat formatter = randomFrom(DocValueFormat.BOOLEAN, DocValueFormat.GEOHASH, - DocValueFormat.IP, DocValueFormat.RAW); + DocValueFormat formatter = randomNumericDocValueFormat(); double value = randomDoubleBetween(0, 100000, true); double normalizationFactor = randomDoubleBetween(0, 100000, true); - return new InternalDerivative(name, value, normalizationFactor, formatter, - pipelineAggregators, metaData); + return new InternalDerivative(name, value, normalizationFactor, formatter, pipelineAggregators, metaData); } @Override