Search in sources :

Example 1 with LogicalPlan

use of io.crate.planner.operators.LogicalPlan in project crate by crate.

the class MoveFilterBeneathWindowAgg method apply.

@Override
public LogicalPlan apply(Filter filter, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
    WindowAgg windowAgg = captures.get(windowAggCapture);
    WindowDefinition windowDefinition = windowAgg.windowDefinition();
    List<WindowFunction> windowFunctions = windowAgg.windowFunctions();
    Predicate<Symbol> containsWindowFunction = symbol -> symbol instanceof WindowFunction && windowFunctions.contains(symbol);
    Symbol predicate = filter.query();
    List<Symbol> filterParts = AndOperator.split(predicate);
    ArrayList<Symbol> remainingFilterSymbols = new ArrayList<>();
    ArrayList<Symbol> windowPartitionedBasedFilters = new ArrayList<>();
    for (Symbol part : filterParts) {
        if (SymbolVisitors.any(containsWindowFunction, part) == false && windowDefinition.partitions().containsAll(extractColumns(part))) {
            windowPartitionedBasedFilters.add(part);
        } else {
            remainingFilterSymbols.add(part);
        }
    }
    assert remainingFilterSymbols.size() > 0 || windowPartitionedBasedFilters.size() > 0 : "Splitting the filter symbol must result in at least one group";
    /* SELECT ROW_NUMBER() OVER(PARTITION BY id)
         * WHERE `x = 1`
         *
         * `x` is not the window partition column.
         * We cannot push down the filter as it would change the window aggregation value
         *
         */
    if (windowPartitionedBasedFilters.isEmpty()) {
        return null;
    }
    /* SELECT ROW_NUMBER() OVER(PARTITION BY id)
         * WHERE `id = 1`
         * remainingFilterSymbols:                  []
         * windowPartitionedBasedFilters:           [id = 1]
         *
         * Filter
         *  |
         * WindowsAgg
         *
         * transforms to
         *
         * WindowAgg
         *  |
         * Filter (id = 1)
         */
    if (remainingFilterSymbols.isEmpty()) {
        return transpose(filter, windowAgg);
    }
    /* WHERE `ROW_NUMBER() OVER(PARTITION BY id) = 2 AND id = 1`
         * remainingFilterSymbols:                  [ROW_NUMBER() OVER(PARTITION BY id) = 2]
         * windowPartitionedBasedFilters:           [id = 1]
         *
         * Filter
         *  |
         * WindowsAgg
         *
         * transforms to
         *
         * Filter (ROW_NUMBER() OVER(PARTITION BY id) = 2)
         *  |
         * WindowAgg
         *  |
         * Filter (id = 1)
         */
    LogicalPlan newWindowAgg = windowAgg.replaceSources(List.of(new Filter(windowAgg.source(), AndOperator.join(windowPartitionedBasedFilters))));
    return new Filter(newWindowAgg, AndOperator.join(remainingFilterSymbols));
}
Also used : TransactionContext(io.crate.metadata.TransactionContext) NodeContext(io.crate.metadata.NodeContext) LogicalPlanner.extractColumns(io.crate.planner.operators.LogicalPlanner.extractColumns) LogicalPlan(io.crate.planner.operators.LogicalPlan) Captures(io.crate.planner.optimizer.matcher.Captures) Predicate(java.util.function.Predicate) Util.transpose(io.crate.planner.optimizer.rule.Util.transpose) Pattern(io.crate.planner.optimizer.matcher.Pattern) Rule(io.crate.planner.optimizer.Rule) SymbolVisitors(io.crate.expression.symbol.SymbolVisitors) ArrayList(java.util.ArrayList) List(java.util.List) AndOperator(io.crate.expression.operator.AndOperator) TableStats(io.crate.statistics.TableStats) WindowDefinition(io.crate.analyze.WindowDefinition) Symbol(io.crate.expression.symbol.Symbol) Pattern.typeOf(io.crate.planner.optimizer.matcher.Pattern.typeOf) WindowFunction(io.crate.expression.symbol.WindowFunction) Patterns.source(io.crate.planner.optimizer.matcher.Patterns.source) Filter(io.crate.planner.operators.Filter) WindowAgg(io.crate.planner.operators.WindowAgg) Capture(io.crate.planner.optimizer.matcher.Capture) WindowFunction(io.crate.expression.symbol.WindowFunction) WindowAgg(io.crate.planner.operators.WindowAgg) Filter(io.crate.planner.operators.Filter) Symbol(io.crate.expression.symbol.Symbol) ArrayList(java.util.ArrayList) LogicalPlan(io.crate.planner.operators.LogicalPlan) WindowDefinition(io.crate.analyze.WindowDefinition)

