Skip to content

Commit d060d73

Browse files
authored
Support time_zone on composite's date_histogram (#51172)
We've been parsing the `time_zone` parameter on `date_hitogram` for a while but it hasn't *done* anything. This wires it up. Closes #45199 Inspired by #45200
1 parent 5c083ee commit d060d73

File tree

4 files changed

+142
-57
lines changed

4 files changed

+142
-57
lines changed

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

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,3 +782,71 @@ setup:
782782
- length: { aggregations.test.buckets: 1 }
783783
- match: { aggregations.test.buckets.0.key.f: "192.168.0.1" }
784784
- match: { aggregations.test.buckets.0.doc_count: 1 }
785+
786+
---
787+
"date_histogram with time_zone":
788+
- skip:
789+
version: " - 7.99.99"
790+
reason: This will fail against 7.whatever until we backport the fix
791+
- do:
792+
index:
793+
index: test
794+
id: 7
795+
body: { "date": "2017-10-22T01:00:00" }
796+
refresh: true
797+
- do:
798+
search:
799+
index: test
800+
body:
801+
aggregations:
802+
test:
803+
composite:
804+
sources: [
805+
{
806+
"date": {
807+
"date_histogram": {
808+
"field": "date",
809+
"calendar_interval": "1d",
810+
"time_zone": "-02:00",
811+
"format": "iso8601" # Format makes the comparisons a little more obvious
812+
}
813+
}
814+
}
815+
]
816+
817+
- match: { hits.total.value: 7 }
818+
- match: { hits.total.relation: eq }
819+
- length: { aggregations.test.buckets: 2 }
820+
- match: { aggregations.test.buckets.0.key.date: "2017-10-20T00:00:00.000-02:00" }
821+
- match: { aggregations.test.buckets.0.doc_count: 1 }
822+
- match: { aggregations.test.buckets.1.key.date: "2017-10-21T00:00:00.000-02:00" }
823+
- match: { aggregations.test.buckets.1.doc_count: 2 }
824+
825+
- do:
826+
search:
827+
index: test
828+
body:
829+
aggregations:
830+
test:
831+
composite:
832+
after: {
833+
date: "2017-10-20"
834+
}
835+
sources: [
836+
{
837+
"date": {
838+
"date_histogram": {
839+
"field": "date",
840+
"calendar_interval": "1d",
841+
"time_zone": "-02:00",
842+
"format": "iso8601" # Format makes the comparisons a little more obvious
843+
}
844+
}
845+
}
846+
]
847+
848+
- match: { hits.total.value: 7 }
849+
- match: { hits.total.relation: eq }
850+
- length: { aggregations.test.buckets: 1 }
851+
- match: { aggregations.test.buckets.0.key.date: "2017-10-21T00:00:00.000-02:00" }
852+
- match: { aggregations.test.buckets.0.doc_count: 2 }

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@
2727
import org.elasticsearch.index.query.QueryShardContext;
2828
import org.elasticsearch.script.Script;
2929
import org.elasticsearch.search.aggregations.support.ValueType;
30-
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
3130
import org.elasticsearch.search.aggregations.support.ValuesSource;
31+
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
3232
import org.elasticsearch.search.sort.SortOrder;
3333

3434
import java.io.IOException;
35+
import java.time.ZoneId;
3536
import java.util.Objects;
3637

