Search in sources :

Example 1 with RIGHT

use of org.apache.calcite.rel.core.JoinRelType.RIGHT in project ignite-3 by apache.

the class IgniteMergeJoin method passThroughCollation.

/**
 * {@inheritDoc}
 */
@Override
public Pair<RelTraitSet, List<RelTraitSet>> passThroughCollation(RelTraitSet required, List<RelTraitSet> inputTraits) {
    RelCollation collation = TraitUtils.collation(required);
    RelTraitSet left = inputTraits.get(0);
    RelTraitSet right = inputTraits.get(1);
    if (joinType == FULL) {
        return defaultCollationPair(required, left, right);
    }
    int leftInputFieldCount = this.left.getRowType().getFieldCount();
    List<Integer> reqKeys = RelCollations.ordinals(collation);
    List<Integer> leftKeys = joinInfo.leftKeys.toIntegerList();
    List<Integer> rightKeys = joinInfo.rightKeys.incr(leftInputFieldCount).toIntegerList();
    ImmutableBitSet reqKeySet = ImmutableBitSet.of(reqKeys);
    ImmutableBitSet leftKeySet = ImmutableBitSet.of(joinInfo.leftKeys);
    ImmutableBitSet rightKeySet = ImmutableBitSet.of(rightKeys);
    RelCollation nodeCollation;
    RelCollation leftCollation;
    RelCollation rightCollation;
    if (reqKeySet.equals(leftKeySet)) {
        if (joinType == RIGHT) {
            return defaultCollationPair(required, left, right);
        }
        nodeCollation = collation;
        leftCollation = collation;
        rightCollation = collation.apply(buildTransposeMapping(true));
    } else if (containsOrderless(leftKeys, collation)) {
        if (joinType == RIGHT) {
            return defaultCollationPair(required, left, right);
        }
        // if sort keys are subset of left join keys, we can extend collations to make sure all join
        // keys are sorted.
        nodeCollation = collation;
        leftCollation = extendCollation(collation, leftKeys);
        rightCollation = leftCollation.apply(buildTransposeMapping(true));
    } else if (containsOrderless(collation, leftKeys) && reqKeys.stream().allMatch(i -> i < leftInputFieldCount)) {
        if (joinType == RIGHT) {
            return defaultCollationPair(required, left, right);
        }
        // if sort keys are superset of left join keys, and left join keys is prefix of sort keys
        // (order not matter), also sort keys are all from left join input.
        nodeCollation = collation;
        leftCollation = collation;
        rightCollation = leftCollation.apply(buildTransposeMapping(true));
    } else if (reqKeySet.equals(rightKeySet)) {
        if (joinType == LEFT) {
            return defaultCollationPair(required, left, right);
        }
        nodeCollation = collation;
        rightCollation = RelCollations.shift(collation, -leftInputFieldCount);
        leftCollation = rightCollation.apply(buildTransposeMapping(false));
    } else if (containsOrderless(rightKeys, collation)) {
        if (joinType == LEFT) {
            return defaultCollationPair(required, left, right);
        }
        nodeCollation = collation;
        rightCollation = RelCollations.shift(extendCollation(collation, rightKeys), -leftInputFieldCount);
        leftCollation = rightCollation.apply(buildTransposeMapping(false));
    } else {
        return defaultCollationPair(required, left, right);
    }
    return Pair.of(required.replace(nodeCollation), ImmutableList.of(left.replace(leftCollation), right.replace(rightCollation)));
}
Also used : EMPTY(org.apache.calcite.rel.RelCollations.EMPTY) RelOptCost(org.apache.calcite.plan.RelOptCost) Join(org.apache.calcite.rel.core.Join) ArrayList(java.util.ArrayList) RIGHT(org.apache.calcite.rel.core.JoinRelType.RIGHT) CorrelationId(org.apache.calcite.rel.core.CorrelationId) IgniteCostFactory(org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCostFactory) ImmutableList(com.google.common.collect.ImmutableList) RexNode(org.apache.calcite.rex.RexNode) Pair(org.apache.calcite.util.Pair) RelInputEx(org.apache.ignite.internal.sql.engine.externalize.RelInputEx) RelCollations.containsOrderless(org.apache.calcite.rel.RelCollations.containsOrderless) RelTraitSet(org.apache.calcite.plan.RelTraitSet) RelOptCluster(org.apache.calcite.plan.RelOptCluster) RelCollations(org.apache.calcite.rel.RelCollations) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) RelInput(org.apache.calcite.rel.RelInput) LEFT(org.apache.calcite.rel.core.JoinRelType.LEFT) Set(java.util.Set) FULL(org.apache.calcite.rel.core.JoinRelType.FULL) RelNode(org.apache.calcite.rel.RelNode) RelFieldCollation(org.apache.calcite.rel.RelFieldCollation) Commons(org.apache.ignite.internal.sql.engine.util.Commons) RelWriter(org.apache.calcite.rel.RelWriter) List(java.util.List) TraitUtils(org.apache.ignite.internal.sql.engine.trait.TraitUtils) RelMetadataQuery(org.apache.calcite.rel.metadata.RelMetadataQuery) RelCollation(org.apache.calcite.rel.RelCollation) IgniteCost(org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCost) JoinRelType(org.apache.calcite.rel.core.JoinRelType) RelOptPlanner(org.apache.calcite.plan.RelOptPlanner) RelCollation(org.apache.calcite.rel.RelCollation) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) RelTraitSet(org.apache.calcite.plan.RelTraitSet)

