Search in sources :

Example 6 with RelationName

use of io.crate.metadata.RelationName in project crate by crate.

the class JoinPlanBuilder method joinWithNext.

private static LogicalPlan joinWithNext(Function<AnalyzedRelation, LogicalPlan> plan, LogicalPlan source, AnalyzedRelation nextRel, Set<RelationName> joinNames, Map<Set<RelationName>, JoinPair> joinPairs, Map<Set<RelationName>, Symbol> queryParts, AnalyzedRelation leftRelation, boolean hashJoinEnabled) {
    RelationName nextName = nextRel.relationName();
    JoinPair joinPair = removeMatch(joinPairs, joinNames, nextName);
    final JoinType type;
    final Symbol condition;
    if (joinPair == null) {
        type = JoinType.CROSS;
        condition = null;
    } else {
        type = maybeInvertPair(nextName, joinPair);
        condition = joinPair.condition();
    }
    LogicalPlan nextPlan = plan.apply(nextRel);
    Symbol query = AndOperator.join(Stream.of(removeMatch(queryParts, joinNames, nextName), queryParts.remove(Collections.singleton(nextName))).filter(Objects::nonNull).iterator());
    return Filter.create(createJoinPlan(source, nextPlan, type, condition, leftRelation, nextRel, query, hashJoinEnabled), query);
}
Also used : Symbol(io.crate.expression.symbol.Symbol) Objects(java.util.Objects) RelationName(io.crate.metadata.RelationName) JoinType(io.crate.planner.node.dql.join.JoinType) JoinPair(io.crate.analyze.relations.JoinPair)

Example 7 with RelationName

use of io.crate.metadata.RelationName in project crate by crate.

the class JoinPlanBuilder method buildJoinTree.

static LogicalPlan buildJoinTree(List<AnalyzedRelation> from, Symbol whereClause, List<JoinPair> joinPairs, Function<AnalyzedRelation, LogicalPlan> plan, boolean hashJoinEnabled) {
    if (from.size() == 1) {
        return Filter.create(plan.apply(from.get(0)), whereClause);
    }
    Map<Set<RelationName>, Symbol> queryParts = QuerySplitter.split(whereClause);
    List<JoinPair> allJoinPairs = JoinOperations.convertImplicitJoinConditionsToJoinPairs(joinPairs, queryParts);
    boolean optimizeOrder = true;
    for (var joinPair : allJoinPairs) {
        if (hasAdditionalDependencies(joinPair)) {
            optimizeOrder = false;
            break;
        }
    }
    LinkedHashMap<Set<RelationName>, JoinPair> joinPairsByRelations = JoinOperations.buildRelationsToJoinPairsMap(allJoinPairs);
    Iterator<RelationName> it;
    if (optimizeOrder) {
        Collection<RelationName> orderedRelationNames = JoinOrdering.getOrderedRelationNames(Lists2.map(from, AnalyzedRelation::relationName), joinPairsByRelations.keySet(), queryParts.keySet());
        it = orderedRelationNames.iterator();
    } else {
        it = Lists2.map(from, AnalyzedRelation::relationName).iterator();
    }
    final RelationName lhsName = it.next();
    final RelationName rhsName = it.next();
    Set<RelationName> joinNames = new HashSet<>();
    joinNames.add(lhsName);
    joinNames.add(rhsName);
    JoinPair joinLhsRhs = joinPairsByRelations.remove(joinNames);
    final JoinType joinType;
    final Symbol joinCondition;
    if (joinLhsRhs == null) {
        joinType = JoinType.CROSS;
        joinCondition = null;
    } else {
        joinType = maybeInvertPair(rhsName, joinLhsRhs);
        joinCondition = joinLhsRhs.condition();
    }
    Map<RelationName, AnalyzedRelation> sources = from.stream().collect(Collectors.toMap(AnalyzedRelation::relationName, rel -> rel));
    AnalyzedRelation lhs = sources.get(lhsName);
    AnalyzedRelation rhs = sources.get(rhsName);
    LogicalPlan lhsPlan = plan.apply(lhs);
    LogicalPlan rhsPlan = plan.apply(rhs);
    Symbol query = removeParts(queryParts, lhsName, rhsName);
    LogicalPlan joinPlan = createJoinPlan(lhsPlan, rhsPlan, joinType, joinCondition, lhs, rhs, query, hashJoinEnabled);
    joinPlan = Filter.create(joinPlan, query);
    while (it.hasNext()) {
        AnalyzedRelation nextRel = sources.get(it.next());
        joinPlan = joinWithNext(plan, joinPlan, nextRel, joinNames, joinPairsByRelations, queryParts, lhs, hashJoinEnabled);
        joinNames.add(nextRel.relationName());
    }
    if (!queryParts.isEmpty()) {
        joinPlan = Filter.create(joinPlan, AndOperator.join(queryParts.values()));
        queryParts.clear();
    }
    assert joinPairsByRelations.isEmpty() : "Must've applied all joinPairs";
    return joinPlan;
}
Also used : Iterator(java.util.Iterator) RelationName(io.crate.metadata.RelationName) Collection(java.util.Collection) Set(java.util.Set) QuerySplitter(io.crate.analyze.relations.QuerySplitter) Function(java.util.function.Function) Collectors(java.util.stream.Collectors) Lists2(io.crate.common.collections.Lists2) JoinPair(io.crate.analyze.relations.JoinPair) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Objects(java.util.Objects) List(java.util.List) AndOperator(io.crate.expression.operator.AndOperator) Stream(java.util.stream.Stream) JoinType(io.crate.planner.node.dql.join.JoinType) JoinOperations(io.crate.execution.engine.join.JoinOperations) Symbol(io.crate.expression.symbol.Symbol) Map(java.util.Map) AnalyzedRelation(io.crate.analyze.relations.AnalyzedRelation) EquiJoinDetector.isHashJoinPossible(io.crate.planner.operators.EquiJoinDetector.isHashJoinPossible) Collections(java.util.Collections) FieldsVisitor(io.crate.expression.symbol.FieldsVisitor) Nullable(javax.annotation.Nullable) Set(java.util.Set) HashSet(java.util.HashSet) Symbol(io.crate.expression.symbol.Symbol) JoinType(io.crate.planner.node.dql.join.JoinType) AnalyzedRelation(io.crate.analyze.relations.AnalyzedRelation) JoinPair(io.crate.analyze.relations.JoinPair) RelationName(io.crate.metadata.RelationName) HashSet(java.util.HashSet)

