Support limit for timeseries query (#5894) (#5931)

* Support limit for timeseries query (#5894)

* Fix tests

* Address PR comments

* Try to fix teamcity inspection checks

* Remove unused method from VirtualColumns

* Remove unused import statement
This commit is contained in:
Surekha 2018-07-09 08:58:42 -07:00 committed by Gian Merlino
parent d1d9358274
commit 441c9819d9
14 changed files with 141 additions and 85 deletions

View File

@ -105,6 +105,7 @@ public class Druids
private List<AggregatorFactory> aggregatorSpecs; private List<AggregatorFactory> aggregatorSpecs;
private List<PostAggregator> postAggregatorSpecs; private List<PostAggregator> postAggregatorSpecs;
private Map<String, Object> context; private Map<String, Object> context;
private int limit;
private TimeseriesQueryBuilder() private TimeseriesQueryBuilder()
{ {
@ -116,6 +117,7 @@ public class Druids
granularity = Granularities.ALL; granularity = Granularities.ALL;
aggregatorSpecs = Lists.newArrayList(); aggregatorSpecs = Lists.newArrayList();
postAggregatorSpecs = Lists.newArrayList(); postAggregatorSpecs = Lists.newArrayList();
limit = 0;
context = null; context = null;
} }
@ -130,6 +132,7 @@ public class Druids
granularity, granularity,
aggregatorSpecs, aggregatorSpecs,
postAggregatorSpecs, postAggregatorSpecs,
limit,
context context
); );
} }
@ -145,6 +148,7 @@ public class Druids
.granularity(query.getGranularity()) .granularity(query.getGranularity())
.aggregators(query.getAggregatorSpecs()) .aggregators(query.getAggregatorSpecs())
.postAggregators(query.getPostAggregatorSpecs()) .postAggregators(query.getPostAggregatorSpecs())
.limit(query.getLimit())
.context(query.getContext()); .context(query.getContext());
} }
@ -254,6 +258,12 @@ public class Druids
context = c; context = c;
return this; return this;
} }
public TimeseriesQueryBuilder limit(int lim)
{
limit = lim;
return this;
}
} }
public static TimeseriesQueryBuilder newTimeseriesQueryBuilder() public static TimeseriesQueryBuilder newTimeseriesQueryBuilder()

View File