Example 2 with RIGHT

use of org.apache.calcite.rel.core.JoinRelType.RIGHT in project ignite-3 by apache.

the class AbstractIgniteJoin method passThroughDistribution.

/**
 * {@inheritDoc}
 */
@Override
public Pair<RelTraitSet, List<RelTraitSet>> passThroughDistribution(RelTraitSet nodeTraits, List<RelTraitSet> inputTraits) {
    // Tere are several rules:
    // 1) any join is possible on broadcast or single distribution
    // 2) hash distributed join is possible when join keys equal to source distribution keys
    // 3) hash and broadcast distributed tables can be joined when join keys equal to hash
    // distributed table distribution keys and:
    // 3.1) it's a left join and a hash distributed table is at left
    // 3.2) it's a right join and a hash distributed table is at right
    // 3.3) it's an inner join, this case a hash distributed table may be at any side
    RelTraitSet left = inputTraits.get(0);
    RelTraitSet right = inputTraits.get(1);
    IgniteDistribution distribution = TraitUtils.distribution(nodeTraits);
    RelDistribution.Type distrType = distribution.getType();
    switch(distrType) {
        case BROADCAST_DISTRIBUTED:
        case SINGLETON:
            return Pair.of(nodeTraits, Commons.transform(inputTraits, t -> t.replace(distribution)));
        case HASH_DISTRIBUTED:
        case RANDOM_DISTRIBUTED:
            // It's impossible to get random or hash distribution from a cross join.
            if (nullOrEmpty(joinInfo.pairs())) {
                break;
            }
            // We cannot provide random distribution without unique constrain on join keys,
            // so, we require hash distribution (wich satisfies random distribution) instead.
            DistributionFunction function = distrType == HASH_DISTRIBUTED ? distribution.function() : DistributionFunction.hash();
            IgniteDistribution outDistr = hash(joinInfo.leftKeys, function);
            if (distrType != HASH_DISTRIBUTED || outDistr.satisfies(distribution)) {
                return Pair.of(nodeTraits.replace(outDistr), List.of(left.replace(outDistr), right.replace(hash(joinInfo.rightKeys, function))));
            }
            break;
        default:
    }
    return Pair.of(nodeTraits.replace(single()), Commons.transform(inputTraits, t -> t.replace(single())));
}
Also used : DistributionFunction(org.apache.ignite.internal.sql.engine.trait.DistributionFunction) IgniteDistributions.single(org.apache.ignite.internal.sql.engine.trait.IgniteDistributions.single) Mappings(org.apache.calcite.util.mapping.Mappings) CollectionUtils.nullOrEmpty(org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty) HashMap(java.util.HashMap) Join(org.apache.calcite.rel.core.Join) CorrelationTrait(org.apache.ignite.internal.sql.engine.trait.CorrelationTrait) IgniteMdRowCount.joinRowCount(org.apache.ignite.internal.sql.engine.metadata.IgniteMdRowCount.joinRowCount) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) IgniteDistributions.broadcast(org.apache.ignite.internal.sql.engine.trait.IgniteDistributions.broadcast) RIGHT(org.apache.calcite.rel.core.JoinRelType.RIGHT) CorrelationId(org.apache.calcite.rel.core.CorrelationId) RexNode(org.apache.calcite.rex.RexNode) IgniteDistribution(org.apache.ignite.internal.sql.engine.trait.IgniteDistribution) Pair(org.apache.calcite.util.Pair) TraitsAwareIgniteRel(org.apache.ignite.internal.sql.engine.trait.TraitsAwareIgniteRel) Map(java.util.Map) RewindabilityTrait(org.apache.ignite.internal.sql.engine.trait.RewindabilityTrait) RelTraitSet(org.apache.calcite.plan.RelTraitSet) RelOptCluster(org.apache.calcite.plan.RelOptCluster) RelCollations(org.apache.calcite.rel.RelCollations) ImmutableIntList(org.apache.calcite.util.ImmutableIntList) IgniteDistributions.random(org.apache.ignite.internal.sql.engine.trait.IgniteDistributions.random) Set(java.util.Set) SqlExplainLevel(org.apache.calcite.sql.SqlExplainLevel) RelNode(org.apache.calcite.rel.RelNode) IgniteDistributions.hash(org.apache.ignite.internal.sql.engine.trait.IgniteDistributions.hash) RelFieldCollation(org.apache.calcite.rel.RelFieldCollation) Commons(org.apache.ignite.internal.sql.engine.util.Commons) RelWriter(org.apache.calcite.rel.RelWriter) List(java.util.List) TraitUtils(org.apache.ignite.internal.sql.engine.trait.TraitUtils) RelMetadataQuery(org.apache.calcite.rel.metadata.RelMetadataQuery) RelCollation(org.apache.calcite.rel.RelCollation) RelDistribution(org.apache.calcite.rel.RelDistribution) HASH_DISTRIBUTED(org.apache.calcite.rel.RelDistribution.Type.HASH_DISTRIBUTED) JoinRelType(org.apache.calcite.rel.core.JoinRelType) Util(org.apache.calcite.util.Util) RelTraitSet(org.apache.calcite.plan.RelTraitSet) IgniteDistribution(org.apache.ignite.internal.sql.engine.trait.IgniteDistribution) DistributionFunction(org.apache.ignite.internal.sql.engine.trait.DistributionFunction) RelDistribution(org.apache.calcite.rel.RelDistribution)

