Skip to content

Commit 11164b3

Browse files
authored
Add unit tests for ValueCountAggregator and InternalValueCount (#22741)
Adds unit tests for the value count aggregator. Relates #22278
1 parent da87401 commit 11164b3

File tree

3 files changed

+215
-0
lines changed

3 files changed

+215
-0
lines changed

core/src/main/java/org/elasticsearch/search/aggregations/metrics/valuecount/InternalValueCount.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.io.IOException;
2929
import java.util.List;
3030
import java.util.Map;
31+
import java.util.Objects;
3132

3233
/**
3334
* An internal implementation of {@link ValueCount}.
@@ -88,4 +89,15 @@ public XContentBuilder doXContentBody(XContentBuilder builder, Params params) th
8889
public String toString() {
8990
return "count[" + value + "]";
9091
}
92+
93+
@Override
94+
protected int doHashCode() {
95+
return Objects.hash(value);
96+
}
97+
98+
@Override
99+
protected boolean doEquals(Object obj) {
100+
InternalValueCount that = (InternalValueCount) obj;
101+
return Objects.equals(this.value, that.value);
102+
}
91103
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.search.aggregations.metrics.valuecount;
21+
22+
import org.elasticsearch.common.io.stream.Writeable;
23+
import org.elasticsearch.search.aggregations.InternalAggregationTestCase;
24+
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
25+
26+
import java.util.List;
27+
import java.util.Map;
28+
29+
public class InternalValueCountTests extends InternalAggregationTestCase<InternalValueCount> {
30+
31+
@Override
32+
protected InternalValueCount createTestInstance(String name,
33+
List<PipelineAggregator> pipelineAggregators,
34+
Map<String, Object> metaData) {
35+
return new InternalValueCount(name, randomIntBetween(0, 100), pipelineAggregators, metaData);
36+
}
37+
38+
@Override
39+
protected void assertReduced(InternalValueCount reduced, List<InternalValueCount> inputs) {
40+
assertEquals(inputs.stream().mapToDouble(InternalValueCount::value).sum(), reduced.getValue(), 0);
41+
}
42+
43+
@Override
44+
protected Writeable.Reader<InternalValueCount> instanceReader() {
45+
return InternalValueCount::new;
46+
}
47+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.search.aggregations.metrics.valuecount;
21+
22+
import org.apache.lucene.document.IntPoint;
23+
import org.apache.lucene.document.NumericDocValuesField;
24+
import org.apache.lucene.document.SortedDocValuesField;
25+
import org.apache.lucene.document.SortedNumericDocValuesField;
26+
import org.apache.lucene.index.DirectoryReader;
27+
import org.apache.lucene.index.IndexReader;
28+
import org.apache.lucene.index.RandomIndexWriter;
29+
import org.apache.lucene.search.FieldValueQuery;
30+
import org.apache.lucene.search.IndexSearcher;
31+
import org.apache.lucene.search.MatchAllDocsQuery;
32+
import org.apache.lucene.search.Query;
33+
import org.apache.lucene.store.Directory;
34+
import org.apache.lucene.util.BytesRef;
35+
import org.elasticsearch.common.CheckedConsumer;
36+
import org.elasticsearch.index.mapper.BooleanFieldMapper;
37+
import org.elasticsearch.index.mapper.DateFieldMapper;
38+
import org.elasticsearch.index.mapper.IpFieldMapper;
39+
import org.elasticsearch.index.mapper.KeywordFieldMapper;
40+
import org.elasticsearch.index.mapper.LatLonPointFieldMapper;
41+
import org.elasticsearch.index.mapper.MappedFieldType;
42+
import org.elasticsearch.index.mapper.NumberFieldMapper;
43+
import org.elasticsearch.search.aggregations.AggregatorTestCase;
44+
import org.elasticsearch.search.aggregations.support.ValueType;
45+
46+
import java.io.IOException;
47+
import java.util.Arrays;
48+
import java.util.function.Consumer;
49+
50+
import static java.util.Collections.singleton;
51+
52+
public class ValueCountAggregatorTests extends AggregatorTestCase {
53+
54+
private static final String FIELD_NAME = "field";
55+
56+
public void testNoDocs() throws IOException {
57+
for (ValueType valueType : ValueType.values()) {
58+
testCase(new MatchAllDocsQuery(), valueType, iw -> {
59+
// Intentionally not writing any docs
60+
}, count -> assertEquals(0L, count.getValue()));
61+
}
62+
}
63+
64+
public void testNoMatchingField() throws IOException {
65+
testCase(new MatchAllDocsQuery(), ValueType.LONG, iw -> {
66+
iw.addDocument(singleton(new SortedNumericDocValuesField("wrong_number", 7)));
67+
iw.addDocument(singleton(new SortedNumericDocValuesField("wrong_number", 1)));
68+
}, count -> assertEquals(0L, count.getValue()));
69+
}
70+
71+
public void testSomeMatchesSortedNumericDocValues() throws IOException {
72+
testCase(new FieldValueQuery(FIELD_NAME), ValueType.NUMERIC, iw -> {
73+
iw.addDocument(singleton(new SortedNumericDocValuesField("wrong_number", 7)));
74+
iw.addDocument(singleton(new SortedNumericDocValuesField(FIELD_NAME, 7)));
75+
iw.addDocument(singleton(new SortedNumericDocValuesField(FIELD_NAME, 1)));
76+
}, count -> assertEquals(2L, count.getValue()));
77+
}
78+
79+
public void testSomeMatchesNumericDocValues() throws IOException {
80+
testCase(new FieldValueQuery(FIELD_NAME), ValueType.NUMBER, iw -> {
81+
iw.addDocument(singleton(new NumericDocValuesField(FIELD_NAME, 7)));
82+
iw.addDocument(singleton(new NumericDocValuesField(FIELD_NAME, 1)));
83+
}, count -> assertEquals(2L, count.getValue()));
84+
}
85+
86+
public void testQueryFiltering() throws IOException {
87+
testCase(IntPoint.newRangeQuery("level", 0, 5), ValueType.STRING, iw -> {
88+
iw.addDocument(Arrays.asList(new IntPoint("level", 0), new SortedDocValuesField(FIELD_NAME, new BytesRef("foo"))));
89+
iw.addDocument(Arrays.asList(new IntPoint("level", 1), new SortedDocValuesField(FIELD_NAME, new BytesRef("bar"))));
90+
iw.addDocument(Arrays.asList(new IntPoint("level", 3), new SortedDocValuesField(FIELD_NAME, new BytesRef("foo"))));
91+
iw.addDocument(Arrays.asList(new IntPoint("level", 5), new SortedDocValuesField(FIELD_NAME, new BytesRef("baz"))));
92+
iw.addDocument(Arrays.asList(new IntPoint("level", 7), new SortedDocValuesField(FIELD_NAME, new BytesRef("baz"))));
93+
}, count -> assertEquals(4L, count.getValue()));
94+
}
95+
96+
public void testQueryFiltersAll() throws IOException {
97+
testCase(IntPoint.newRangeQuery("level", -1, 0), ValueType.STRING, iw -> {
98+
iw.addDocument(Arrays.asList(new IntPoint("level", 3), new SortedDocValuesField(FIELD_NAME, new BytesRef("foo"))));
99+
iw.addDocument(Arrays.asList(new IntPoint("level", 5), new SortedDocValuesField(FIELD_NAME, new BytesRef("baz"))));
100+
}, count -> assertEquals(0L, count.getValue()));
101+
}
102+
103+
private void testCase(Query query,
104+
ValueType valueType,
105+
CheckedConsumer<RandomIndexWriter, IOException> indexer,
106+
Consumer<ValueCount> verify) throws IOException {
107+
108+
try (Directory directory = newDirectory()) {
109+
try (RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory)) {
110+
indexer.accept(indexWriter);
111+
}
112+
113+
try (IndexReader indexReader = DirectoryReader.open(directory)) {
114+
IndexSearcher indexSearcher = newSearcher(indexReader, true, true);
115+
116+
MappedFieldType fieldType = createMappedFieldType(valueType);
117+
fieldType.setName(FIELD_NAME);
118+
fieldType.setHasDocValues(true);
119+
120+
ValueCountAggregationBuilder aggregationBuilder = new ValueCountAggregationBuilder("_name", valueType);
121+
aggregationBuilder.field(FIELD_NAME);
122+
123+
try (ValueCountAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType)) {
124+
aggregator.preCollection();
125+
indexSearcher.search(query, aggregator);
126+
aggregator.postCollection();
127+
128+
verify.accept((ValueCount) aggregator.buildAggregation(0L));
129+
}
130+
}
131+
}
132+
}
133+
134+
private static MappedFieldType createMappedFieldType(ValueType valueType) {
135+
switch (valueType) {
136+
case BOOLEAN:
137+
return new BooleanFieldMapper.BooleanFieldType();
138+
case STRING:
139+
return new KeywordFieldMapper.KeywordFieldType();
140+
case DOUBLE:
141+
return new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.DOUBLE);
142+
case NUMBER:
143+
case NUMERIC:
144+
case LONG:
145+
return new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.LONG);
146+
case DATE:
147+
return new DateFieldMapper.Builder("_name").fieldType();
148+
case IP:
149+
return new IpFieldMapper.Builder("_name").fieldType();
150+
case GEOPOINT:
151+
return new LatLonPointFieldMapper.Builder("_name").fieldType();
152+
default:
153+
throw new IllegalArgumentException("Test does not support value type [" + valueType + "]");
154+
}
155+
}
156+
}

0 commit comments

Comments
 (0)