This is an automated email from the ASF dual-hosted git repository.

amatya pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 67f45fa7bfc Fix histograms for sketches where min and max are equal 
(#15381)
67f45fa7bfc is described below

commit 67f45fa7bfc5eeb17e9ff23b3519fb01520a8360
Author: Magnus Henoch <[email protected]>
AuthorDate: Thu Nov 16 07:01:22 2023 +0000

    Fix histograms for sketches where min and max are equal (#15381)
    
    There is a problem with Quantiles sketches and KLL Quantiles sketches.
    Queries using the histogram post-aggregator fail if:
    
    - the sketch contains at least one value, and
    - the values in the sketch are all equal, and
    - the splitPoints argument is not passed to the post-aggregator, and
    - the numBins argument is greater than 2 (or not specified, which
      leads to the default of 10 being used)
    
    In that case, the query fails and returns this error:
    
        {
          "error": "Unknown exception",
          "errorClass": 
"org.apache.datasketches.common.SketchesArgumentException",
          "host": null,
          "errorCode": "legacyQueryException",
          "persona": "OPERATOR",
          "category": "RUNTIME_FAILURE",
          "errorMessage": "Values must be unique, monotonically increasing and 
not NaN.",
          "context": {
            "host": null,
            "errorClass": 
"org.apache.datasketches.common.SketchesArgumentException",
            "legacyErrorCode": "Unknown exception"
          }
        }
    
    This behaviour is undesirable, since the caller doesn't necessarily
    know in advance whether the sketch has values that are diverse
    enough. With this change, the post-aggregators return [N, 0, 0...]
    instead of crashing, where N is the number of values in the sketch,
    and the length of the list is equal to numBins. That is what they
    already returned for numBins = 2.
    
    Here is an example of a query that would fail:
    
        {"queryType":"timeseries",
         "dataSource": {
           "type": "inline",
           "columnNames": ["foo", "bar"],
           "rows": [
              ["abc", 42.0],
              ["def", 42.0]
           ]
         },
         "intervals":["0000/3000"],
         "granularity":"all",
         "aggregations":[
           {"name":"the_sketch", "fieldName":"bar", 
"type":"quantilesDoublesSketch"}],
         "postAggregations":[
           {"name":"the_histogram",
            "type":"quantilesDoublesSketchToHistogram",
            "field":{"type":"fieldAccess","fieldName":"the_sketch"},
            "numBins": 3}]}
    
    I believe this also fixes issue #10585.
---
 .../KllDoublesSketchToHistogramPostAggregator.java |  21 ++-
 .../KllFloatsSketchToHistogramPostAggregator.java  |  21 ++-
 .../DoublesSketchToHistogramPostAggregator.java    |  21 ++-
 ...DoublesSketchToHistogramPostAggregatorTest.java | 152 +++++++++++++++++++++
 ...lFloatsSketchToHistogramPostAggregatorTest.java | 152 +++++++++++++++++++++
 ...DoublesSketchToHistogramPostAggregatorTest.java | 152 +++++++++++++++++++++
 6 files changed, 510 insertions(+), 9 deletions(-)

diff --git 
a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllDoublesSketchToHistogramPostAggregator.java
 
b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllDoublesSketchToHistogramPostAggregator.java
index 90a295e7e8a..54a0022cfac 100644
--- 
a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllDoublesSketchToHistogramPostAggregator.java
+++ 
b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllDoublesSketchToHistogramPostAggregator.java
@@ -67,7 +67,7 @@ public class KllDoublesSketchToHistogramPostAggregator 
implements PostAggregator
   public Object compute(final Map<String, Object> combinedAggregators)
   {
     final KllDoublesSketch sketch = (KllDoublesSketch) 
field.compute(combinedAggregators);
-    final int numBins = splitPoints != null ? splitPoints.length + 1 :
+    final int numBins = this.splitPoints != null ? this.splitPoints.length + 1 
:
         (this.numBins != null ? this.numBins.intValue() : DEFAULT_NUM_BINS);
     if (numBins < 2) {
       throw new IAE("at least 2 bins expected");
@@ -77,8 +77,23 @@ public class KllDoublesSketchToHistogramPostAggregator 
implements PostAggregator
       Arrays.fill(histogram, Double.NaN);
       return histogram;
     }
-    final double[] histogram = sketch.getPMF(splitPoints != null ? splitPoints 
:
-      equallySpacedPoints(numBins, sketch.getMinItem(), sketch.getMaxItem()));
+    final double[] splitPoints;
+    if (this.splitPoints != null) {
+      splitPoints = this.splitPoints;
+    } else {
+      final double min = sketch.getMinItem();
+      final double max = sketch.getMaxItem();
+      if (min == max) {
+        // if min is equal to max, we can't create an array of equally spaced 
points.
+        // all values would go into the first bucket anyway, and the remaining
+        // buckets are left as zero.
+        final double[] histogram = new double[numBins];
+        histogram[0] = sketch.getN();
+        return histogram;
+      }
+      splitPoints = equallySpacedPoints(numBins, min, max);
+    }
+    final double[] histogram = sketch.getPMF(splitPoints);
     for (int i = 0; i < histogram.length; i++) {
       histogram[i] *= sketch.getN(); // scale fractions to counts
     }
diff --git 
a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregator.java
 
b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregator.java
index 90e0942f80a..a5bfc68f326 100644
--- 
a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregator.java
+++ 
b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregator.java
@@ -67,7 +67,7 @@ public class KllFloatsSketchToHistogramPostAggregator 
implements PostAggregator
   public Object compute(final Map<String, Object> combinedAggregators)
   {
     final KllFloatsSketch sketch = (KllFloatsSketch) 
field.compute(combinedAggregators);
-    final int numBins = splitPoints != null ? splitPoints.length + 1 :
+    final int numBins = this.splitPoints != null ? this.splitPoints.length + 1 
:
         (this.numBins != null ? this.numBins.intValue() : DEFAULT_NUM_BINS);
     if (numBins < 2) {
       throw new IAE("at least 2 bins expected");
@@ -77,8 +77,23 @@ public class KllFloatsSketchToHistogramPostAggregator 
implements PostAggregator
       Arrays.fill(histogram, Double.NaN);
       return histogram;
     }
-    final double[] histogram = sketch.getPMF(splitPoints != null ? splitPoints 
:
-      equallySpacedPoints(numBins, sketch.getMinItem(), sketch.getMaxItem()));
+    final float[] splitPoints;
+    if (this.splitPoints != null) {
+      splitPoints = this.splitPoints;
+    } else {
+      final float min = sketch.getMinItem();
+      final float max = sketch.getMaxItem();
+      if (min == max) {
+        // if min is equal to max, we can't create an array of equally spaced 
points.
+        // all values would go into the first bucket anyway, and the remaining
+        // buckets are left as zero.
+        final double[] histogram = new double[numBins];
+        histogram[0] = sketch.getN();
+        return histogram;
+      }
+      splitPoints = equallySpacedPoints(numBins, min, max);
+    }
+    final double[] histogram = sketch.getPMF(splitPoints);
     for (int i = 0; i < histogram.length; i++) {
       histogram[i] *= sketch.getN(); // scale fractions to counts
     }
diff --git 
a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/DoublesSketchToHistogramPostAggregator.java
 
b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/DoublesSketchToHistogramPostAggregator.java
index 49d4f84cd4f..7598561f273 100644
--- 
a/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/DoublesSketchToHistogramPostAggregator.java
+++ 
b/extensions-core/datasketches/src/main/java/org/apache/druid/query/aggregation/datasketches/quantiles/DoublesSketchToHistogramPostAggregator.java
@@ -67,7 +67,7 @@ public class DoublesSketchToHistogramPostAggregator 
implements PostAggregator
   public Object compute(final Map<String, Object> combinedAggregators)
   {
     final DoublesSketch sketch = (DoublesSketch) 
field.compute(combinedAggregators);
-    final int numBins = splitPoints != null ? splitPoints.length + 1 :
+    final int numBins = this.splitPoints != null ? this.splitPoints.length + 1 
:
         (this.numBins != null ? this.numBins.intValue() : DEFAULT_NUM_BINS);
     if (numBins < 2) {
       throw new IAE("at least 2 bins expected");
@@ -77,8 +77,23 @@ public class DoublesSketchToHistogramPostAggregator 
implements PostAggregator
       Arrays.fill(histogram, Double.NaN);
       return histogram;
     }
-    final double[] histogram = sketch.getPMF(splitPoints != null ? splitPoints 
:
-      equallySpacedPoints(numBins, sketch.getMinItem(), sketch.getMaxItem()));
+    final double[] splitPoints;
+    if (this.splitPoints != null) {
+      splitPoints = this.splitPoints;
+    } else {
+      final double min = sketch.getMinItem();
+      final double max = sketch.getMaxItem();
+      if (min == max) {
+        // if min is equal to max, we can't create an array of equally spaced 
points.
+        // all values would go into the first bucket anyway, and the remaining
+        // buckets are left as zero.
+        final double[] histogram = new double[numBins];
+        histogram[0] = sketch.getN();
+        return histogram;
+      }
+      splitPoints = equallySpacedPoints(numBins, min, max);
+    }
+    final double[] histogram = sketch.getPMF(splitPoints);
     for (int i = 0; i < histogram.length; i++) {
       histogram[i] *= sketch.getN(); // scale fractions to counts
     }
diff --git 
a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/kll/KllDoublesSketchToHistogramPostAggregatorTest.java
 
b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/kll/KllDoublesSketchToHistogramPostAggregatorTest.java
index e3f55b4fb79..bfb125b42b5 100644
--- 
a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/kll/KllDoublesSketchToHistogramPostAggregatorTest.java
+++ 
b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/kll/KllDoublesSketchToHistogramPostAggregatorTest.java
@@ -157,6 +157,36 @@ public class KllDoublesSketchToHistogramPostAggregatorTest
     Assert.assertEquals(3.0, histogram[1], 0);
   }
 
+  @Test
+  public void splitPointsEqualValues()
+  {
+    final double[] values = new double[] {6, 6, 6, 6, 6, 6};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new KllDoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllDoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        new double[] {3.5}, // all values are in the second bin
+        null
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(0.0, histogram[0], 0);
+    Assert.assertEquals(6.0, histogram[1], 0);
+  }
+
   @Test
   public void numBins()
   {
@@ -187,6 +217,128 @@ public class KllDoublesSketchToHistogramPostAggregatorTest
     Assert.assertEquals(3.0, histogram[1], 0);
   }
 
+  @Test
+  public void oneValueTwoBins()
+  {
+    final double[] values = new double[] {1};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new KllDoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllDoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        2 // two bins, the second is empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(1.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+  }
+
+  @Test
+  public void oneValueThreeBins()
+  {
+    final double[] values = new double[] {1};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new KllDoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllDoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        3 // three bins, the second and third are empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(3, histogram.length);
+    Assert.assertEquals(1.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+    Assert.assertEquals(0.0, histogram[2], 0);
+  }
+
+  @Test
+  public void equalValuesTwoBins()
+  {
+    final double[] values = new double[] {1, 1, 1};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new KllDoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllDoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        2 // two bins, the second is empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(3.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+  }
+
+  @Test
+  public void equalValuesThreeBins()
+  {
+    final double[] values = new double[] {1, 1, 1};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new KllDoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllDoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        3 // three bins, the second and third are empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(3, histogram.length);
+    Assert.assertEquals(3.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+    Assert.assertEquals(0.0, histogram[2], 0);
+  }
+
   @Test
   public void testResultArraySignature()
   {
diff --git 
a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregatorTest.java
 
b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregatorTest.java
index 5b970816f3f..bf5862bec88 100644
--- 
a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregatorTest.java
+++ 
b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/kll/KllFloatsSketchToHistogramPostAggregatorTest.java
@@ -157,6 +157,36 @@ public class KllFloatsSketchToHistogramPostAggregatorTest
     Assert.assertEquals(3.0, histogram[1], 0);
   }
 
+  @Test
+  public void splitPointsEqualValues()
+  {
+    final float[] values = new float[] {6, 6, 6, 6, 6, 6};
+    final TestFloatColumnSelector selector = new 
TestFloatColumnSelector(values);
+
+    final Aggregator agg = new KllFloatsSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllFloatsSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        new float[] {3.5f}, // all values are in the second bin
+        null
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(0.0, histogram[0], 0);
+    Assert.assertEquals(6.0, histogram[1], 0);
+  }
+
   @Test
   public void numBins()
   {
@@ -187,6 +217,128 @@ public class KllFloatsSketchToHistogramPostAggregatorTest
     Assert.assertEquals(3.0, histogram[1], 0);
   }
 
+  @Test
+  public void oneValueTwoBins()
+  {
+    final float[] values = new float[] {1};
+    final TestFloatColumnSelector selector = new 
TestFloatColumnSelector(values);
+
+    final Aggregator agg = new KllFloatsSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllFloatsSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        2 // two bins, the second is empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(1.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+  }
+
+  @Test
+  public void oneValueThreeBins()
+  {
+    final float[] values = new float[] {1};
+    final TestFloatColumnSelector selector = new 
TestFloatColumnSelector(values);
+
+    final Aggregator agg = new KllFloatsSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllFloatsSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        3 // three bins, the second and third are empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(3, histogram.length);
+    Assert.assertEquals(1.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+    Assert.assertEquals(0.0, histogram[2], 0);
+  }
+
+  @Test
+  public void equalValuesTwoBins()
+  {
+    final float[] values = new float[] {1, 1, 1};
+    final TestFloatColumnSelector selector = new 
TestFloatColumnSelector(values);
+
+    final Aggregator agg = new KllFloatsSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllFloatsSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        2 // two bins, the second is empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(3.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+  }
+
+  @Test
+  public void equalValuesThreeBins()
+  {
+    final float[] values = new float[] {1, 1, 1};
+    final TestFloatColumnSelector selector = new 
TestFloatColumnSelector(values);
+
+    final Aggregator agg = new KllFloatsSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new 
KllFloatsSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        3 // three bins, the second and third are empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(3, histogram.length);
+    Assert.assertEquals(3.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+    Assert.assertEquals(0.0, histogram[2], 0);
+  }
+
   @Test
   public void testResultArraySignature()
   {
diff --git 
a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/quantiles/DoublesSketchToHistogramPostAggregatorTest.java
 
b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/quantiles/DoublesSketchToHistogramPostAggregatorTest.java
index 2bfc0e53539..94bc7fa1b9d 100644
--- 
a/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/quantiles/DoublesSketchToHistogramPostAggregatorTest.java
+++ 
b/extensions-core/datasketches/src/test/java/org/apache/druid/query/aggregation/datasketches/quantiles/DoublesSketchToHistogramPostAggregatorTest.java
@@ -157,6 +157,36 @@ public class DoublesSketchToHistogramPostAggregatorTest
     Assert.assertEquals(3.0, histogram[1], 0);
   }
 
+  @Test
+  public void splitPointsEqualValues()
+  {
+    final double[] values = new double[] {6, 6, 6, 6, 6, 6};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new DoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new DoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        new double[] {3.5}, // all values are in the second bin
+        null
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(0.0, histogram[0], 0);
+    Assert.assertEquals(6.0, histogram[1], 0);
+  }
+
   @Test
   public void numBins()
   {
@@ -187,6 +217,128 @@ public class DoublesSketchToHistogramPostAggregatorTest
     Assert.assertEquals(3.0, histogram[1], 0);
   }
 
+  @Test
+  public void oneValueTwoBins()
+  {
+    final double[] values = new double[] {1};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new DoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new DoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        2 // two bins, the second is empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(1.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+  }
+
+  @Test
+  public void oneValueThreeBins()
+  {
+    final double[] values = new double[] {1};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new DoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new DoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        3 // three bins, the second and third are empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(3, histogram.length);
+    Assert.assertEquals(1.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+    Assert.assertEquals(0.0, histogram[2], 0);
+  }
+
+  @Test
+  public void equalValuesTwoBins()
+  {
+    final double[] values = new double[] {1, 1, 1};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new DoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new DoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        2 // two bins, the second is empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(2, histogram.length);
+    Assert.assertEquals(3.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+  }
+
+  @Test
+  public void equalValuesThreeBins()
+  {
+    final double[] values = new double[] {1, 1, 1};
+    final TestDoubleColumnSelectorImpl selector = new 
TestDoubleColumnSelectorImpl(values);
+
+    final Aggregator agg = new DoublesSketchBuildAggregator(selector, 8);
+    //noinspection ForLoopReplaceableByForEach
+    for (int i = 0; i < values.length; i++) {
+      agg.aggregate();
+      selector.increment();
+    }
+
+    final Map<String, Object> fields = new HashMap<>();
+    fields.put("sketch", agg.get());
+
+    final PostAggregator postAgg = new DoublesSketchToHistogramPostAggregator(
+        "histogram",
+        new FieldAccessPostAggregator("field", "sketch"),
+        null,
+        3 // three bins, the second and third are empty
+    );
+
+    final double[] histogram = (double[]) postAgg.compute(fields);
+    Assert.assertNotNull(histogram);
+    Assert.assertEquals(3, histogram.length);
+    Assert.assertEquals(3.0, histogram[0], 0);
+    Assert.assertEquals(0.0, histogram[1], 0);
+    Assert.assertEquals(0.0, histogram[2], 0);
+  }
+
   @Test
   public void testResultArraySignature()
   {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to