Example 3 with RIGHT

use of org.apache.calcite.rel.core.JoinRelType.RIGHT in project ignite-3 by apache.

the class MergeJoinExecutionTest method verifyJoin.

/**
 * Creates execution tree and executes it. Then compares the result of the execution with the given one.
 *
 * @param left     Data for left table.
 * @param right    Data for right table.
 * @param joinType Join type.
 * @param expRes   Expected result.
 */
private void verifyJoin(Object[][] left, Object[][] right, JoinRelType joinType, Object[][] expRes) {
    ExecutionContext<Object[]> ctx = executionContext(true);
    RelDataType leftType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class, Integer.class);
    ScanNode<Object[]> leftNode = new ScanNode<>(ctx, leftType, Arrays.asList(left));
    RelDataType rightType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class);
    ScanNode<Object[]> rightNode = new ScanNode<>(ctx, rightType, Arrays.asList(right));
    RelDataType outType;
    if (setOf(SEMI, ANTI).contains(joinType)) {
        outType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class, Integer.class);
    } else {
        outType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class, Integer.class, int.class, String.class);
    }
    MergeJoinNode<Object[]> join = MergeJoinNode.create(ctx, outType, leftType, rightType, joinType, (r1, r2) -> {
        Object o1 = r1[2];
        Object o2 = r2[0];
        if (o1 == null || o2 == null) {
            if (o1 != null) {
                return 1;
            } else if (o2 != null) {
                return -1;
            } else {
                return 0;
            }
        }
        return Integer.compare((Integer) o1, (Integer) o2);
    });
    join.register(asList(leftNode, rightNode));
    RelDataType rowType;
    ProjectNode<Object[]> project;
    if (setOf(SEMI, ANTI).contains(joinType)) {
        rowType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class);
        project = new ProjectNode<>(ctx, rowType, r -> new Object[] { r[0], r[1] });
    } else {
        rowType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class, String.class);
        project = new ProjectNode<>(ctx, rowType, r -> new Object[] { r[0], r[1], r[4] });
    }
    project.register(join);
    RootNode<Object[]> node = new RootNode<>(ctx, rowType);
    node.register(project);
    ArrayList<Object[]> rows = new ArrayList<>();
    while (node.hasNext()) {
        rows.add(node.next());
    }
    assertThat(rows.toArray(EMPTY), equalTo(expRes));
}
Also used : ArrayUtils.asList(org.apache.ignite.internal.util.ArrayUtils.asList) RelDataType(org.apache.calcite.rel.type.RelDataType) LEFT(org.apache.calcite.rel.core.JoinRelType.LEFT) Arrays(java.util.Arrays) ANTI(org.apache.calcite.rel.core.JoinRelType.ANTI) INNER(org.apache.calcite.rel.core.JoinRelType.INNER) SEMI(org.apache.calcite.rel.core.JoinRelType.SEMI) IsEqual.equalTo(org.hamcrest.core.IsEqual.equalTo) Set(java.util.Set) TypeUtils(org.apache.ignite.internal.sql.engine.util.TypeUtils) FULL(org.apache.calcite.rel.core.JoinRelType.FULL) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Test(org.junit.jupiter.api.Test) RIGHT(org.apache.calcite.rel.core.JoinRelType.RIGHT) JoinRelType(org.apache.calcite.rel.core.JoinRelType) ExecutionContext(org.apache.ignite.internal.sql.engine.exec.ExecutionContext) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) ArrayList(java.util.ArrayList) RelDataType(org.apache.calcite.rel.type.RelDataType)

