Skip to content

Commit 2051507

Browse files
committed
Handle after key with formatted date histogram + address reviews
1 parent 360a28a commit 2051507

File tree

6 files changed

+82
-16
lines changed

6 files changed

+82
-16
lines changed

rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ setup:
241241
"Composite aggregation with format":
242242
- skip:
243243
version: " - 6.99.99"
244-
reason: this uses a new option (format) added 7.0.0
244+
reason: this uses a new option (format) added in 7.0.0
245245

246246
- do:
247247
search:

server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ final class CompositeValuesComparator {
5656
if (vs.isFloatingPoint()) {
5757
arrays[i] = CompositeValuesSource.wrapDouble(vs, size, reverseMul);
5858
} else {
59-
arrays[i] = CompositeValuesSource.wrapLong(vs, size, reverseMul);
59+
arrays[i] = CompositeValuesSource.wrapLong(vs, sources[i].format(), size, reverseMul);
6060
}
6161
}
6262
}

server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
import org.apache.lucene.index.SortedSetDocValues;
2424
import org.apache.lucene.search.LeafCollector;
2525
import org.apache.lucene.util.BytesRef;
26+
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
2627
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
2728
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
29+
import org.elasticsearch.search.DocValueFormat;
2830
import org.elasticsearch.search.aggregations.support.ValuesSource;
2931
import org.elasticsearch.search.sort.SortOrder;
3032

