Skip to content

Commit 8eec8d9

Browse files
authored
Don't validate internal stats if they are empty (#113846) (#114136)
Fixes a validation step that might prevent creating empty aggregations iif the output format does not allows negative numbers.
1 parent 7d12398 commit 8eec8d9

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

docs/changelog/113846.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 113846
2+
summary: Don't validate internal stats if they are empty
3+
area: Aggregations
4+
type: bug
5+
issues:
6+
- 113811

server/src/main/java/org/elasticsearch/search/aggregations/metrics/InternalStats.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public InternalStats(
7676
}
7777

7878
private void verifyFormattingStats() {
79-
if (format != DocValueFormat.RAW) {
79+
if (format != DocValueFormat.RAW && count != 0) {
8080
verifyFormattingStat(Fields.MIN, format, min);
8181
verifyFormattingStat(Fields.MAX, format, max);
8282
verifyFormattingStat(Fields.AVG, format, getAvg());

server/src/test/java/org/elasticsearch/search/aggregations/metrics/ExtendedStatsAggregatorTests.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,20 @@
1414
import org.apache.lucene.document.SortedNumericDocValuesField;
1515
import org.apache.lucene.tests.index.RandomIndexWriter;
1616
import org.apache.lucene.util.NumericUtils;
17+
import org.elasticsearch.common.time.DateFormatter;
1718
import org.elasticsearch.core.CheckedConsumer;
19+
import org.elasticsearch.index.mapper.DateFieldMapper;
1820
import org.elasticsearch.index.mapper.MappedFieldType;
1921
import org.elasticsearch.index.mapper.NumberFieldMapper;
2022
import org.elasticsearch.search.aggregations.AggregatorTestCase;
2123
import org.elasticsearch.search.aggregations.support.AggregationInspectionHelper;
2224

2325
import java.io.IOException;
26+
import java.util.Map;
2427
import java.util.function.Consumer;
2528

2629
import static java.util.Collections.singleton;
30+
import static org.elasticsearch.search.aggregations.AggregationBuilders.stats;
2731

2832
public class ExtendedStatsAggregatorTests extends AggregatorTestCase {
2933
private static final double TOLERANCE = 1e-5;
@@ -49,6 +53,37 @@ public void testEmpty() throws IOException {
4953
});
5054
}
5155

56+
public void testEmptyDate() throws IOException {
57+
DateFormatter.forPattern("epoch_millis");
58+
final MappedFieldType ft = new DateFieldMapper.DateFieldType(
59+
"field",
60+
true,
61+
true,
62+
false,
63+
true,
64+
DateFormatter.forPattern("epoch_millis"),
65+
DateFieldMapper.Resolution.MILLISECONDS,
66+
null,
67+
null,
68+
Map.of()
69+
);
70+
testCase(ft, iw -> {}, stats -> {
71+
assertEquals(0d, stats.getCount(), 0);
72+
assertEquals(0d, stats.getSum(), 0);
73+
assertEquals(Float.NaN, stats.getAvg(), 0);
74+
assertEquals(Double.POSITIVE_INFINITY, stats.getMin(), 0);
75+
assertEquals(Double.NEGATIVE_INFINITY, stats.getMax(), 0);
76+
assertEquals(Double.NaN, stats.getVariance(), 0);
77+
assertEquals(Double.NaN, stats.getVariancePopulation(), 0);
78+
assertEquals(Double.NaN, stats.getVarianceSampling(), 0);
79+
assertEquals(Double.NaN, stats.getStdDeviation(), 0);
80+
assertEquals(Double.NaN, stats.getStdDeviationPopulation(), 0);
81+
assertEquals(Double.NaN, stats.getStdDeviationSampling(), 0);
82+
assertEquals(0d, stats.getSumOfSquares(), 0);
83+
assertFalse(AggregationInspectionHelper.hasValue(stats));
84+
});
85+
}
86+
5287
public void testRandomDoubles() throws IOException {
5388
MappedFieldType ft = new NumberFieldMapper.NumberFieldType("field", NumberFieldMapper.NumberType.DOUBLE);
5489
final ExtendedSimpleStatsAggregator expected = new ExtendedSimpleStatsAggregator();

server/src/test/java/org/elasticsearch/search/aggregations/metrics/StatsAggregatorTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
import org.apache.lucene.tests.index.RandomIndexWriter;
1919
import org.apache.lucene.util.NumericUtils;
2020
import org.elasticsearch.common.settings.Settings;
21+
import org.elasticsearch.common.time.DateFormatter;
2122
import org.elasticsearch.core.CheckedConsumer;
23+
import org.elasticsearch.index.mapper.DateFieldMapper;
2224
import org.elasticsearch.index.mapper.MappedFieldType;
2325
import org.elasticsearch.index.mapper.NumberFieldMapper;
2426
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
@@ -73,6 +75,30 @@ public void testEmpty() throws IOException {
7375
}, ft);
7476
}
7577

78+
public void testEmptyDate() throws IOException {
79+
DateFormatter.forPattern("epoch_millis");
80+
final MappedFieldType ft = new DateFieldMapper.DateFieldType(
81+
"field",
82+
true,
83+
true,
84+
false,
85+
true,
86+
DateFormatter.forPattern("epoch_millis"),
87+
DateFieldMapper.Resolution.MILLISECONDS,
88+
null,
89+
null,
90+
Map.of()
91+
);
92+
testCase(stats("_name").field(ft.name()), iw -> {}, stats -> {
93+
assertEquals(0d, stats.getCount(), 0);
94+
assertEquals(0d, stats.getSum(), 0);
95+
assertEquals(Float.NaN, stats.getAvg(), 0);
96+
assertEquals(Double.POSITIVE_INFINITY, stats.getMin(), 0);
97+
assertEquals(Double.NEGATIVE_INFINITY, stats.getMax(), 0);
98+
assertFalse(AggregationInspectionHelper.hasValue(stats));
99+
}, ft);
100+
}
101+
76102
public void testRandomDoubles() throws IOException {
77103
final MappedFieldType ft = new NumberFieldMapper.NumberFieldType("field", NumberType.DOUBLE);
78104
final SimpleStatsAggregator expected = new SimpleStatsAggregator();

0 commit comments

Comments
 (0)