Example 4 with RIGHT

use of org.apache.calcite.rel.core.JoinRelType.RIGHT in project ignite-3 by apache.

the class NestedLoopJoinExecutionTest method verifyJoin.

/**
 * Creates execution tree and executes it. Then compares the result of the execution with the given one.
 *
 * @param left     Data for left table.
 * @param right    Data for right table.
 * @param joinType Join type.
 * @param expRes   Expected result.
 */
private void verifyJoin(Object[][] left, Object[][] right, JoinRelType joinType, Object[][] expRes) {
    ExecutionContext<Object[]> ctx = executionContext(true);
    RelDataType leftType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class, Integer.class);
    ScanNode<Object[]> leftNode = new ScanNode<>(ctx, leftType, Arrays.asList(left));
    RelDataType rightType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class);
    ScanNode<Object[]> rightNode = new ScanNode<>(ctx, rightType, Arrays.asList(right));
    RelDataType outType;
    if (setOf(SEMI, ANTI).contains(joinType)) {
        outType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class, Integer.class);
    } else {
        outType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class, Integer.class, int.class, String.class);
    }
    RowHandler<Object[]> hnd = ctx.rowHandler();
    NestedLoopJoinNode<Object[]> join = NestedLoopJoinNode.create(ctx, outType, leftType, rightType, joinType, (r1, r2) -> getFieldFromBiRows(hnd, 2, r1, r2) == getFieldFromBiRows(hnd, 3, r1, r2));
    join.register(asList(leftNode, rightNode));
    RelDataType rowType;
    ProjectNode<Object[]> project;
    if (setOf(SEMI, ANTI).contains(joinType)) {
        rowType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class);
        project = new ProjectNode<>(ctx, rowType, r -> new Object[] { r[0], r[1] });
    } else {
        rowType = TypeUtils.createRowType(ctx.getTypeFactory(), int.class, String.class, String.class);
        project = new ProjectNode<>(ctx, rowType, r -> new Object[] { r[0], r[1], r[4] });
    }
    project.register(join);
    RootNode<Object[]> node = new RootNode<>(ctx, rowType);
    node.register(project);
    ArrayList<Object[]> rows = new ArrayList<>();
    while (node.hasNext()) {
        rows.add(node.next());
    }
    assertArrayEquals(expRes, rows.toArray(EMPTY));
}
Also used : ArrayUtils.asList(org.apache.ignite.internal.util.ArrayUtils.asList) RelDataType(org.apache.calcite.rel.type.RelDataType) LEFT(org.apache.calcite.rel.core.JoinRelType.LEFT) Arrays(java.util.Arrays) ANTI(org.apache.calcite.rel.core.JoinRelType.ANTI) INNER(org.apache.calcite.rel.core.JoinRelType.INNER) RowHandler(org.apache.ignite.internal.sql.engine.exec.RowHandler) SEMI(org.apache.calcite.rel.core.JoinRelType.SEMI) Set(java.util.Set) TypeUtils(org.apache.ignite.internal.sql.engine.util.TypeUtils) FULL(org.apache.calcite.rel.core.JoinRelType.FULL) ArrayList(java.util.ArrayList) Assertions.assertArrayEquals(org.junit.jupiter.api.Assertions.assertArrayEquals) HashSet(java.util.HashSet) Test(org.junit.jupiter.api.Test) RIGHT(org.apache.calcite.rel.core.JoinRelType.RIGHT) Commons.getFieldFromBiRows(org.apache.ignite.internal.sql.engine.util.Commons.getFieldFromBiRows) JoinRelType(org.apache.calcite.rel.core.JoinRelType) ExecutionContext(org.apache.ignite.internal.sql.engine.exec.ExecutionContext) ArrayList(java.util.ArrayList) RelDataType(org.apache.calcite.rel.type.RelDataType)