@@ -96,8 +98,9 @@ interface Collector {
9698
/**
9799
* Creates a {@link CompositeValuesSource} that generates long values.
98100
*/
99-
static CompositeValuesSource<ValuesSource.Numeric, Long> wrapLong(ValuesSource.Numeric vs, int size, int reverseMul) {
100-
return new LongValuesSource(vs, size, reverseMul);
101+
static CompositeValuesSource<ValuesSource.Numeric, Long> wrapLong(ValuesSource.Numeric vs, DocValueFormat format,
102+
int size, int reverseMul) {
103+
return new LongValuesSource(vs, format, size, reverseMul);
101104
}
102105

103106
/**
@@ -273,9 +276,12 @@ Collector getLeafCollector(LeafReaderContext context, Collector next) throws IOE
273276
*/
274277
private static class LongValuesSource extends CompositeValuesSource<ValuesSource.Numeric, Long> {
275278
private final long[] values;
279+
// handles "format" for date histogram source
280+
private final DocValueFormat format;
276281

277-
LongValuesSource(ValuesSource.Numeric vs, int size, int reverseMul) {
282+
LongValuesSource(ValuesSource.Numeric vs, DocValueFormat format, int size, int reverseMul) {
278283
super(vs, size, reverseMul);
284+
this.format = format;
279285
this.values = new long[size];
280286
}
281287

@@ -304,7 +310,11 @@ void setTop(Comparable<?> value) {
304310
if (value instanceof Number) {
305311
topValue = ((Number) value).longValue();
306312
} else {
307-
topValue = Long.parseLong(value.toString());
313+
// for date histogram source with "format", the after value is formatted
314+
// as a string so we need to retrieve the original value in milliseconds.
315+
topValue = format.parseLong(value.toString(), false, () -> {
316+
throw new IllegalArgumentException("now() is not supported in [after] key");
317+
});
308318
}
309319
}
310320

server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/InternalComposite.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.util.AbstractSet;
3838
import java.util.ArrayList;
3939
import java.util.Arrays;
40+
import java.util.Collections;
4041
import java.util.Iterator;
4142
import java.util.List;
4243
import java.util.Map;
@@ -68,11 +69,11 @@ public InternalComposite(StreamInput in) throws IOException {
6869
super(in);
6970
this.size = in.readVInt();
7071
this.sourceNames = in.readList(StreamInput::readString);
71-
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
72-
this.formats = in.readNamedWriteableList(DocValueFormat.class);
73-
} else {
74-
this.formats = new ArrayList<>(sourceNames.size());
75-
for (int i = 0; i < sourceNames.size(); i++) {
72+
this.formats = new ArrayList<>(sourceNames.size());
73+
for (int i = 0; i < sourceNames.size(); i++) {
74+
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
75+
formats.add(in.readNamedWriteable(DocValueFormat.class));
76+
} else {
7677
formats.add(DocValueFormat.RAW);
7778
}
7879
}
@@ -85,7 +86,9 @@ protected void doWriteTo(StreamOutput out) throws IOException {
8586
out.writeVInt(size);
8687
out.writeStringList(sourceNames);
8788
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
88-
out.writeNamedWriteableList(formats);
89+
for (DocValueFormat format : formats) {
90+
out.writeNamedWriteable(format);
91+
}
8992
}
9093
out.writeIntArray(reverseMuls);
9194
out.writeList(buckets);

server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregatorTests.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.apache.lucene.util.LuceneTestCase;
4040
import org.apache.lucene.util.NumericUtils;
4141
import org.apache.lucene.util.TestUtil;
42+
import org.elasticsearch.ElasticsearchParseException;
4243
import org.elasticsearch.common.settings.Settings;
4344
import org.elasticsearch.index.Index;
4445
import org.elasticsearch.index.IndexSettings;
@@ -68,6 +69,9 @@
6869
import java.util.function.Consumer;
6970
import java.util.function.Supplier;
7071

72+
import static org.hamcrest.Matchers.containsString;
73+
import static org.hamcrest.Matchers.instanceOf;
74+
7175
public class CompositeAggregatorTests extends AggregatorTestCase {
7276
private static MappedFieldType[] FIELD_TYPES;
7377

@@ -800,7 +804,7 @@ public void testWithDateHistogramAndFormat() throws IOException {
800804
.dateHistogramInterval(DateHistogramInterval.days(1))
801805
.format("yyyy-MM-dd");
802806
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
803-
.aggregateAfter(createAfterKey("date", 1474329600000L));
807+
.aggregateAfter(createAfterKey("date", "2016-09-20"));
804808

805809
}, (result) -> {
806810
assertEquals(2, result.getBuckets().size());
@@ -812,6 +816,38 @@ public void testWithDateHistogramAndFormat() throws IOException {
812816
);
813817
}
814818

819+
public void testThatDateHistogramFailsFormatAfter() throws IOException {
820+
ElasticsearchParseException exc = expectThrows(ElasticsearchParseException.class,
821+
() -> testSearchCase(new MatchAllDocsQuery(), null, Collections.emptyList(),
822+
() -> {
823+
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
824+
.field("date")
825+
.dateHistogramInterval(DateHistogramInterval.days(1))
826+
.format("yyyy-MM-dd");
827+
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
828+
.aggregateAfter(createAfterKey("date", "now"));
829+
},
830+
(result) -> {}
831+
));
832+
assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class));
833+
assertThat(exc.getCause().getMessage(), containsString("now() is not supported in [after] key"));
834+
835+
exc = expectThrows(ElasticsearchParseException.class,
836+
() -> testSearchCase(new MatchAllDocsQuery(), null, Collections.emptyList(),
837+
() -> {
838+
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
839+
.field("date")
840+
.dateHistogramInterval(DateHistogramInterval.days(1))
841+
.format("yyyy-MM-dd");
842+
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
843+
.aggregateAfter(createAfterKey("date", "1474329600000"));
844+
},
845+
(result) -> {}
846+
));
847+
assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class));
848+
assertThat(exc.getCause().getMessage(), containsString("Parse failure"));
849+
}
850+
815851
public void testWithDateHistogramAndTimeZone() throws IOException {
816852
final List<Map<String, List<Object>>> dataset = new ArrayList<>();
817853
dataset.addAll(

server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121

2222
import org.apache.lucene.util.BytesRef;
2323
import org.elasticsearch.common.io.stream.Writeable;
24+
import org.elasticsearch.common.joda.Joda;
2425
import org.elasticsearch.common.util.BigArrays;
2526
import org.elasticsearch.search.DocValueFormat;
2627
import org.elasticsearch.search.aggregations.InternalAggregation;
2728
import org.elasticsearch.search.aggregations.InternalAggregations;
2829
import org.elasticsearch.search.aggregations.ParsedAggregation;
2930
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
3031
import org.elasticsearch.test.InternalMultiBucketAggregationTestCase;
32+
import org.joda.time.DateTimeZone;
3133
import org.junit.After;
3234

3335
import java.io.IOException;
@@ -52,6 +54,20 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa
5254
private int[] types;
5355
private int size;
5456

57+
private static DocValueFormat randomDocValueFormat(boolean isLong) {
58+
if (isLong) {
59+
// we use specific format only for date histogram on a long/date field
60+
if (randomBoolean()) {
61+
return new DocValueFormat.DateTime(Joda.forPattern("epoch_second"), DateTimeZone.forOffsetHours(1));
62+
} else {
63+
return DocValueFormat.RAW;
64+
}
65+
} else {
66+
// and the raw format for the other types
67+
return DocValueFormat.RAW;
68+
}
69+
}
70+
5571
@Override
5672
public void setUp() throws Exception {
5773
super.setUp();
@@ -63,17 +79,18 @@ public void setUp() throws Exception {
6379
types = new int[numFields];
6480
for (int i = 0; i < numFields; i++) {
6581
sourceNames.add("field_" + i);
66-
formats.add(DocValueFormat.RAW);
6782
reverseMuls[i] = randomBoolean() ? 1 : -1;
68-
types[i] = randomIntBetween(0, 2);
83+
int type = randomIntBetween(0, 2);
84+
types[i] = type;
85+
formats.add(randomDocValueFormat(type == 0));
6986
}
7087
}
7188

7289
@Override
7390
@After
7491
public void tearDown() throws Exception {
7592
super.tearDown();
76-
sourceNames= null;
93+
sourceNames = null;
7794
formats = null;
7895
reverseMuls = null;
7996
types = null;

0 commit comments

Comments
 (0)