You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by GitBox <gi...@apache.org> on 2022/07/05 08:49:17 UTC

[GitHub] [calcite] chunweilei commented on a diff in pull request #2848: [CALCITE-5201] Improve SemiJoinRule to match Join's right input which is unique for Join keys

chunweilei commented on code in PR #2848:
URL: https://github.com/apache/calcite/pull/2848#discussion_r913543258


##########
core/src/main/java/org/apache/calcite/rel/rules/SemiJoinRule.java:
##########
@@ -232,6 +237,79 @@ default JoinToSemiJoinRuleConfig withOperandFor(Class<Join> joinClass,
     }
   }
 
+  /**
+   * SemiJoinRule that matches a Join with a RelNode which is unique
+   * for Join's right keys.
+   *
+   * @see CoreRules#JOIN_ON_UNIQUE_TO_SEMI_JOIN */
+  public static class JoinOnUniqueToSemiJoinRule extends SemiJoinRule {
+
+    /** Creates a JoinOnUniqueToSemiJoinRule. */
+    protected JoinOnUniqueToSemiJoinRule(JoinOnUniqueToSemiJoinRuleConfig config) {
+      super(config);
+    }
+
+    @Override public void onMatch(RelOptRuleCall call) {
+      final Project project = call.rel(0);
+      final Join join = call.rel(1);
+      final RelNode left = call.rel(2);
+      final RelNode right = call.rel(3);
+
+      // return if right's fields are used.
+      final ImmutableBitSet bits =
+          RelOptUtil.InputFinder.bits(project.getProjects(), null);
+      final ImmutableBitSet rightBits =
+          ImmutableBitSet.range(left.getRowType().getFieldCount(),
+              join.getRowType().getFieldCount());
+      if (bits.intersects(rightBits)) {
+        return;
+      }
+
+      final JoinInfo joinInfo = join.analyzeCondition();
+      final RelOptCluster cluster = join.getCluster();
+      final RelMetadataQuery mq = cluster.getMetadataQuery();
+      final Boolean unique = mq.areColumnsUnique(right, joinInfo.rightSet());
+      if (unique != null && unique) {
+        final RelBuilder builder = call.builder();
+        switch (join.getJoinType()) {
+        case INNER:
+        case SEMI:
+          builder.push(left);
+          builder.push(right);
+          builder.join(JoinRelType.SEMI, join.getCondition());
+          break;
+        case LEFT:
+          builder.push(left);
+          break;
+        default:
+          throw new AssertionError(join.getJoinType());
+        }
+        builder.project(project.getProjects());
+        call.transformTo(builder.build());
+      }
+    }
+
+    /**
+     * Rule configuration.
+     */
+    @Value.Immutable
+    public interface JoinOnUniqueToSemiJoinRuleConfig extends SemiJoinRule.Config {
+      JoinOnUniqueToSemiJoinRuleConfig DEFAULT = ImmutableJoinOnUniqueToSemiJoinRuleConfig.of()
+          .withDescription("SemiJoinRule:unique")
+          .withOperandSupplier(b ->
+              b.operand(Project.class).oneInput(
+                  b2 -> b2.operand(Join.class).predicate(SemiJoinRule::isJoinTypeSupported).inputs(
+                      b3 -> b3.operand(RelNode.class).anyInputs(),
+                      b4 -> b4.operand(RelNode.class).anyInputs()

Review Comment:
   Is it necessary to capture the join's input?



##########
core/src/main/java/org/apache/calcite/rel/rules/SemiJoinRule.java:
##########
@@ -232,6 +237,79 @@ default JoinToSemiJoinRuleConfig withOperandFor(Class<Join> joinClass,
     }
   }
 
+  /**
+   * SemiJoinRule that matches a Join with a RelNode which is unique
+   * for Join's right keys.
+   *
+   * @see CoreRules#JOIN_ON_UNIQUE_TO_SEMI_JOIN */
+  public static class JoinOnUniqueToSemiJoinRule extends SemiJoinRule {

Review Comment:
   The comment should be 'SemiJoinRule that matches a Project on top of a Join xxxx'.



##########
core/src/main/java/org/apache/calcite/rel/rules/SemiJoinRule.java:
##########
@@ -42,14 +43,18 @@
 /**
  * Planner rule that creates a {@code SemiJoin} from a
  * {@link org.apache.calcite.rel.core.Join} on top of a
- * {@link org.apache.calcite.rel.logical.LogicalAggregate}.
+ * {@link org.apache.calcite.rel.logical.LogicalAggregate} or
+ * on a {@link org.apache.calcite.rel.RelNode} which is
+ * unique for join's right keys.
  */
 public abstract class SemiJoinRule
     extends RelRule<SemiJoinRule.Config>
     implements TransformationRule {
   private static boolean isJoinTypeSupported(Join join) {
     final JoinRelType type = join.getJoinType();
-    return type == JoinRelType.INNER || type == JoinRelType.LEFT;
+    return type == JoinRelType.INNER
+        || type == JoinRelType.LEFT
+        || type == JoinRelType.SEMI;
   }

Review Comment:
   If it is already a semi join, do we still need to convert it?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@calcite.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org