Aggregations

ArrayList (java.util.ArrayList)4 Set (java.util.Set)4 JoinRelType (org.apache.calcite.rel.core.JoinRelType)4 RIGHT (org.apache.calcite.rel.core.JoinRelType.RIGHT)4 HashSet (java.util.HashSet)3 FULL (org.apache.calcite.rel.core.JoinRelType.FULL)3 LEFT (org.apache.calcite.rel.core.JoinRelType.LEFT)3 Arrays (java.util.Arrays)2 List (java.util.List)2 RelOptCluster (org.apache.calcite.plan.RelOptCluster)2 RelTraitSet (org.apache.calcite.plan.RelTraitSet)2 RelCollation (org.apache.calcite.rel.RelCollation)2 RelCollations (org.apache.calcite.rel.RelCollations)2 RelFieldCollation (org.apache.calcite.rel.RelFieldCollation)2 RelNode (org.apache.calcite.rel.RelNode)2 RelWriter (org.apache.calcite.rel.RelWriter)2 CorrelationId (org.apache.calcite.rel.core.CorrelationId)2 Join (org.apache.calcite.rel.core.Join)2 ANTI (org.apache.calcite.rel.core.JoinRelType.ANTI)2 INNER (org.apache.calcite.rel.core.JoinRelType.INNER)2