@ -35,11 +35,18 @@ public class DefaultTimeseriesQueryMetrics extends DefaultQueryMetrics<Timeserie
public void query(TimeseriesQuery query) public void query(TimeseriesQuery query)
{ {
super.query(query); super.query(query);
limit(query);
numMetrics(query); numMetrics(query);
numComplexMetrics(query); numComplexMetrics(query);
granularity(query); granularity(query);
} }
@Override
public void limit(TimeseriesQuery query)
{
setDimension("limit", String.valueOf(query.getLimit()));
}
@Override @Override
public void numMetrics(TimeseriesQuery query) public void numMetrics(TimeseriesQuery query)
{ {

View File

@ -22,6 +22,7 @@ package io.druid.query.timeseries;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonTypeName;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import io.druid.java.util.common.granularity.Granularity; import io.druid.java.util.common.granularity.Granularity;
import io.druid.query.BaseQuery; import io.druid.query.BaseQuery;
@ -52,6 +53,7 @@ public class TimeseriesQuery extends BaseQuery<Result<TimeseriesResultValue>>
private final DimFilter dimFilter; private final DimFilter dimFilter;
private final List<AggregatorFactory> aggregatorSpecs; private final List<AggregatorFactory> aggregatorSpecs;
private final List<PostAggregator> postAggregatorSpecs; private final List<PostAggregator> postAggregatorSpecs;
private final int limit;
@JsonCreator @JsonCreator
public TimeseriesQuery( public TimeseriesQuery(
@ -63,6 +65,7 @@ public class TimeseriesQuery extends BaseQuery<Result<TimeseriesResultValue>>
@JsonProperty("granularity") Granularity granularity, @JsonProperty("granularity") Granularity granularity,
@JsonProperty("aggregations") List<AggregatorFactory> aggregatorSpecs, @JsonProperty("aggregations") List<AggregatorFactory> aggregatorSpecs,
@JsonProperty("postAggregations") List<PostAggregator> postAggregatorSpecs, @JsonProperty("postAggregations") List<PostAggregator> postAggregatorSpecs,
@JsonProperty("limit") int limit,
@JsonProperty("context") Map<String, Object> context @JsonProperty("context") Map<String, Object> context
) )
{ {
@ -76,6 +79,8 @@ public class TimeseriesQuery extends BaseQuery<Result<TimeseriesResultValue>>
this.aggregatorSpecs, this.aggregatorSpecs,
postAggregatorSpecs == null ? ImmutableList.of() : postAggregatorSpecs postAggregatorSpecs == null ? ImmutableList.of() : postAggregatorSpecs
); );
this.limit = (limit == 0) ? Integer.MAX_VALUE : limit;
Preconditions.checkArgument(this.limit > 0, "limit must be greater than 0");
} }
@Override @Override
@ -120,6 +125,12 @@ public class TimeseriesQuery extends BaseQuery<Result<TimeseriesResultValue>>
return postAggregatorSpecs; return postAggregatorSpecs;
} }
@JsonProperty("limit")
public int getLimit()
{
return limit;
}
public boolean isGrandTotal() public boolean isGrandTotal()
{ {
return getContextBoolean(CTX_GRAND_TOTAL, false); return getContextBoolean(CTX_GRAND_TOTAL, false);
@ -171,6 +182,7 @@ public class TimeseriesQuery extends BaseQuery<Result<TimeseriesResultValue>>
", granularity='" + getGranularity() + '\'' + ", granularity='" + getGranularity() + '\'' +
", aggregatorSpecs=" + aggregatorSpecs + ", aggregatorSpecs=" + aggregatorSpecs +
", postAggregatorSpecs=" + postAggregatorSpecs + ", postAggregatorSpecs=" + postAggregatorSpecs +
", limit=" + limit +
", context=" + getContext() + ", context=" + getContext() +
'}'; '}';
} }
@ -188,7 +200,8 @@ public class TimeseriesQuery extends BaseQuery<Result<TimeseriesResultValue>>
return false; return false;
} }
final TimeseriesQuery that = (TimeseriesQuery) o; final TimeseriesQuery that = (TimeseriesQuery) o;
return Objects.equals(virtualColumns, that.virtualColumns) && return limit == that.limit &&
Objects.equals(virtualColumns, that.virtualColumns) &&
Objects.equals(dimFilter, that.dimFilter) && Objects.equals(dimFilter, that.dimFilter) &&
Objects.equals(aggregatorSpecs, that.aggregatorSpecs) && Objects.equals(aggregatorSpecs, that.aggregatorSpecs) &&
Objects.equals(postAggregatorSpecs, that.postAggregatorSpecs); Objects.equals(postAggregatorSpecs, that.postAggregatorSpecs);
@ -197,6 +210,6 @@ public class TimeseriesQuery extends BaseQuery<Result<TimeseriesResultValue>>
@Override @Override
public int hashCode() public int hashCode()
{ {
return Objects.hash(super.hashCode(), virtualColumns, dimFilter, aggregatorSpecs, postAggregatorSpecs); return Objects.hash(super.hashCode(), virtualColumns, dimFilter, aggregatorSpecs, postAggregatorSpecs, limit);
} }
} }

View File