Example 2 with LogicalPlan

use of io.crate.planner.operators.LogicalPlan in project crate by crate.

the class CopyToPlan method optimizeCollect.

private static LogicalPlan optimizeCollect(PlannerContext context, TableStats tableStats, LogicalPlan collect) {
    OptimizeCollectWhereClauseAccess rewriteCollectToGet = new OptimizeCollectWhereClauseAccess();
    Match<Collect> match = rewriteCollectToGet.pattern().accept(collect, Captures.empty());
    if (match.isPresent()) {
        LogicalPlan plan = rewriteCollectToGet.apply(match.value(), match.captures(), tableStats, context.transactionContext(), context.nodeContext());
        return plan == null ? collect : plan;
    }
    return collect;
}
Also used : Collect(io.crate.planner.operators.Collect) LogicalPlan(io.crate.planner.operators.LogicalPlan) OptimizeCollectWhereClauseAccess(io.crate.planner.optimizer.rule.OptimizeCollectWhereClauseAccess)

Example 3 with LogicalPlan

use of io.crate.planner.operators.LogicalPlan in project crate by crate.

the class CopyToPlan method planCopyToExecution.

@VisibleForTesting
static ExecutionPlan planCopyToExecution(AnalyzedCopyTo copyTo, PlannerContext context, TableStats tableStats, ProjectionBuilder projectionBuilder, Row params, SubQueryResults subQueryResults) {
    var boundedCopyTo = bind(copyTo, context.transactionContext(), context.nodeContext(), params, subQueryResults);
    WriterProjection.OutputFormat outputFormat = boundedCopyTo.outputFormat();
    if (outputFormat == null) {
        outputFormat = boundedCopyTo.columnsDefined() ? WriterProjection.OutputFormat.JSON_ARRAY : WriterProjection.OutputFormat.JSON_OBJECT;
    }
    WriterProjection projection = ProjectionBuilder.writerProjection(boundedCopyTo.outputs(), boundedCopyTo.uri(), boundedCopyTo.compressionType(), boundedCopyTo.overwrites(), boundedCopyTo.outputNames(), outputFormat, boundedCopyTo.withClauseOptions());
    LogicalPlan collect = Collect.create(new DocTableRelation(boundedCopyTo.table()), boundedCopyTo.outputs(), boundedCopyTo.whereClause(), tableStats, context.params());
    LogicalPlan source = optimizeCollect(context, tableStats, collect);
    ExecutionPlan executionPlan = source.build(context, Set.of(), projectionBuilder, 0, 0, null, null, params, SubQueryResults.EMPTY);
    executionPlan.addProjection(projection);
    return Merge.ensureOnHandler(executionPlan, context, List.of(MergeCountProjection.INSTANCE));
}
Also used : WriterProjection(io.crate.execution.dsl.projection.WriterProjection) ExecutionPlan(io.crate.planner.ExecutionPlan) DocTableRelation(io.crate.analyze.relations.DocTableRelation) LogicalPlan(io.crate.planner.operators.LogicalPlan) VisibleForTesting(io.crate.common.annotations.VisibleForTesting)

Example 4 with LogicalPlan

