Skip to content

Commit 1535223

Browse files
committed
Add support for scan queries.
1 parent 8d675e2 commit 1535223

File tree

4 files changed

+124
-2
lines changed

4 files changed

+124
-2
lines changed

src/main/java/com/simplaex/clients/druid/DruidClientImpl.java

+16
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import io.druid.query.metadata.SegmentMetadataQueryConfig;
2626
import io.druid.query.metadata.SegmentMetadataQueryQueryToolChest;
2727
import io.druid.query.metadata.metadata.SegmentMetadataQuery;
28+
import io.druid.query.scan.ScanQuery;
29+
import io.druid.query.scan.ScanQueryConfig;
30+
import io.druid.query.scan.ScanQueryQueryToolChest;
2831
import io.druid.query.search.SearchQueryQueryToolChest;
2932
import io.druid.query.search.SearchQuery;
3033
import io.druid.query.search.SearchQueryConfig;
@@ -273,6 +276,19 @@ public String getFormatString() {
273276
chestMap.put(TopNQuery.class, topNQueryQueryToolChest);
274277

275278

279+
// scan queries
280+
281+
final ScanQueryConfig scanQueryConfig = new ScanQueryConfig();
282+
283+
final ScanQueryQueryToolChest scanToolChest =
284+
new ScanQueryQueryToolChest(
285+
scanQueryConfig,
286+
genericQueryMetricsFactory
287+
);
288+
289+
chestMap.put(ScanQuery.class, scanToolChest);
290+
291+
276292
return new MapQueryToolChestWarehouse(chestMap);
277293
}
278294

src/test/java/com/simplaex/clients/druid/DruidClientTest.java

+56-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.simplaex.clients.druid;
22

3-
43
import io.druid.query.Druids;
54
import io.druid.query.Result;
5+
import io.druid.query.filter.DimFilters;
66
import io.druid.query.metadata.metadata.AllColumnIncluderator;
77
import io.druid.query.metadata.metadata.SegmentAnalysis;
88
import io.druid.query.metadata.metadata.SegmentMetadataQuery;
9+
import io.druid.query.scan.ScanQuery;
10+
import io.druid.query.scan.ScanResultValue;
911
import io.druid.query.select.EventHolder;
1012
import io.druid.query.select.PagingSpec;
1113
import io.druid.query.select.SelectQuery;
@@ -15,6 +17,9 @@
1517
import org.joda.time.Interval;
1618
import org.junit.*;
1719
import org.mockserver.integration.ClientAndServer;
20+
import org.mockserver.matchers.JsonStringMatcher;
21+
import org.mockserver.matchers.MatchType;
22+
import org.mockserver.matchers.Matcher;
1823
import org.mockserver.model.HttpRequest;
1924
import org.mockserver.model.HttpResponse;
2025

@@ -138,7 +143,8 @@ public void shouldExecuteASelectQuery() throws IOException {
138143
final SelectQuery query = new Druids.SelectQueryBuilder()
139144
.dataSource("player_explorer_s3")
140145
.dimensions(Collections.singletonList("deviceType"))
141-
.intervals(new MultipleIntervalSegmentSpec(Collections.singletonList(new Interval(from, to))))
146+
.intervals(new MultipleIntervalSegmentSpec(
147+
Collections.singletonList(new Interval(from, to))))
142148
.pagingSpec(new PagingSpec(Collections.emptyMap(), 100))
143149
.build();
144150

@@ -169,4 +175,52 @@ public void shouldExecuteASelectQuery() throws IOException {
169175
);
170176
}
171177