3738
/**
@@ -276,7 +277,15 @@ protected abstract CompositeValuesSourceConfig innerBuild(QueryShardContext quer
276277

277278
public final CompositeValuesSourceConfig build(QueryShardContext queryShardContext) throws IOException {
278279
ValuesSourceConfig<?> config = ValuesSourceConfig.resolve(queryShardContext,
279-
valueType, field, script, null,null, format);
280+
valueType, field, script, null, timeZone(), format);
280281
return innerBuild(queryShardContext, config);
281282
}
283+
284+
/**
285+
* The time zone for this value source. Default implementation returns {@code null}
286+
* because most value source types don't support time zone.
287+
*/
288+
protected ZoneId timeZone() {
289+
return null;
290+
}
282291
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ public DateHistogramValuesSourceBuilder timeZone(ZoneId timeZone) {
228228
/**
229229
* Gets the time zone to use for this aggregation
230230
*/
231+
@Override
231232
public ZoneId timeZone() {
232233
return timeZone;
233234
}

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

Lines changed: 62 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181

8282
import java.io.IOException;
8383
import java.net.InetAddress;
84-
import java.time.ZoneOffset;
84+
import java.time.ZoneId;
8585
import java.util.ArrayList;
8686
import java.util.Arrays;
8787
import java.util.Collections;
@@ -1088,6 +1088,67 @@ public void testWithDateHistogram() throws IOException {
10881088
assertEquals(1L, result.getBuckets().get(2).getDocCount());
10891089
}
10901090
);
1091+
1092+
/*
1093+
* Tests the -04:00 time zone. This functions identically to
1094+
* the four hour offset.
1095+
*/
1096+
testSearchCase(Arrays.asList(new MatchAllDocsQuery(), new DocValuesFieldExistsQuery("date"),
1097+
LongPoint.newRangeQuery(
1098+
"date",
1099+
asLong("2016-09-20T09:00:34"),
1100+
asLong("2017-10-20T06:09:24")
1101+
)), dataset,
1102+
() -> {
1103+
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
1104+
.field("date")
1105+
.calendarInterval(DateHistogramInterval.days(1))
1106+
.timeZone(ZoneId.of("-04:00"));
1107+
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
1108+
.aggregateAfter(createAfterKey("date", 1474329600000L));
1109+
1110+
}, (result) -> {
1111+
assertEquals(3, result.getBuckets().size());
1112+
assertEquals("{date=1508472000000}", result.afterKey().toString());
1113+
assertEquals("{date=1474344000000}", result.getBuckets().get(0).getKeyAsString());
1114+
assertEquals(2L, result.getBuckets().get(0).getDocCount());
1115+
assertEquals("{date=1508385600000}", result.getBuckets().get(1).getKeyAsString());
1116+
assertEquals(2L, result.getBuckets().get(1).getDocCount());
1117+
assertEquals("{date=1508472000000}", result.getBuckets().get(2).getKeyAsString());
1118+
assertEquals(1L, result.getBuckets().get(2).getDocCount());
1119+
}
1120+
);
1121+
1122+
/*
1123+
* Tests a four hour offset with a time zone, demonstrating
1124+
* why we support both things.
1125+
*/
1126+
testSearchCase(Arrays.asList(new MatchAllDocsQuery(), new DocValuesFieldExistsQuery("date"),
1127+
LongPoint.newRangeQuery(
1128+
"date",
1129+
asLong("2016-09-20T09:00:34"),
1130+
asLong("2017-10-20T06:09:24")
1131+
)), dataset,
1132+
() -> {
1133+
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
1134+
.field("date")
1135+
.calendarInterval(DateHistogramInterval.days(1))
1136+
.offset(TimeUnit.HOURS.toMillis(4))
1137+
.timeZone(ZoneId.of("America/Los_Angeles"));
1138+
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
1139+
.aggregateAfter(createAfterKey("date", 1474329600000L));
1140+
1141+
}, (result) -> {
1142+
assertEquals(3, result.getBuckets().size());
1143+
assertEquals("{date=1508410800000}", result.afterKey().toString());
1144+
assertEquals("{date=1474369200000}", result.getBuckets().get(0).getKeyAsString());
1145+
assertEquals(1L, result.getBuckets().get(0).getDocCount());
1146+
assertEquals("{date=1508324400000}", result.getBuckets().get(1).getKeyAsString());
1147+
assertEquals(1L, result.getBuckets().get(1).getDocCount());
1148+
assertEquals("{date=1508410800000}", result.getBuckets().get(2).getKeyAsString());
1149+
assertEquals(2L, result.getBuckets().get(2).getDocCount());
1150+
}
1151+
);
10911152
}
10921153