use of io.crate.planner.operators.LogicalPlan in project crate by crate.

the class RewriteFilterOnOuterJoinToInnerJoin method apply.

@Override
public LogicalPlan apply(Filter filter, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
    var symbolEvaluator = new SymbolEvaluator(txnCtx, nodeCtx, SubQueryResults.EMPTY);
    NestedLoopJoin nl = captures.get(nlCapture);
    Symbol query = filter.query();
    Map<Set<RelationName>, Symbol> splitQueries = QuerySplitter.split(query);
    if (splitQueries.size() == 1 && splitQueries.keySet().iterator().next().size() > 1) {
        return null;
    }
    LogicalPlan lhs = nl.sources().get(0);
    LogicalPlan rhs = nl.sources().get(1);
    Set<RelationName> leftName = lhs.getRelationNames();
    Set<RelationName> rightName = rhs.getRelationNames();
    Symbol leftQuery = splitQueries.remove(leftName);
    Symbol rightQuery = splitQueries.remove(rightName);
    final LogicalPlan newLhs;
    final LogicalPlan newRhs;
    final boolean newJoinIsInnerJoin;
    switch(nl.joinType()) {
        case LEFT:
            /* LEFT OUTER JOIN -> NULL rows are generated for the RHS if the join-condition doesn't match
                 *
                 * cr> select t1.x as t1x, t2.x as t2x from t1 left join t2 on t1.x = t2.x;
                 * +-----+------+
                 * | t1x |  t2x |
                 * +-----+------+
                 * |   3 |    3 |
                 * |   2 |    2 |
                 * |   1 | NULL |
                 * +-----+------+
                 */
            newLhs = getNewSource(leftQuery, lhs);
            if (rightQuery == null) {
                newRhs = rhs;
                newJoinIsInnerJoin = false;
            } else if (couldMatchOnNull(rightQuery, symbolEvaluator)) {
                newRhs = rhs;
                newJoinIsInnerJoin = false;
                splitQueries.put(rightName, rightQuery);
            } else {
                newRhs = getNewSource(rightQuery, rhs);
                newJoinIsInnerJoin = true;
            }
            break;
        case RIGHT:
            /* RIGHT OUTER JOIN -> NULL rows are generated for the LHS if the join-condition doesn't match

                 * cr> select t1.x as t1x, t2.x as t2x from t1 right join t2 on t1.x = t2.x;
                 * +------+-----+
                 * |  t1x | t2x |
                 * +------+-----+
                 * |    3 |   3 |
                 * |    2 |   2 |
                 * | NULL |   4 |
                 * +------+-----+
                 */
            if (leftQuery == null) {
                newLhs = lhs;
                newJoinIsInnerJoin = false;
            } else if (couldMatchOnNull(leftQuery, symbolEvaluator)) {
                newLhs = lhs;
                newJoinIsInnerJoin = false;
                splitQueries.put(leftName, leftQuery);
            } else {
                newLhs = getNewSource(leftQuery, lhs);
                newJoinIsInnerJoin = true;
            }
            newRhs = getNewSource(rightQuery, rhs);
            break;
        case FULL:
            if (couldMatchOnNull(leftQuery, symbolEvaluator)) {
                newLhs = lhs;
            } else {
                newLhs = getNewSource(leftQuery, lhs);
                if (leftQuery != null) {
                    splitQueries.put(leftName, leftQuery);
                }
            }
            if (couldMatchOnNull(rightQuery, symbolEvaluator)) {
                newRhs = rhs;
            } else {
                newRhs = getNewSource(rightQuery, rhs);
            }
            /*
                 * Filters on each side must be put back into the Filter as each side can generate NULL's on outer joins
                 * which must be filtered out AFTER the join operation.
                 * In case the filter is only on one side, the join could be rewritten to a LEFT/RIGHT OUTER.
                 * TODO: Create a dedicated rule RewriteFilterOnOuterJoinToLeftOrRight
                 *
                 * cr> select t1.x as t1x, t2.x as t2x, t2.y as t2y from t1 full outer join t2 on t1.x = t2.x where t2y = 1;
                 * +------+------+------+
                 * |  t1x |  t2x |  t2y |
                 * +------+------+------+
                 * |    3 |    3 |    1 |
                 * |    2 |    2 |    1 |
                 * | NULL |    4 |    1 |
                 * +------+------+------+
                 */
            if (leftQuery != null) {
                splitQueries.put(leftName, leftQuery);
            }
            if (rightQuery != null) {
                splitQueries.put(rightName, rightQuery);
            }
            newJoinIsInnerJoin = newLhs != lhs && newRhs != rhs;
            break;
        default:
            throw new UnsupportedOperationException("The Rule to rewrite filter+outer-joins to inner joins must not be run on joins of type=" + nl.joinType());
    }
    if (newLhs == lhs && newRhs == rhs) {
        return null;
    }
    NestedLoopJoin newJoin = new NestedLoopJoin(newLhs, newRhs, newJoinIsInnerJoin ? JoinType.INNER : nl.joinType(), nl.joinCondition(), nl.isFiltered(), nl.topMostLeftRelation(), nl.orderByWasPushedDown(), true);
    assert newJoin.outputs().equals(nl.outputs()) : "Outputs after rewrite must be the same as before";
    return splitQueries.isEmpty() ? newJoin : new Filter(newJoin, AndOperator.join(splitQueries.values()));
}
Also used : Set(java.util.Set) Filter(io.crate.planner.operators.Filter) Symbol(io.crate.expression.symbol.Symbol) NestedLoopJoin(io.crate.planner.operators.NestedLoopJoin) RelationName(io.crate.metadata.RelationName) LogicalPlan(io.crate.planner.operators.LogicalPlan) SymbolEvaluator(io.crate.analyze.SymbolEvaluator)