Example 8 with RelationName

use of io.crate.metadata.RelationName in project crate by crate.

the class SysTableRegistry method registerSysTable.

public <R> void registerSysTable(TableInfo tableInfo, Supplier<CompletableFuture<? extends Iterable<R>>> iterableSupplier, Map<ColumnIdent, ? extends RowCollectExpressionFactory<R>> expressionFactories, boolean involvesIO) {
    RelationName ident = tableInfo.ident();
    sysSchemaInfo.registerSysTable(tableInfo);
    tableDefinitions.registerTableDefinition(ident, new StaticTableDefinition<>(iterableSupplier, expressionFactories, involvesIO));
}
Also used : RelationName(io.crate.metadata.RelationName)

Example 9 with RelationName

use of io.crate.metadata.RelationName 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 10 with RelationName

use of io.crate.metadata.RelationName in project crate by crate.

the class RewriteToQueryThenFetch method apply.

@Override
public LogicalPlan apply(Limit limit, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
    if (Symbols.containsColumn(limit.outputs(), DocSysColumns.FETCHID)) {
        return null;
    }
    FetchRewrite fetchRewrite = limit.source().rewriteToFetch(tableStats, Set.of());
    if (fetchRewrite == null) {
        return null;
    }
    List<Reference> fetchRefs = fetchRewrite.extractFetchRefs();
    Map<RelationName, FetchSource> fetchSourceByRelation = fetchRewrite.createFetchSources();
    return new Fetch(fetchRewrite.replacedOutputs(), fetchRefs, fetchSourceByRelation, limit.replaceSources(List.of(fetchRewrite.newPlan())));
}
Also used : Fetch(io.crate.planner.operators.Fetch) FetchRewrite(io.crate.planner.operators.FetchRewrite) FetchSource(io.crate.planner.node.fetch.FetchSource) Reference(io.crate.metadata.Reference) RelationName(io.crate.metadata.RelationName)

Aggregations

RelationName (io.crate.metadata.RelationName)180 Test (org.junit.Test)100 CrateDummyClusterServiceUnitTest (io.crate.test.integration.CrateDummyClusterServiceUnitTest)55 PartitionName (io.crate.metadata.PartitionName)47 Symbol (io.crate.expression.symbol.Symbol)42 Reference (io.crate.metadata.Reference)37 ColumnIdent (io.crate.metadata.ColumnIdent)31 AnalyzedRelation (io.crate.analyze.relations.AnalyzedRelation)21 ReferenceIdent (io.crate.metadata.ReferenceIdent)21 DocTableInfo (io.crate.metadata.doc.DocTableInfo)21 Map (java.util.Map)20 HashMap (java.util.HashMap)19 SqlExpressions (io.crate.testing.SqlExpressions)18 ArrayList (java.util.ArrayList)18 List (java.util.List)17 Before (org.junit.Before)17 DocTableRelation (io.crate.analyze.relations.DocTableRelation)13 SQLExecutor (io.crate.testing.SQLExecutor)11 CoordinatorTxnCtx (io.crate.metadata.CoordinatorTxnCtx)10 IndexTemplateMetadata (org.elasticsearch.cluster.metadata.IndexTemplateMetadata)10