10931154
public void testWithDateTerms() throws IOException {
@@ -1219,60 +1280,6 @@ public void testThatDateHistogramFailsFormatAfter() throws IOException {
12191280
assertWarnings("[interval] on [date_histogram] is deprecated, use [fixed_interval] or [calendar_interval] in the future.");
12201281
}
12211282

1222-
public void testWithDateHistogramAndTimeZone() throws IOException {
1223-
final List<Map<String, List<Object>>> dataset = new ArrayList<>();
1224-
dataset.addAll(
1225-
Arrays.asList(
1226-
createDocument("date", asLong("2017-10-20T03:08:45")),
1227-
createDocument("date", asLong("2016-09-20T09:00:34")),
1228-
createDocument("date", asLong("2016-09-20T11:34:00")),
1229-
createDocument("date", asLong("2017-10-20T06:09:24")),
1230-
createDocument("date", asLong("2017-10-19T06:09:24")),
1231-
createDocument("long", 4L)
1232-
)
1233-
);
1234-
testSearchCase(Arrays.asList(new MatchAllDocsQuery(), new DocValuesFieldExistsQuery("date")), dataset,
1235-
() -> {
1236-
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
1237-
.field("date")
1238-
.dateHistogramInterval(DateHistogramInterval.days(1))
1239-
.timeZone(ZoneOffset.ofHours(1));
1240-
return new CompositeAggregationBuilder("name", Collections.singletonList(histo));
1241-
},
1242-
(result) -> {
1243-
assertEquals(3, result.getBuckets().size());
1244-
assertEquals("{date=1508454000000}", result.afterKey().toString());
1245-
assertEquals("{date=1474326000000}", result.getBuckets().get(0).getKeyAsString());
1246-
assertEquals(2L, result.getBuckets().get(0).getDocCount());
1247-
assertEquals("{date=1508367600000}", result.getBuckets().get(1).getKeyAsString());
1248-
assertEquals(1L, result.getBuckets().get(1).getDocCount());
1249-
assertEquals("{date=1508454000000}", result.getBuckets().get(2).getKeyAsString());
1250-
assertEquals(2L, result.getBuckets().get(2).getDocCount());
1251-
}
1252-
);
1253-
1254-
testSearchCase(Arrays.asList(new MatchAllDocsQuery(), new DocValuesFieldExistsQuery("date")), dataset,
1255-
() -> {
1256-
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
1257-
.field("date")
1258-
.dateHistogramInterval(DateHistogramInterval.days(1))
1259-
.timeZone(ZoneOffset.ofHours(1));
1260-
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
1261-
.aggregateAfter(createAfterKey("date", 1474326000000L));
1262-
1263-
}, (result) -> {
1264-
assertEquals(2, result.getBuckets().size());
1265-
assertEquals("{date=1508454000000}", result.afterKey().toString());
1266-
assertEquals("{date=1508367600000}", result.getBuckets().get(0).getKeyAsString());
1267-
assertEquals(1L, result.getBuckets().get(0).getDocCount());
1268-
assertEquals("{date=1508454000000}", result.getBuckets().get(1).getKeyAsString());
1269-
assertEquals(2L, result.getBuckets().get(1).getDocCount());
1270-
}
1271-
);
1272-
1273-
assertWarnings("[interval] on [date_histogram] is deprecated, use [fixed_interval] or [calendar_interval] in the future.");
1274-
}
1275-
12761283
public void testWithDateHistogramAndKeyword() throws IOException {
12771284
final List<Map<String, List<Object>>> dataset = new ArrayList<>();
12781285
dataset.addAll(

0 commit comments

Comments
 (0)