@ -46,7 +46,16 @@ public class TimeseriesQueryEngine
} }
final Filter filter = Filters.convertToCNFFromQueryContext(query, Filters.toFilter(query.getDimensionsFilter())); final Filter filter = Filters.convertToCNFFromQueryContext(query, Filters.toFilter(query.getDimensionsFilter()));
final int limit = query.getLimit();
Sequence<Result<TimeseriesResultValue>> result = generateTimeseriesResult(adapter, query, filter);
if (limit < Integer.MAX_VALUE) {
return result.limit(limit);
}
return result;
}
private Sequence<Result<TimeseriesResultValue>> generateTimeseriesResult(StorageAdapter adapter, TimeseriesQuery query, Filter filter)
{
return QueryRunnerHelper.makeCursorBasedQuery( return QueryRunnerHelper.makeCursorBasedQuery(
adapter, adapter,
query.getQuerySegmentSpec().getIntervals(), query.getQuerySegmentSpec().getIntervals(),
@ -81,7 +90,6 @@ public class TimeseriesQueryEngine
} }
cursor.advance(); cursor.advance();
} }
TimeseriesResultBuilder bob = new TimeseriesResultBuilder(cursor.getTime()); TimeseriesResultBuilder bob = new TimeseriesResultBuilder(cursor.getTime());
for (int i = 0; i < aggregatorSpecs.size(); i++) { for (int i = 0; i < aggregatorSpecs.size(); i++) {

View File

@ -29,6 +29,13 @@ import io.druid.query.QueryMetrics;
@ExtensionPoint @ExtensionPoint
public interface TimeseriesQueryMetrics extends QueryMetrics<TimeseriesQuery> public interface TimeseriesQueryMetrics extends QueryMetrics<TimeseriesQuery>
{ {
/**
* Sets {@link TimeseriesQuery#getLimit()} of the given query as dimension.
*/
@PublicApi
void limit(TimeseriesQuery query);
/** /**
* Sets the number of metrics of the given timeseries query as dimension. * Sets the number of metrics of the given timeseries query as dimension.
*/ */

View File

@ -107,12 +107,17 @@ public class TimeseriesQueryQueryToolChest extends QueryToolChest<Result<Timeser
Map<String, Object> context Map<String, Object> context
) )
{ {
return super.doRun( int limit = ((TimeseriesQuery) queryPlus.getQuery()).getLimit();
Sequence<Result<TimeseriesResultValue>> result = super.doRun(
baseRunner, baseRunner,
// Don't do post aggs until makePostComputeManipulatorFn() is called // Don't do post aggs until makePostComputeManipulatorFn() is called
queryPlus.withQuery(((TimeseriesQuery) queryPlus.getQuery()).withPostAggregatorSpecs(ImmutableList.of())), queryPlus.withQuery(((TimeseriesQuery) queryPlus.getQuery()).withPostAggregatorSpecs(ImmutableList.of())),
context context
); );
if (limit < Integer.MAX_VALUE) {
return result.limit(limit);
}
return result;
} }
@Override @Override
@ -264,6 +269,7 @@ public class TimeseriesQueryQueryToolChest extends QueryToolChest<Result<Timeser
.appendCacheable(query.getDimensionsFilter()) .appendCacheable(query.getDimensionsFilter())
.appendCacheables(query.getAggregatorSpecs()) .appendCacheables(query.getAggregatorSpecs())
.appendCacheable(query.getVirtualColumns()) .appendCacheable(query.getVirtualColumns())
.appendInt(query.getLimit())
.build(); .build();
} }

View File

@ -25,7 +25,6 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import io.druid.java.util.common.Cacheable; import io.druid.java.util.common.Cacheable;
@ -71,11 +70,6 @@ public class VirtualColumns implements Cacheable
} }
} }
public static VirtualColumns create(VirtualColumn...virtualColumns)
{
return create(Lists.newArrayList(virtualColumns));
}
@JsonCreator @JsonCreator
public static VirtualColumns create(List<VirtualColumn> virtualColumns) public static VirtualColumns create(List<VirtualColumn> virtualColumns)
{ {

View File

@ -60,7 +60,7 @@ public class DefaultTimeseriesQueryMetricsTest
queryMetrics.reportQueryTime(0).emit(serviceEmitter); queryMetrics.reportQueryTime(0).emit(serviceEmitter);
Map<String, Object> actualEvent = cachingEmitter.getLastEmittedEvent().toMap(); Map<String, Object> actualEvent = cachingEmitter.getLastEmittedEvent().toMap();
Assert.assertEquals(14, actualEvent.size()); Assert.assertEquals(15, actualEvent.size());
Assert.assertTrue(actualEvent.containsKey("feed")); Assert.assertTrue(actualEvent.containsKey("feed"));
Assert.assertTrue(actualEvent.containsKey("timestamp")); Assert.assertTrue(actualEvent.containsKey("timestamp"));
Assert.assertEquals("", actualEvent.get("host")); Assert.assertEquals("", actualEvent.get("host"));

View File

@ -79,6 +79,7 @@ public class TimeseriesQueryQueryToolChestTest
new LongSumAggregatorFactory("metric0", "metric0") new LongSumAggregatorFactory("metric0", "metric0")
), ),
ImmutableList.<PostAggregator>of(new ConstantPostAggregator("post", 10)), ImmutableList.<PostAggregator>of(new ConstantPostAggregator("post", 10)),
0,
null null
) )
); );

