mirror of https://github.com/apache/druid.git
Fix TimeBoundary planning when filters require virtual columns. (#16337)
The timeBoundary query does not support virtual columns, so we should avoid it if the query requires virtual columns.
This commit is contained in:
parent
31eee7d51e
commit
68d6e682e8
|
@ -1078,6 +1078,12 @@ public class DruidQuery
|
||||||
virtualColumnRegistry,
|
virtualColumnRegistry,
|
||||||
plannerContext.getJoinableFactoryWrapper()
|
plannerContext.getJoinableFactoryWrapper()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!getVirtualColumns(true).isEmpty()) {
|
||||||
|
// timeBoundary query does not support virtual columns.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final DataSource newDataSource = dataSourceFiltrationPair.lhs;
|
final DataSource newDataSource = dataSourceFiltrationPair.lhs;
|
||||||
final Filtration filtration = dataSourceFiltrationPair.rhs;
|
final Filtration filtration = dataSourceFiltrationPair.rhs;
|
||||||
String bound = minTime ? TimeBoundaryQuery.MIN_TIME : TimeBoundaryQuery.MAX_TIME;
|
String bound = minTime ? TimeBoundaryQuery.MIN_TIME : TimeBoundaryQuery.MAX_TIME;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.apache.druid.query.aggregation.LongMaxAggregatorFactory;
|
||||||
import org.apache.druid.query.aggregation.LongMinAggregatorFactory;
|
import org.apache.druid.query.aggregation.LongMinAggregatorFactory;
|
||||||
import org.apache.druid.query.spec.MultipleIntervalSegmentSpec;
|
import org.apache.druid.query.spec.MultipleIntervalSegmentSpec;
|
||||||
import org.apache.druid.query.timeboundary.TimeBoundaryQuery;
|
import org.apache.druid.query.timeboundary.TimeBoundaryQuery;
|
||||||
|
import org.apache.druid.segment.column.ColumnType;
|
||||||
import org.apache.druid.segment.join.JoinType;
|
import org.apache.druid.segment.join.JoinType;
|
||||||
import org.apache.druid.sql.calcite.filtration.Filtration;
|
import org.apache.druid.sql.calcite.filtration.Filtration;
|
||||||
import org.apache.druid.sql.calcite.util.CalciteTests;
|
import org.apache.druid.sql.calcite.util.CalciteTests;
|
||||||
|
@ -83,7 +84,7 @@ public class CalciteTimeBoundaryQueryTest extends BaseCalciteQueryTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMinTimeQueryWithFilters()
|
public void testMinTimeQueryWithTimeFilters()
|
||||||
{
|
{
|
||||||
HashMap<String, Object> queryContext = new HashMap<>(QUERY_CONTEXT_DEFAULT);
|
HashMap<String, Object> queryContext = new HashMap<>(QUERY_CONTEXT_DEFAULT);
|
||||||
queryContext.put(QueryContexts.TIME_BOUNDARY_PLANNING_KEY, true);
|
queryContext.put(QueryContexts.TIME_BOUNDARY_PLANNING_KEY, true);
|
||||||
|
@ -108,6 +109,66 @@ public class CalciteTimeBoundaryQueryTest extends BaseCalciteQueryTest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMinTimeQueryWithTimeAndColumnFilters()
|
||||||
|
{
|
||||||
|
HashMap<String, Object> queryContext = new HashMap<>(QUERY_CONTEXT_DEFAULT);
|
||||||
|
queryContext.put(QueryContexts.TIME_BOUNDARY_PLANNING_KEY, true);
|
||||||
|
HashMap<String, Object> expectedContext = new HashMap<>(QUERY_CONTEXT_DEFAULT);
|
||||||
|
expectedContext.put(TimeBoundaryQuery.MIN_TIME_ARRAY_OUTPUT_NAME, "a0");
|
||||||
|
testQuery(
|
||||||
|
"SELECT MIN(__time) AS minTime FROM foo\n"
|
||||||
|
+ "where __time >= '2001-01-01' and __time < '2003-01-01'\n"
|
||||||
|
+ "and dim2 = 'abc'",
|
||||||
|
queryContext,
|
||||||
|
ImmutableList.of(
|
||||||
|
Druids.newTimeBoundaryQueryBuilder()
|
||||||
|
.dataSource("foo")
|
||||||
|
.intervals(
|
||||||
|
new MultipleIntervalSegmentSpec(
|
||||||
|
ImmutableList.of(Intervals.of("2001-01-01T00:00:00.000Z/2003-01-01T00:00:00.000Z"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.bound(TimeBoundaryQuery.MIN_TIME)
|
||||||
|
.filters(equality("dim2", "abc", ColumnType.STRING))
|
||||||
|
.context(expectedContext)
|
||||||
|
.build()
|
||||||
|
),
|
||||||
|
ImmutableList.of(new Object[]{DateTimes.of("2001-01-02").getMillis()})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMinTimeQueryWithTimeAndExpressionFilters()
|
||||||
|
{
|
||||||
|
// Cannot vectorize due to UPPER expression.
|
||||||
|
cannotVectorize();
|
||||||
|
|
||||||
|
HashMap<String, Object> queryContext = new HashMap<>(QUERY_CONTEXT_DEFAULT);
|
||||||
|
queryContext.put(QueryContexts.TIME_BOUNDARY_PLANNING_KEY, true);
|
||||||
|
testQuery(
|
||||||
|
"SELECT MIN(__time) AS minTime FROM foo\n"
|
||||||
|
+ "where __time >= '2001-01-01' and __time < '2003-01-01'\n"
|
||||||
|
+ "and upper(dim2) = 'ABC'",
|
||||||
|
queryContext,
|
||||||
|
ImmutableList.of(
|
||||||
|
Druids.newTimeseriesQueryBuilder()
|
||||||
|
.dataSource("foo")
|
||||||
|
.intervals(
|
||||||
|
new MultipleIntervalSegmentSpec(
|
||||||
|
ImmutableList.of(Intervals.of("2001-01-01T00:00:00.000Z/2003-01-01T00:00:00.000Z"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.virtualColumns(expressionVirtualColumn("v0", "upper(\"dim2\")", ColumnType.STRING))
|
||||||
|
.filters(equality("v0", "ABC", ColumnType.STRING))
|
||||||
|
.aggregators(new LongMinAggregatorFactory("a0", "__time"))
|
||||||
|
.context(queryContext)
|
||||||
|
.build()
|
||||||
|
),
|
||||||
|
ImmutableList.of(new Object[]{DateTimes.of("2001-01-02").getMillis()})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Currently, if both min(__time) and max(__time) are present, we don't convert it
|
// Currently, if both min(__time) and max(__time) are present, we don't convert it
|
||||||
// to a timeBoundary query. (ref : https://github.com/apache/druid/issues/12479)
|
// to a timeBoundary query. (ref : https://github.com/apache/druid/issues/12479)
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue