From e0956b6491c90d7672b05c2f6623df808ba85022 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Thu, 20 Apr 2017 10:16:51 +0200 Subject: [PATCH] Add parsing methods for Percentiles aggregations (#24183) --- .../percentiles/ParsedPercentileRanks.java | 2 +- ...ercentiles.java => ParsedPercentiles.java} | 8 +- .../hdr/ParsedHDRPercentileRanks.java | 4 +- .../percentiles/hdr/ParsedHDRPercentiles.java | 57 +++++++++++++ .../tdigest/ParsedTDigestPercentileRanks.java | 4 +- .../tdigest/ParsedTDigestPercentiles.java | 57 +++++++++++++ .../InternalAggregationTestCase.java | 45 +++++++--- .../AbstractPercentilesTestCase.java | 84 +++++++++++++++++++ .../InternalPercentilesRanksTestCase.java | 82 ++---------------- .../InternalPercentilesTestCase.java | 41 +++++++++ .../hdr/InternalHDRPercentilesRanksTests.java | 14 ++-- .../hdr/InternalHDRPercentilesTests.java | 50 +++++++++++ .../InternalTDigestPercentilesRanksTests.java | 18 ++-- .../InternalTDigestPercentilesTests.java | 50 +++++++++++ 14 files changed, 407 insertions(+), 109 deletions(-) rename core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/{AbstractParsedPercentiles.java => ParsedPercentiles.java} (96%) create mode 100644 core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/ParsedHDRPercentiles.java create mode 100644 core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/ParsedTDigestPercentiles.java create mode 100644 core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/AbstractPercentilesTestCase.java create mode 100644 core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/InternalPercentilesTestCase.java create mode 100644 core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/InternalHDRPercentilesTests.java create mode 100644 core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/InternalTDigestPercentilesTests.java diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/ParsedPercentileRanks.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/ParsedPercentileRanks.java index de3e81e966cf2..2c80d0328dd86 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/ParsedPercentileRanks.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/ParsedPercentileRanks.java @@ -19,7 +19,7 @@ package org.elasticsearch.search.aggregations.metrics.percentiles; -public abstract class ParsedPercentileRanks extends AbstractParsedPercentiles implements PercentileRanks { +public abstract class ParsedPercentileRanks extends ParsedPercentiles implements PercentileRanks { @Override public double percent(double value) { diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/AbstractParsedPercentiles.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/ParsedPercentiles.java similarity index 96% rename from core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/AbstractParsedPercentiles.java rename to core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/ParsedPercentiles.java index e3152bac3a36c..eee058fc2f861 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/AbstractParsedPercentiles.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/ParsedPercentiles.java @@ -31,7 +31,7 @@ import java.util.LinkedHashMap; import java.util.Map; -public abstract class AbstractParsedPercentiles extends ParsedAggregation implements Iterable { +public abstract class ParsedPercentiles extends ParsedAggregation implements Iterable { private final Map percentiles = new LinkedHashMap<>(); private final Map percentilesAsString = new HashMap<>(); @@ -46,14 +46,14 @@ void addPercentileAsString(Double key, String valueAsString) { percentilesAsString.put(key, valueAsString); } - Double getPercentile(double percent) { + protected Double getPercentile(double percent) { if (percentiles.isEmpty()) { return Double.NaN; } return percentiles.get(percent); } - String getPercentileAsString(double percent) { + protected String getPercentileAsString(double percent) { String valueAsString = percentilesAsString.get(percent); if (valueAsString != null) { return valueAsString; @@ -119,7 +119,7 @@ protected XContentBuilder doXContentBody(XContentBuilder builder, Params params) return builder; } - protected static void declarePercentilesFields(ObjectParser objectParser) { + protected static void declarePercentilesFields(ObjectParser objectParser) { ParsedAggregation.declareAggregationFields(objectParser); objectParser.declareField((parser, aggregation, context) -> { diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/ParsedHDRPercentileRanks.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/ParsedHDRPercentileRanks.java index 79749df11760b..5d00d8dc8e3f0 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/ParsedHDRPercentileRanks.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/ParsedHDRPercentileRanks.java @@ -21,7 +21,7 @@ import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.search.aggregations.metrics.percentiles.AbstractParsedPercentiles; +import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentileRanks; import org.elasticsearch.search.aggregations.metrics.percentiles.Percentile; @@ -55,7 +55,7 @@ public Percentile next() { private static ObjectParser PARSER = new ObjectParser<>(ParsedHDRPercentileRanks.class.getSimpleName(), true, ParsedHDRPercentileRanks::new); static { - AbstractParsedPercentiles.declarePercentilesFields(PARSER); + ParsedPercentiles.declarePercentilesFields(PARSER); } public static ParsedHDRPercentileRanks fromXContent(XContentParser parser, String name) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/ParsedHDRPercentiles.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/ParsedHDRPercentiles.java new file mode 100644 index 0000000000000..0b6da9f00e112 --- /dev/null +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/ParsedHDRPercentiles.java @@ -0,0 +1,57 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.aggregations.metrics.percentiles.hdr; + +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; +import org.elasticsearch.search.aggregations.metrics.percentiles.Percentiles; + +import java.io.IOException; + +public class ParsedHDRPercentiles extends ParsedPercentiles implements Percentiles { + + @Override + protected String getType() { + return InternalHDRPercentiles.NAME; + } + + @Override + public double percentile(double percent) { + return getPercentile(percent); + } + + @Override + public String percentileAsString(double percent) { + return getPercentileAsString(percent); + } + + private static ObjectParser PARSER = + new ObjectParser<>(ParsedHDRPercentiles.class.getSimpleName(), true, ParsedHDRPercentiles::new); + static { + ParsedPercentiles.declarePercentilesFields(PARSER); + } + + public static ParsedHDRPercentiles fromXContent(XContentParser parser, String name) throws IOException { + ParsedHDRPercentiles aggregation = PARSER.parse(parser, null); + aggregation.setName(name); + return aggregation; + } +} diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/ParsedTDigestPercentileRanks.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/ParsedTDigestPercentileRanks.java index 3d51e98d62201..34fd92ad4fb2d 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/ParsedTDigestPercentileRanks.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/ParsedTDigestPercentileRanks.java @@ -21,7 +21,7 @@ import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.search.aggregations.metrics.percentiles.AbstractParsedPercentiles; +import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentileRanks; import org.elasticsearch.search.aggregations.metrics.percentiles.Percentile; @@ -55,7 +55,7 @@ public Percentile next() { private static ObjectParser PARSER = new ObjectParser<>(ParsedTDigestPercentileRanks.class.getSimpleName(), true, ParsedTDigestPercentileRanks::new); static { - AbstractParsedPercentiles.declarePercentilesFields(PARSER); + ParsedPercentiles.declarePercentilesFields(PARSER); } public static ParsedTDigestPercentileRanks fromXContent(XContentParser parser, String name) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/ParsedTDigestPercentiles.java b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/ParsedTDigestPercentiles.java new file mode 100644 index 0000000000000..bdd2d6b810a2c --- /dev/null +++ b/core/src/main/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/ParsedTDigestPercentiles.java @@ -0,0 +1,57 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.aggregations.metrics.percentiles.tdigest; + +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; +import org.elasticsearch.search.aggregations.metrics.percentiles.Percentiles; + +import java.io.IOException; + +public class ParsedTDigestPercentiles extends ParsedPercentiles implements Percentiles { + + @Override + protected String getType() { + return InternalTDigestPercentiles.NAME; + } + + @Override + public double percentile(double percent) { + return getPercentile(percent); + } + + @Override + public String percentileAsString(double percent) { + return getPercentileAsString(percent); + } + + private static ObjectParser PARSER = + new ObjectParser<>(ParsedTDigestPercentiles.class.getSimpleName(), true, ParsedTDigestPercentiles::new); + static { + ParsedPercentiles.declarePercentilesFields(PARSER); + } + + public static ParsedTDigestPercentiles fromXContent(XContentParser parser, String name) throws IOException { + ParsedTDigestPercentiles aggregation = PARSER.parse(parser, null); + aggregation.setName(name); + return aggregation; + } +} 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 ac58866cb3e2b..6747924382dba 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java @@ -27,6 +27,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.rest.action.search.RestSearchAction; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.metrics.avg.AvgAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.avg.ParsedAvg; import org.elasticsearch.search.aggregations.metrics.cardinality.CardinalityAggregationBuilder; @@ -36,16 +37,19 @@ import org.elasticsearch.search.aggregations.metrics.min.MinAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.min.ParsedMin; import org.elasticsearch.search.aggregations.metrics.percentiles.hdr.InternalHDRPercentileRanks; +import org.elasticsearch.search.aggregations.metrics.percentiles.hdr.InternalHDRPercentiles; import org.elasticsearch.search.aggregations.metrics.percentiles.hdr.ParsedHDRPercentileRanks; +import org.elasticsearch.search.aggregations.metrics.percentiles.hdr.ParsedHDRPercentiles; import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.InternalTDigestPercentileRanks; +import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.InternalTDigestPercentiles; import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.ParsedTDigestPercentileRanks; +import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.ParsedTDigestPercentiles; import org.elasticsearch.search.aggregations.metrics.sum.ParsedSum; import org.elasticsearch.search.aggregations.metrics.sum.SumAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.valuecount.ParsedValueCount; import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCountAggregationBuilder; import org.elasticsearch.search.aggregations.pipeline.InternalSimpleValue; import org.elasticsearch.search.aggregations.pipeline.ParsedSimpleValue; -import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.search.aggregations.pipeline.derivative.DerivativePipelineAggregationBuilder; @@ -70,7 +74,9 @@ public abstract class InternalAggregationTestCase static List getNamedXContents() { Map> namedXContents = new HashMap<>(); namedXContents.put(CardinalityAggregationBuilder.NAME, (p, c) -> ParsedCardinality.fromXContent(p, (String) c)); + namedXContents.put(InternalHDRPercentiles.NAME, (p, c) -> ParsedHDRPercentiles.fromXContent(p, (String) c)); namedXContents.put(InternalHDRPercentileRanks.NAME, (p, c) -> ParsedHDRPercentileRanks.fromXContent(p, (String) c)); + namedXContents.put(InternalTDigestPercentiles.NAME, (p, c) -> ParsedTDigestPercentiles.fromXContent(p, (String) c)); namedXContents.put(InternalTDigestPercentileRanks.NAME, (p, c) -> ParsedTDigestPercentileRanks.fromXContent(p, (String) c)); namedXContents.put(MinAggregationBuilder.NAME, (p, c) -> ParsedMin.fromXContent(p, (String) c)); namedXContents.put(MaxAggregationBuilder.NAME, (p, c) -> ParsedMax.fromXContent(p, (String) c)); @@ -108,7 +114,6 @@ protected NamedXContentRegistry xContentRegistry() { } public final void testFromXContent() throws IOException { - final NamedXContentRegistry xContentRegistry = xContentRegistry(); final T aggregation = createTestInstance(); //norelease Remove this assumption when all aggregations can be parsed back. @@ -120,8 +125,33 @@ public final void testFromXContent() throws IOException { final XContentType xContentType = randomFrom(XContentType.values()); final BytesReference originalBytes = toShuffledXContent(aggregation, xContentType, params, humanReadable); + final Aggregation parsedAggregation = parse(aggregation, xContentType, humanReadable, randomBoolean()); + + final BytesReference parsedBytes = toXContent((ToXContent) parsedAggregation, xContentType, params, humanReadable); + assertToXContentEquivalent(originalBytes, parsedBytes, xContentType); + assertFromXContent(aggregation, (ParsedAggregation) parsedAggregation); + } + + //norelease TODO make abstract + protected void assertFromXContent(T aggregation, ParsedAggregation parsedAggregation) { + } + + @SuppressWarnings("unchecked") + protected

P parse(final InternalAggregation aggregation, + final XContentType xContentType, + final boolean humanReadable, + final boolean shuffled) throws IOException { + + final ToXContent.Params params = new ToXContent.MapParams(singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true")); + final BytesReference originalBytes; + if (shuffled) { + originalBytes = toShuffledXContent(aggregation, xContentType, params, humanReadable); + } else { + originalBytes = toXContent(aggregation, xContentType, params, humanReadable); + } + Aggregation parsedAggregation; - try (XContentParser parser = xContentType.xContent().createParser(xContentRegistry, originalBytes)) { + try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) { assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken()); assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken()); @@ -141,15 +171,8 @@ public final void testFromXContent() throws IOException { assertTrue(parsedAggregation instanceof ParsedAggregation); assertEquals(aggregation.getType(), ((ParsedAggregation) parsedAggregation).getType()); - - final BytesReference parsedBytes = toXContent((ToXContent) parsedAggregation, xContentType, params, humanReadable); - assertToXContentEquivalent(originalBytes, parsedBytes, xContentType); - assertFromXContent(aggregation, (ParsedAggregation) parsedAggregation); } - } - - //norelease TODO make abstract - protected void assertFromXContent(T aggregation, ParsedAggregation parsedAggregation) { + return (P) parsedAggregation; } /** diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/AbstractPercentilesTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/AbstractPercentilesTestCase.java new file mode 100644 index 0000000000000..0859a5111778d --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/AbstractPercentilesTestCase.java @@ -0,0 +1,84 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.aggregations.metrics.percentiles; + +import com.carrotsearch.randomizedtesting.annotations.Repeat; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.search.aggregations.InternalAggregation; +import org.elasticsearch.search.aggregations.InternalAggregationTestCase; +import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; +import org.junit.Before; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public abstract class AbstractPercentilesTestCase> + extends InternalAggregationTestCase { + + private double[] percents; + private boolean keyed; + private DocValueFormat docValueFormat; + + @Before + public void init() { + percents = randomPercents(); + keyed = randomBoolean(); + docValueFormat = randomNumericDocValueFormat(); + } + + @Override + protected T createTestInstance(String name, List pipelineAggregators, Map metaData) { + int numValues = randomInt(100); + double[] values = new double[numValues]; + for (int i = 0; i < numValues; ++i) { + values[i] = randomDouble(); + } + return createTestInstance(name, pipelineAggregators, metaData, keyed, docValueFormat, percents, values); + } + + protected abstract T createTestInstance(String name, List pipelineAggregators, Map metaData, + boolean keyed, DocValueFormat format, double[] percents, double[] values); + + protected abstract Class implementationClass(); + + @Repeat(iterations = 1000) + public void testPercentilesIterators() throws IOException { + final T aggregation = createTestInstance(); + final Iterable parsedAggregation = parse(aggregation, randomFrom(XContentType.values()), randomBoolean(), false); + + Iterator it = aggregation.iterator(); + Iterator parsedIt = parsedAggregation.iterator(); + while (it.hasNext()) { + assertEquals(it.next(), parsedIt.next()); + } + } + + private static double[] randomPercents() { + List randomCdfValues = randomSubsetOf(randomIntBetween(1, 7), 0.01d, 0.05d, 0.25d, 0.50d, 0.75d, 0.95d, 0.99d); + double[] percents = new double[randomCdfValues.size()]; + for (int i = 0; i < randomCdfValues.size(); i++) { + percents[i] = randomCdfValues.get(i); + } + return percents; + } +} diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/InternalPercentilesRanksTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/InternalPercentilesRanksTestCase.java index be7d55e5447e4..f45b7cce51e37 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/InternalPercentilesRanksTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/InternalPercentilesRanksTestCase.java @@ -19,92 +19,24 @@ package org.elasticsearch.search.aggregations.metrics.percentiles; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentType; -import org.elasticsearch.rest.action.search.RestSearchAction; -import org.elasticsearch.search.DocValueFormat; -import org.elasticsearch.search.aggregations.Aggregation; import org.elasticsearch.search.aggregations.InternalAggregation; -import org.elasticsearch.search.aggregations.InternalAggregationTestCase; import org.elasticsearch.search.aggregations.ParsedAggregation; -import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; -import java.io.IOException; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import static java.util.Collections.singletonMap; -import static org.elasticsearch.common.xcontent.XContentHelper.toXContent; - -public abstract class InternalPercentilesRanksTestCase extends InternalAggregationTestCase { - - @Override - protected final T createTestInstance(String name, List pipelineAggregators, Map metaData) { - final boolean keyed = randomBoolean(); - final DocValueFormat format = randomFrom(DocValueFormat.RAW, new DocValueFormat.Decimal("###.##")); - List randomCdfValues = randomSubsetOf(randomIntBetween(1, 5), 0.01d, 0.05d, 0.25d, 0.50d, 0.75d, 0.95d, 0.99d); - double[] cdfValues = new double[randomCdfValues.size()]; - for (int i = 0; i < randomCdfValues.size(); i++) { - cdfValues[i] = randomCdfValues.get(i); - } - return createTestInstance(name, pipelineAggregators, metaData, cdfValues, keyed, format); - } - - protected abstract T createTestInstance(String name, List aggregators, Map metadata, - double[] cdfValues, boolean keyed, DocValueFormat format); +public abstract class InternalPercentilesRanksTestCase + extends AbstractPercentilesTestCase { @Override protected final void assertFromXContent(T aggregation, ParsedAggregation parsedAggregation) { - assertTrue(aggregation instanceof PercentileRanks); - PercentileRanks percentileRanks = (PercentileRanks) aggregation; - assertTrue(parsedAggregation instanceof PercentileRanks); PercentileRanks parsedPercentileRanks = (PercentileRanks) parsedAggregation; - for (Percentile percentile : percentileRanks) { + for (Percentile percentile : aggregation) { Double value = percentile.getValue(); - assertEquals(percentileRanks.percent(value), parsedPercentileRanks.percent(value), 0); - assertEquals(percentileRanks.percentAsString(value), parsedPercentileRanks.percentAsString(value)); + assertEquals(aggregation.percent(value), parsedPercentileRanks.percent(value), 0); + assertEquals(aggregation.percentAsString(value), parsedPercentileRanks.percentAsString(value)); } - Class parsedClass = parsedParsedPercentileRanksClass(); - assertNotNull(parsedClass); - assertTrue(parsedClass.isInstance(parsedAggregation)); + Class parsedClass = implementationClass(); + assertTrue(parsedClass != null && parsedClass.isInstance(parsedAggregation)); } - - public void testPercentilesRanksIterators() throws IOException { - final T aggregation = createTestInstance(); - - final ToXContent.Params params = new ToXContent.MapParams(singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true")); - final XContentType xContentType = randomFrom(XContentType.values()); - final BytesReference originalBytes = toXContent(aggregation, xContentType, params, randomBoolean()); - - Aggregation parsedAggregation; - try (XContentParser parser = xContentType.xContent().createParser(xContentRegistry(), originalBytes)) { - assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken()); - assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken()); - - String currentName = parser.currentName(); - int i = currentName.indexOf(InternalAggregation.TYPED_KEYS_DELIMITER); - String aggType = currentName.substring(0, i); - String aggName = currentName.substring(i + 1); - - parsedAggregation = parser.namedObject(Aggregation.class, aggType, aggName); - - assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken()); - assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken()); - assertNull(parser.nextToken()); - } - - final Iterator it = ((PercentileRanks) aggregation).iterator(); - final Iterator parsedIt = ((PercentileRanks) parsedAggregation).iterator(); - while (it.hasNext()) { - assertEquals(it.next(), parsedIt.next()); - } - } - - protected abstract Class parsedParsedPercentileRanksClass(); } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/InternalPercentilesTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/InternalPercentilesTestCase.java new file mode 100644 index 0000000000000..404c033f11af8 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/InternalPercentilesTestCase.java @@ -0,0 +1,41 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.aggregations.metrics.percentiles; + +import org.elasticsearch.search.aggregations.InternalAggregation; +import org.elasticsearch.search.aggregations.ParsedAggregation; + +public abstract class InternalPercentilesTestCase extends AbstractPercentilesTestCase { + + @Override + protected final void assertFromXContent(T aggregation, ParsedAggregation parsedAggregation) { + assertTrue(parsedAggregation instanceof Percentiles); + Percentiles parsedPercentiles = (Percentiles) parsedAggregation; + + for (Percentile percentile : aggregation) { + Double percent = percentile.getPercent(); + assertEquals(aggregation.percentile(percent), parsedPercentiles.percentile(percent), 0); + assertEquals(aggregation.percentileAsString(percent), parsedPercentiles.percentileAsString(percent)); + } + + Class parsedClass = implementationClass(); + assertTrue(parsedClass != null && parsedClass.isInstance(parsedAggregation)); + } +} diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/InternalHDRPercentilesRanksTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/InternalHDRPercentilesRanksTests.java index 17140f4014c0e..c837a71346a59 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/InternalHDRPercentilesRanksTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/InternalHDRPercentilesRanksTests.java @@ -23,9 +23,10 @@ import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.metrics.percentiles.InternalPercentilesRanksTestCase; -import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentileRanks; +import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -33,13 +34,16 @@ public class InternalHDRPercentilesRanksTests extends InternalPercentilesRanksTe @Override protected InternalHDRPercentileRanks createTestInstance(String name, List aggregators, Map metadata, - double[] cdfValues, boolean keyed, DocValueFormat format) { - DoubleHistogram state = new DoubleHistogram(3); - return new InternalHDRPercentileRanks(name, cdfValues, state, keyed, format, aggregators, metadata); + boolean keyed, DocValueFormat format, double[] percents, double[] values) { + + final DoubleHistogram state = new DoubleHistogram(3); + Arrays.stream(values).forEach(state::recordValue); + + return new InternalHDRPercentileRanks(name, percents, state, keyed, format, aggregators, metadata); } @Override - protected Class parsedParsedPercentileRanksClass() { + protected Class implementationClass() { return ParsedHDRPercentileRanks.class; } } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/InternalHDRPercentilesTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/InternalHDRPercentilesTests.java new file mode 100644 index 0000000000000..3ab44740a25e3 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/hdr/InternalHDRPercentilesTests.java @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.aggregations.metrics.percentiles.hdr; + +import org.HdrHistogram.DoubleHistogram; +import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.search.aggregations.metrics.percentiles.InternalPercentilesTestCase; +import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; +import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class InternalHDRPercentilesTests extends InternalPercentilesTestCase { + + @Override + protected InternalHDRPercentiles createTestInstance(String name, + List pipelineAggregators, + Map metaData, + boolean keyed, DocValueFormat format, double[] percents, double[] values) { + + final DoubleHistogram state = new DoubleHistogram(3); + Arrays.stream(values).forEach(state::recordValue); + + return new InternalHDRPercentiles(name, percents, state, keyed, format, pipelineAggregators, metaData); + } + + @Override + protected Class implementationClass() { + return ParsedHDRPercentiles.class; + } +} diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/InternalTDigestPercentilesRanksTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/InternalTDigestPercentilesRanksTests.java index c7fcbba6447b3..07758a790c1f7 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/InternalTDigestPercentilesRanksTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/InternalTDigestPercentilesRanksTests.java @@ -19,12 +19,13 @@ package org.elasticsearch.search.aggregations.metrics.percentiles.tdigest; -import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.metrics.percentiles.InternalPercentilesRanksTestCase; import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentileRanks; +import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -33,17 +34,16 @@ public class InternalTDigestPercentilesRanksTests extends InternalPercentilesRan @Override protected InternalTDigestPercentileRanks createTestInstance(String name, List aggregators, Map metadata, - double[] cdfValues, boolean keyed, DocValueFormat format) { - TDigestState state = new TDigestState(100); - int numValues = randomInt(100); - for (int i = 0; i < numValues; ++i) { - state.add(randomDouble()); - } - return new InternalTDigestPercentileRanks(name, cdfValues, state, keyed, format, aggregators, metadata); + boolean keyed, DocValueFormat format, double[] percents, double[] values) { + final TDigestState state = new TDigestState(100); + Arrays.stream(values).forEach(state::add); + + assertEquals(state.centroidCount(), values.length); + return new InternalTDigestPercentileRanks(name, percents, state, keyed, format, aggregators, metadata); } @Override - protected Class parsedParsedPercentileRanksClass() { + protected Class implementationClass() { return ParsedTDigestPercentileRanks.class; } } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/InternalTDigestPercentilesTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/InternalTDigestPercentilesTests.java new file mode 100644 index 0000000000000..ab82c7c4ecde2 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/aggregations/metrics/percentiles/tdigest/InternalTDigestPercentilesTests.java @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.aggregations.metrics.percentiles.tdigest; + +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.search.aggregations.metrics.percentiles.InternalPercentilesTestCase; +import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; +import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class InternalTDigestPercentilesTests extends InternalPercentilesTestCase { + + @Override + protected InternalTDigestPercentiles createTestInstance(String name, + List pipelineAggregators, + Map metaData, + boolean keyed, DocValueFormat format, double[] percents, double[] values) { + final TDigestState state = new TDigestState(100); + Arrays.stream(values).forEach(state::add); + + assertEquals(state.centroidCount(), values.length); + return new InternalTDigestPercentiles(name, percents, state, keyed, format, pipelineAggregators, metaData); + } + + @Override + protected Class implementationClass() { + return ParsedTDigestPercentiles.class; + } +}