View File

@ -2415,4 +2415,36 @@ public class TimeseriesQueryRunnerTest
TestHelper.assertExpectedResults(expectedResults, results2); TestHelper.assertExpectedResults(expectedResults, results2);
} }
@Test
public void testTimeseriesWithLimit()
{
TimeseriesQuery query = Druids.newTimeseriesQueryBuilder()
.dataSource(QueryRunnerTestHelper.dataSource)
.granularity(QueryRunnerTestHelper.dayGran)
.intervals(QueryRunnerTestHelper.fullOnInterval)
.aggregators(
Arrays.<AggregatorFactory>asList(
QueryRunnerTestHelper.rowsCount,
QueryRunnerTestHelper.qualityUniques
)
)
.descending(descending)
.limit(10)
.build();
// Must create a toolChest so we can run mergeResults.
QueryToolChest<Result<TimeseriesResultValue>, TimeseriesQuery> toolChest = new TimeseriesQueryQueryToolChest(
QueryRunnerTestHelper.NoopIntervalChunkingQueryRunnerDecorator()
);
// Must wrapped in a results finalizer to stop the runner's builtin finalizer from being called.
final FinalizeResultsQueryRunner finalRunner = new FinalizeResultsQueryRunner(
toolChest.mergeResults(runner),
toolChest
);
final List list = finalRunner.run(QueryPlus.wrap(query), CONTEXT).toList();
Assert.assertEquals(10, list.size());
}
} }

View File

@ -103,12 +103,25 @@ public class DruidQuery
private final RowSignature sourceRowSignature; private final RowSignature sourceRowSignature;
private final PlannerContext plannerContext; private final PlannerContext plannerContext;
@Nullable
private final DimFilter filter; private final DimFilter filter;
@Nullable
private final SelectProjection selectProjection; private final SelectProjection selectProjection;
@Nullable
private final Grouping grouping; private final Grouping grouping;
@Nullable
private final SortProject sortProject; private final SortProject sortProject;
@Nullable
private final DefaultLimitSpec limitSpec; private final DefaultLimitSpec limitSpec;
@Nullable
private final RowSignature outputRowSignature; private final RowSignature outputRowSignature;
@Nullable
private final RelDataType outputRowType; private final RelDataType outputRowType;
private final Query query; private final Query query;
@ -731,7 +744,7 @@ public class DruidQuery
final Granularity queryGranularity; final Granularity queryGranularity;
final boolean descending; final boolean descending;
int timeseriesLimit = 0;
if (grouping.getDimensions().isEmpty()) { if (grouping.getDimensions().isEmpty()) {
queryGranularity = Granularities.ALL; queryGranularity = Granularities.ALL;
descending = false; descending = false;
@ -746,11 +759,10 @@ public class DruidQuery
// Timeseries only applies if the single dimension is granular __time. // Timeseries only applies if the single dimension is granular __time.
return null; return null;
} }
if (limitSpec != null) { if (limitSpec != null) {
// If there is a limit spec, timeseries cannot LIMIT; and must be ORDER BY time (or nothing). // If there is a limit spec, set timeseriesLimit to given value if less than Integer.Max_VALUE
if (limitSpec.isLimited()) { if (limitSpec.isLimited()) {
return null; timeseriesLimit = limitSpec.getLimit();
} }
if (limitSpec.getColumns().isEmpty()) { if (limitSpec.getColumns().isEmpty()) {
@ -797,6 +809,7 @@ public class DruidQuery
queryGranularity, queryGranularity,
grouping.getAggregatorFactories(), grouping.getAggregatorFactories(),
postAggregators, postAggregators,
timeseriesLimit,
ImmutableSortedMap.copyOf(theContext) ImmutableSortedMap.copyOf(theContext)
); );
} }

View File

@ -308,7 +308,7 @@ public class DruidAvaticaHandlerTest extends CalciteTestBase
ImmutableList.of( ImmutableList.of(
ImmutableMap.of( ImmutableMap.of(
"PLAN", "PLAN",
"DruidQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"context\":{\"skipEmptyBuckets\":true}}], signature=[{a0:LONG}])\n" "DruidQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"limit\":2147483647,\"context\":{\"skipEmptyBuckets\":true}}], signature=[{a0:LONG}])\n"
) )
), ),
getRows(resultSet) getRows(resultSet)