Example 5 with LogicalPlan

use of io.crate.planner.operators.LogicalPlan in project crate by crate.

the class MoveOrderBeneathUnion method apply.

@Override
public LogicalPlan apply(Order order, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
    Union union = captures.get(unionCapture);
    List<LogicalPlan> unionSources = union.sources();
    assert unionSources.size() == 2 : "A UNION must have exactly 2 unionSources";
    Order lhsOrder = updateSources(order, unionSources.get(0));
    Order rhsOrder = updateSources(order, unionSources.get(1));
    return union.replaceSources(List.of(lhsOrder, rhsOrder));
}
Also used : Order(io.crate.planner.operators.Order) LogicalPlan(io.crate.planner.operators.LogicalPlan) Union(io.crate.planner.operators.Union)

Aggregations

LogicalPlan (io.crate.planner.operators.LogicalPlan)28 Symbol (io.crate.expression.symbol.Symbol)12 CrateDummyClusterServiceUnitTest (io.crate.test.integration.CrateDummyClusterServiceUnitTest)11 Test (org.junit.Test)11 Filter (io.crate.planner.operators.Filter)9 TableStats (io.crate.statistics.TableStats)7 WindowFunction (io.crate.expression.symbol.WindowFunction)6 WindowAgg (io.crate.planner.operators.WindowAgg)6 ArrayList (java.util.ArrayList)5 SelectSymbol (io.crate.expression.symbol.SelectSymbol)4 List (java.util.List)4 Reference (io.crate.metadata.Reference)3 ExecutionPlan (io.crate.planner.ExecutionPlan)3 DocTableRelation (io.crate.analyze.relations.DocTableRelation)2 VisibleForTesting (io.crate.common.annotations.VisibleForTesting)2 Row (io.crate.data.Row)2 Row1 (io.crate.data.Row1)2 RowConsumer (io.crate.data.RowConsumer)2 UnsupportedFeatureException (io.crate.exceptions.UnsupportedFeatureException)2 NodeOperationTree (io.crate.execution.dsl.phases.NodeOperationTree)2