Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/87554.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 87554
summary: "[TSDB] Add Kahan support to downsampling summation"
area: "Rollup"
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public CompensatedSum(double value, double delta) {
this.delta = delta;
}

public CompensatedSum() {
this(0, 0);
}

/**
* The value of the sum.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.search.aggregations.metrics.CompensatedSum;

import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -145,26 +146,25 @@ void reset() {
* Metric implementation that computes the sum of all values of a field
*/
static class Sum extends Metric {
private double sum = 0;
private final CompensatedSum kahanSummation = new CompensatedSum();

Sum() {
super("sum");
}

@Override
void collect(double value) {
// TODO: switch to Kahan summation ?
this.sum += value;
kahanSummation.add(value);
}

@Override
Number get() {
return sum;
return kahanSummation.value();
}

@Override
void reset() {
sum = 0;
kahanSummation.reset(0, 0);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,47 @@ public void testSumCountMetric() {
assertEquals(0d, metric.get());
}

/**
* Testing summation accuracy.
* Tests stolen from SumAggregatorTests#testSummationAccuracy
*/
public void testSummationAccuracy() {
MetricFieldProducer.Metric metric = new MetricFieldProducer.Sum();
// Summing up a normal array and expect an accurate value
double[] values = new double[] { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7 };
for (int i = 0; i < values.length; i++) {
metric.collect(values[i]);
}
assertEquals(metric.get().doubleValue(), 15.3, Double.MIN_NORMAL);

// Summing up an array which contains NaN and infinities and expect a result same as naive summation
metric.reset();
int n = randomIntBetween(5, 10);
double sum = 0;
for (int i = 0; i < n; i++) {
double d = frequently()
? randomFrom(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)
: randomDoubleBetween(Double.MIN_VALUE, Double.MAX_VALUE, true);
sum += d;
metric.collect(d);
}
assertEquals(metric.get().doubleValue(), sum, 1e-10);

// Summing up some big double values and expect infinity result
metric.reset();
n = randomIntBetween(5, 10);
for (int i = 0; i < n; i++) {
metric.collect(Double.MAX_VALUE);
}
assertEquals(metric.get().doubleValue(), Double.POSITIVE_INFINITY, 0d);

metric.reset();
for (int i = 0; i < n; i++) {
metric.collect(-Double.MAX_VALUE);
}
assertEquals(metric.get().doubleValue(), Double.NEGATIVE_INFINITY, 0d);
}

public void testValueCountMetric() {
MetricFieldProducer.Metric metric = new MetricFieldProducer.ValueCount();
assertEquals(0L, metric.get());
Expand Down