View File

@ -82,7 +82,6 @@ import io.druid.query.topn.DimensionTopNMetricSpec;
import io.druid.query.topn.InvertedTopNMetricSpec; import io.druid.query.topn.InvertedTopNMetricSpec;
import io.druid.query.topn.NumericTopNMetricSpec; import io.druid.query.topn.NumericTopNMetricSpec;
import io.druid.query.topn.TopNQueryBuilder; import io.druid.query.topn.TopNQueryBuilder;
import io.druid.segment.VirtualColumns;
import io.druid.segment.column.Column; import io.druid.segment.column.Column;
import io.druid.segment.column.ValueType; import io.druid.segment.column.ValueType;
import io.druid.segment.virtual.ExpressionVirtualColumn; import io.druid.segment.virtual.ExpressionVirtualColumn;
@ -2129,6 +2128,7 @@ public class CalciteQueryTest extends CalciteTestBase
+ "\"granularity\":{\"type\":\"all\"}," + "\"granularity\":{\"type\":\"all\"},"
+ "\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}]," + "\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],"
+ "\"postAggregations\":[]," + "\"postAggregations\":[],"
+ "\"limit\":2147483647,"
+ "\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"skipEmptyBuckets\":true,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"}}]" + "\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"skipEmptyBuckets\":true,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"}}]"
+ ", signature=[{a0:LONG}])\n"; + ", signature=[{a0:LONG}])\n";
@ -4128,7 +4128,7 @@ public class CalciteQueryTest extends CalciteTestBase
public void testExplainDoubleNestedGroupBy() throws Exception public void testExplainDoubleNestedGroupBy() throws Exception
{ {
final String explanation = final String explanation =
"DruidOuterQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"__subquery__\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"longSum\",\"name\":\"a0\",\"fieldName\":\"cnt\",\"expression\":null},{\"type\":\"count\",\"name\":\"a1\"}],\"postAggregations\":[],\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"skipEmptyBuckets\":true,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"}}], signature=[{a0:LONG, a1:LONG}])\n" "DruidOuterQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"__subquery__\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"longSum\",\"name\":\"a0\",\"fieldName\":\"cnt\",\"expression\":null},{\"type\":\"count\",\"name\":\"a1\"}],\"postAggregations\":[],\"limit\":2147483647,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"skipEmptyBuckets\":true,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"}}], signature=[{a0:LONG, a1:LONG}])\n"
+ " DruidOuterQueryRel(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"__subquery__\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"default\",\"dimension\":\"dim2\",\"outputName\":\"d0\",\"outputType\":\"STRING\"}],\"aggregations\":[{\"type\":\"longSum\",\"name\":\"a0\",\"fieldName\":\"cnt\",\"expression\":null}],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], signature=[{d0:STRING, a0:LONG}])\n" + " DruidOuterQueryRel(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"__subquery__\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"default\",\"dimension\":\"dim2\",\"outputName\":\"d0\",\"outputType\":\"STRING\"}],\"aggregations\":[{\"type\":\"longSum\",\"name\":\"a0\",\"fieldName\":\"cnt\",\"expression\":null}],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], signature=[{d0:STRING, a0:LONG}])\n"
+ " DruidQueryRel(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"default\",\"dimension\":\"dim1\",\"outputName\":\"d0\",\"outputType\":\"STRING\"},{\"type\":\"default\",\"dimension\":\"dim2\",\"outputName\":\"d1\",\"outputType\":\"STRING\"}],\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], signature=[{d0:STRING, d1:STRING, a0:LONG}])\n"; + " DruidQueryRel(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"default\",\"dimension\":\"dim1\",\"outputName\":\"d0\",\"outputType\":\"STRING\"},{\"type\":\"default\",\"dimension\":\"dim2\",\"outputName\":\"d1\",\"outputType\":\"STRING\"}],\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], signature=[{d0:STRING, d1:STRING, a0:LONG}])\n";
@ -4425,7 +4425,7 @@ public class CalciteQueryTest extends CalciteTestBase
public void testExplainExactCountDistinctOfSemiJoinResult() throws Exception public void testExplainExactCountDistinctOfSemiJoinResult() throws Exception
{ {
final String explanation = final String explanation =
"DruidOuterQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"__subquery__\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"skipEmptyBuckets\":true,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"}}], signature=[{a0:LONG}])\n" "DruidOuterQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"__subquery__\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"limit\":2147483647,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"skipEmptyBuckets\":true,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"}}], signature=[{a0:LONG}])\n"
+ " DruidSemiJoin(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"default\",\"dimension\":\"dim2\",\"outputName\":\"d0\",\"outputType\":\"STRING\"}],\"aggregations\":[],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], leftExpressions=[[SUBSTRING($3, 1, 1)]], rightKeys=[[0]])\n" + " DruidSemiJoin(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"default\",\"dimension\":\"dim2\",\"outputName\":\"d0\",\"outputType\":\"STRING\"}],\"aggregations\":[],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], leftExpressions=[[SUBSTRING($3, 1, 1)]], rightKeys=[[0]])\n"
+ " DruidQueryRel(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"filter\":{\"type\":\"not\",\"field\":{\"type\":\"selector\",\"dimension\":\"dim1\",\"value\":\"\",\"extractionFn\":null}},\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"extraction\",\"dimension\":\"dim1\",\"outputName\":\"d0\",\"outputType\":\"STRING\",\"extractionFn\":{\"type\":\"substring\",\"index\":0,\"length\":1}}],\"aggregations\":[],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], signature=[{d0:STRING}])\n"; + " DruidQueryRel(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"filter\":{\"type\":\"not\",\"field\":{\"type\":\"selector\",\"dimension\":\"dim1\",\"value\":\"\",\"extractionFn\":null}},\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"extraction\",\"dimension\":\"dim1\",\"outputName\":\"d0\",\"outputType\":\"STRING\",\"extractionFn\":{\"type\":\"substring\",\"index\":0,\"length\":1}}],\"aggregations\":[],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], signature=[{d0:STRING}])\n";
@ -6118,32 +6118,13 @@ public class CalciteQueryTest extends CalciteTestBase
+ "LIMIT 1", + "LIMIT 1",
CalciteTests.REGULAR_USER_AUTH_RESULT, CalciteTests.REGULAR_USER_AUTH_RESULT,
ImmutableList.of( ImmutableList.of(
GroupByQuery.builder() Druids.newTimeseriesQueryBuilder()
.setDataSource(CalciteTests.DATASOURCE1) .dataSource(CalciteTests.DATASOURCE1)
.setInterval(QSS(Filtration.eternity())) .intervals(QSS(Filtration.eternity()))
.setGranularity(Granularities.ALL) .granularity(Granularities.MONTH)
.setVirtualColumns( .aggregators(AGGS(new LongSumAggregatorFactory("a0", "cnt")))
EXPRESSION_VIRTUAL_COLUMN( .limit(1)
"d0:v", .context(TIMESERIES_CONTEXT_DEFAULT)
"timestamp_floor(\"__time\",'P1M','','UTC')",
ValueType.LONG
)
)
.setDimensions(DIMS(new DefaultDimensionSpec("d0:v", "d0", ValueType.LONG)))
.setAggregatorSpecs(AGGS(new LongSumAggregatorFactory("a0", "cnt")))
.setLimitSpec(
new DefaultLimitSpec(
ImmutableList.of(
new OrderByColumnSpec(
"d0",
OrderByColumnSpec.Direction.ASCENDING,
StringComparators.NUMERIC
)
),
1
)
)
.setContext(QUERY_CONTEXT_DEFAULT)
.build() .build()
), ),
ImmutableList.of( ImmutableList.of(
@ -6164,18 +6145,13 @@ public class CalciteQueryTest extends CalciteTestBase
+ "GROUP BY gran\n" + "GROUP BY gran\n"
+ "LIMIT 1", + "LIMIT 1",
ImmutableList.of( ImmutableList.of(
new TopNQueryBuilder() Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1) .dataSource(CalciteTests.DATASOURCE1)
.intervals(QSS(Filtration.eternity())) .intervals(QSS(Filtration.eternity()))
.granularity(Granularities.ALL) .granularity(Granularities.MONTH)
.virtualColumns(
EXPRESSION_VIRTUAL_COLUMN("d0:v", "timestamp_floor(\"__time\",'P1M','','UTC')", ValueType.LONG)
)
.dimension(new DefaultDimensionSpec("d0:v", "d0", ValueType.LONG))
.aggregators(AGGS(new LongSumAggregatorFactory("a0", "cnt"))) .aggregators(AGGS(new LongSumAggregatorFactory("a0", "cnt")))
.metric(new DimensionTopNMetricSpec(null, StringComparators.NUMERIC)) .limit(1)
.threshold(1) .context(TIMESERIES_CONTEXT_DEFAULT)
.context(QUERY_CONTEXT_DEFAULT)
.build() .build()
), ),
ImmutableList.of( ImmutableList.of(
@ -6197,18 +6173,13 @@ public class CalciteQueryTest extends CalciteTestBase
+ "ORDER BY gran\n" + "ORDER BY gran\n"
+ "LIMIT 1", + "LIMIT 1",
ImmutableList.of( ImmutableList.of(
new TopNQueryBuilder() Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1) .dataSource(CalciteTests.DATASOURCE1)
.intervals(QSS(Filtration.eternity())) .intervals(QSS(Filtration.eternity()))
.granularity(Granularities.ALL) .granularity(Granularities.MONTH)
.virtualColumns(
EXPRESSION_VIRTUAL_COLUMN("d0:v", "timestamp_floor(\"__time\",'P1M','','UTC')", ValueType.LONG)
)
.dimension(new DefaultDimensionSpec("d0:v", "d0", ValueType.LONG))
.aggregators(AGGS(new LongSumAggregatorFactory("a0", "cnt"))) .aggregators(AGGS(new LongSumAggregatorFactory("a0", "cnt")))
.metric(new DimensionTopNMetricSpec(null, StringComparators.NUMERIC)) .limit(1)
.threshold(1) .context(TIMESERIES_CONTEXT_DEFAULT)
.context(QUERY_CONTEXT_DEFAULT)
.build() .build()
), ),
ImmutableList.of( ImmutableList.of(
@ -6334,7 +6305,7 @@ public class CalciteQueryTest extends CalciteTestBase
+ " BindableJoin(condition=[=($1, $3)], joinType=[left])\n" + " BindableJoin(condition=[=($1, $3)], joinType=[left])\n"
+ " BindableJoin(condition=[true], joinType=[inner])\n" + " BindableJoin(condition=[true], joinType=[inner])\n"
+ " DruidQueryRel(query=[{\"queryType\":\"scan\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"resultFormat\":\"compactedList\",\"batchSize\":20480,\"limit\":9223372036854775807,\"filter\":null,\"columns\":[\"dim1\",\"dim2\"],\"legacy\":false,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false,\"granularity\":{\"type\":\"all\"}}], signature=[{dim1:STRING, dim2:STRING}])\n" + " DruidQueryRel(query=[{\"queryType\":\"scan\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"resultFormat\":\"compactedList\",\"batchSize\":20480,\"limit\":9223372036854775807,\"filter\":null,\"columns\":[\"dim1\",\"dim2\"],\"legacy\":false,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false,\"granularity\":{\"type\":\"all\"}}], signature=[{dim1:STRING, dim2:STRING}])\n"
+ " DruidQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":{\"type\":\"like\",\"dimension\":\"dim1\",\"pattern\":\"%bc\",\"escape\":null,\"extractionFn\":null},\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"skipEmptyBuckets\":true,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"}}], signature=[{a0:LONG}])\n" + " DruidQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":{\"type\":\"like\",\"dimension\":\"dim1\",\"pattern\":\"%bc\",\"escape\":null,\"extractionFn\":null},\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"limit\":2147483647,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"skipEmptyBuckets\":true,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"}}], signature=[{a0:LONG}])\n"
+ " DruidQueryRel(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[{\"type\":\"expression\",\"name\":\"d1:v\",\"expression\":\"1\",\"outputType\":\"LONG\"}],\"filter\":{\"type\":\"like\",\"dimension\":\"dim1\",\"pattern\":\"%bc\",\"escape\":null,\"extractionFn\":null},\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"default\",\"dimension\":\"dim1\",\"outputName\":\"d0\",\"outputType\":\"STRING\"},{\"type\":\"default\",\"dimension\":\"d1:v\",\"outputName\":\"d1\",\"outputType\":\"LONG\"}],\"aggregations\":[],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], signature=[{d0:STRING, d1:LONG}])\n"; + " DruidQueryRel(query=[{\"queryType\":\"groupBy\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[{\"type\":\"expression\",\"name\":\"d1:v\",\"expression\":\"1\",\"outputType\":\"LONG\"}],\"filter\":{\"type\":\"like\",\"dimension\":\"dim1\",\"pattern\":\"%bc\",\"escape\":null,\"extractionFn\":null},\"granularity\":{\"type\":\"all\"},\"dimensions\":[{\"type\":\"default\",\"dimension\":\"dim1\",\"outputName\":\"d0\",\"outputType\":\"STRING\"},{\"type\":\"default\",\"dimension\":\"d1:v\",\"outputName\":\"d1\",\"outputType\":\"LONG\"}],\"aggregations\":[],\"postAggregations\":[],\"having\":null,\"limitSpec\":{\"type\":\"NoopLimitSpec\"},\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false}], signature=[{d0:STRING, d1:LONG}])\n";
final String theQuery = "SELECT dim1, dim2, COUNT(*) FROM druid.foo\n" final String theQuery = "SELECT dim1, dim2, COUNT(*) FROM druid.foo\n"
@ -6767,27 +6738,21 @@ public class CalciteQueryTest extends CalciteTestBase
{ {
testQuery( testQuery(
"SELECT " "SELECT "
+ " FLOOR(__time TO SECOND), "
+ " AVG(m2), " + " AVG(m2), "
+ " SUM(m1) + SUM(m2) " + " SUM(m1) + SUM(m2) "
+ "FROM " + "FROM "
+ " druid.foo " + " druid.foo "
+ "WHERE " + "WHERE "
+ " dim2 = 'a' " + " dim2 = 'a' "
+ "GROUP BY FLOOR(__time TO SECOND) " + "GROUP BY m1 "
+ "ORDER BY FLOOR(__time TO SECOND) " + "ORDER BY m1 "
+ "LIMIT 5", + "LIMIT 5",
Collections.singletonList( Collections.singletonList(
new TopNQueryBuilder() new TopNQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1) .dataSource(CalciteTests.DATASOURCE1)
.intervals(QSS(Filtration.eternity())) .intervals(QSS(Filtration.eternity()))
.granularity(Granularities.ALL) .granularity(Granularities.ALL)
.dimension(new DefaultDimensionSpec("d0:v", "d0", ValueType.LONG)) .dimension(new DefaultDimensionSpec("m1", "d0", ValueType.FLOAT))
.virtualColumns(
VirtualColumns.create(
EXPRESSION_VIRTUAL_COLUMN("d0:v", "timestamp_floor(\"__time\",'PT1S','','UTC')", ValueType.LONG)
)
)
.filters("dim2", "a") .filters("dim2", "a")
.aggregators(AGGS( .aggregators(AGGS(
new DoubleSumAggregatorFactory("a0:sum", "m2"), new DoubleSumAggregatorFactory("a0:sum", "m2"),
@ -6814,8 +6779,8 @@ public class CalciteQueryTest extends CalciteTestBase
.build() .build()
), ),
ImmutableList.of( ImmutableList.of(
new Object[]{946684800000L, 1.0, 2.0}, new Object[]{1.0, 2.0},
new Object[]{978307200000L, 4.0, 8.0} new Object[]{4.0, 8.0}
) )
); );
} }

View File

@ -235,7 +235,7 @@ public class SqlResourceTest extends CalciteTestBase
ImmutableList.of( ImmutableList.of(
ImmutableMap.<String, Object>of( ImmutableMap.<String, Object>of(
"PLAN", "PLAN",
"DruidQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"context\":{\"skipEmptyBuckets\":true}}], signature=[{a0:LONG}])\n" "DruidQueryRel(query=[{\"queryType\":\"timeseries\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"descending\":false,\"virtualColumns\":[],\"filter\":null,\"granularity\":{\"type\":\"all\"},\"aggregations\":[{\"type\":\"count\",\"name\":\"a0\"}],\"postAggregations\":[],\"limit\":2147483647,\"context\":{\"skipEmptyBuckets\":true}}], signature=[{a0:LONG}])\n"
) )
), ),
rows rows