178+
@Test
179+
public void shouldExecuteAScanQuery() throws IOException {
180+
181+
setResponse(load("scan_query_response.json"));
182+
183+
final DruidClient client =
184+
DruidClient.create("localhost", mockServer.getPort());
185+
186+
final long from = Instant.parse("2017-06-30T00:00:00Z").toEpochMilli();
187+
final long to = Instant.parse("2020-10-02T00:00:00Z").toEpochMilli();
188+
189+
final ScanQuery query = new ScanQuery.ScanQueryBuilder()
190+
.dataSource("player_explorer_s3")
191+
.filters(DimFilters.dimEquals("version", "All"))
192+
.resultFormat("compactList")
193+
.columns(Arrays.asList("__time", "sessionCount", "deviceType"))
194+
.intervals(new MultipleIntervalSegmentSpec(
195+
Collections.singletonList(new Interval(from, to))))
196+
.build();
197+
198+
final DruidResult<ScanResultValue> result = client.run(query);
199+
200+
// The http request body isn't marked as json, so can't use automatic json body matcher.
201+
HttpRequest[] requests = mockServer.retrieveRecordedRequests(HttpRequest.request());
202+
Assert.assertEquals("Single request should be recorded", 1, requests.length);
203+
Matcher<String> jsonMatcher = new JsonStringMatcher(load("scan_query.json"), MatchType.ONLY_MATCHING_FIELDS);
204+
String requestedJson = (String)requests[0].getBody().getValue();
205+
Assert.assertTrue(
206+
String.format("expected request json should match %s, but was %s", jsonMatcher, requestedJson),
207+
jsonMatcher.matches(requestedJson));
208+
209+
final List<ScanResultValue> resultList = result.toList();
210+
211+
Assert.assertEquals("Number of results should be 11", 11, resultList.size());
212+
ScanResultValue scanResult = resultList.get(10);
213+
214+
Assert.assertEquals("should have 3 columns", 3, scanResult.getColumns().size());
215+
Assert.assertEquals(
216+
"second columns should be sessionCount",
217+
"sessionCount",
218+
scanResult.getColumns().get(1));
219+
220+
final List<List<Object>> events = (List<List<Object>>) scanResult.getEvents();
221+
Assert.assertEquals("should have 2 events", 2, events.size());
222+
223+
final List<Object> values = events.get(1);
224+
Assert.assertEquals("the last event should have a sessionCount of 25", 25, values.get(1));
225+
}
172226
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"queryType": "scan",
3+
"filter": {"type": "selector", "dimension": "version", "value": "All"},
4+
"resultFormat": "compactList",
5+
"intervals":{"type":"intervals","intervals":["2017-06-30T00:00:00.000Z/2020-10-02T00:00:00.000Z"]},
6+
"columns": ["__time", "sessionCount", "deviceType"]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[ {
2+
"segmentId" : "player_explorer_s3_2017-07-01T00:00:00.000Z_2017-07-02T00:00:00.000Z_2018-02-08T08:34:25.479Z_401",
3+
"columns" : [ "__time", "sessionCount", "deviceType" ],
4+
"events" : [ [ 1498867200000, 15, "Smartphone" ], [ 1498867200000, 25, "Smart-TV" ] ]
5+
}, {
6+
"segmentId" : "player_explorer_s3_2017-07-02T00:00:00.000Z_2017-07-03T00:00:00.000Z_2018-02-09T21:09:39.596Z_333",
7+
"columns" : [ "__time", "sessionCount", "deviceType" ],
8+
"events" : [ [ 1498953600000, 145, "Smartphone" ] ]
9+
}, {
10+
"segmentId" : "player_explorer_s3_2017-07-03T00:00:00.000Z_2017-07-04T00:00:00.000Z_2018-02-10T00:21:46.504Z_301",
11+
"columns" : [ "__time", "sessionCount", "deviceType" ],
12+
"events" : [ [ 1499040000000, 25, "Smartphone" ] ]
13+
}, {
14+
"segmentId" : "player_explorer_s3_2017-07-04T00:00:00.000Z_2017-07-05T00:00:00.000Z_2018-02-10T03:30:51.706Z_306",
15+
"columns" : [ "__time", "sessionCount", "deviceType" ],
16+
"events" : [ [ 1499126400000, 17, "Smartphone" ] ]
17+
}, {
18+
"segmentId" : "player_explorer_s3_2017-07-05T00:00:00.000Z_2017-07-06T00:00:00.000Z_2018-02-10T06:41:58.681Z_305",
19+
"columns" : [ "__time", "sessionCount", "deviceType" ],
20+
"events" : [ [ 1499212800000, 34, "Smartphone" ] ]
21+
}, {
22+
"segmentId" : "player_explorer_s3_2017-07-06T00:00:00.000Z_2017-07-07T00:00:00.000Z_2018-02-10T09:51:58.586Z_261",
23+
"columns" : [ "__time", "sessionCount", "deviceType" ],
24+
"events" : [ [ 1499299200000, 45, "Smartphone" ] ]
25+
}, {
26+
"segmentId" : "player_explorer_s3_2017-07-07T00:00:00.000Z_2017-07-08T00:00:00.000Z_2018-02-10T13:08:29.227Z_293",
27+
"columns" : [ "__time", "sessionCount", "deviceType" ],
28+
"events" : [ [ 1499385600000, 6, "Smartphone" ] ]
29+
}, {
30+
"segmentId" : "player_explorer_s3_2017-07-08T00:00:00.000Z_2017-07-09T00:00:00.000Z_2018-02-10T16:16:55.837Z_293",
31+
"columns" : [ "__time", "sessionCount", "deviceType" ],
32+
"events" : [ [ 1499472000000, 233, "Smartphone" ], [ 1499472000000, 25, "Smart-TV" ] ]
33+
}, {
34+
"segmentId" : "player_explorer_s3_2017-07-09T00:00:00.000Z_2017-07-10T00:00:00.000Z_2018-02-10T19:25:43.987Z_417",
35+
"columns" : [ "__time", "sessionCount", "deviceType" ],
36+
"events" : [ [ 1499558400000, 22, "Smartphone" ] ]
37+
}, {
38+
"segmentId" : "player_explorer_s3_2017-07-10T00:00:00.000Z_2017-07-11T00:00:00.000Z_2018-02-09T05:04:25.460Z_248",
39+
"columns" : [ "__time", "sessionCount", "deviceType" ],
40+
"events" : [ [ 1499644800000, 355, "Smartphone" ] ]
41+
}, {
42+
"segmentId" : "player_explorer_s3_2017-07-11T00:00:00.000Z_2017-07-12T00:00:00.000Z_2018-02-09T08:20:10.493Z_320",
43+
"columns" : [ "__time", "sessionCount", "deviceType" ],
44+
"events" : [ [ 1499731200000, 24, "Smartphone" ], [ 1499731200000, 25, "Smart-TV" ] ]
45+
} ]

0 commit comments

Comments
 (0)