| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.drill.exec.planner.logical; |
| |
| import org.apache.calcite.plan.RelOptCluster; |
| import org.apache.calcite.plan.RelOptCost; |
| import org.apache.calcite.plan.RelOptPlanner; |
| import org.apache.calcite.plan.RelTraitSet; |
| import org.apache.calcite.rel.RelNode; |
| import org.apache.calcite.rel.core.JoinInfo; |
| import org.apache.calcite.rel.core.JoinRelType; |
| import org.apache.calcite.rel.metadata.RelMdUtil; |
| import org.apache.calcite.rel.metadata.RelMetadataQuery; |
| import org.apache.calcite.rex.RexNode; |
| import org.apache.calcite.util.Pair; |
| import org.apache.drill.common.expression.FieldReference; |
| import org.apache.drill.common.logical.data.Join; |
| import org.apache.drill.common.logical.data.JoinCondition; |
| import org.apache.drill.common.logical.data.LogicalOperator; |
| import org.apache.drill.common.logical.data.LogicalSemiJoin; |
| import org.apache.drill.exec.planner.common.DrillJoinRelBase; |
| import com.google.common.collect.Lists; |
| import com.google.common.base.Preconditions; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class DrillSemiJoinRel extends DrillJoinRelBase implements DrillJoin, DrillRel { |
| |
| public DrillSemiJoinRel( |
| RelOptCluster cluster, |
| RelTraitSet traitSet, |
| RelNode left, |
| RelNode right, |
| RexNode condition, |
| List<Integer> leftKeys, |
| List<Integer> rightKeys) { |
| super(cluster, |
| traitSet, |
| left, |
| right, |
| condition, |
| JoinRelType.SEMI); |
| this.leftKeys = leftKeys; |
| this.rightKeys = rightKeys; |
| } |
| |
| public static DrillSemiJoinRel create(RelNode left, RelNode right, RexNode condition, |
| List<Integer> leftKeys, List<Integer> rightKeys) { |
| final RelOptCluster cluster = left.getCluster(); |
| return new DrillSemiJoinRel(cluster, cluster.traitSetOf(DrillRel.DRILL_LOGICAL), left, |
| right, condition, leftKeys, rightKeys); |
| } |
| |
| @Override |
| public DrillSemiJoinRel copy(RelTraitSet traitSet, RexNode condition, |
| RelNode left, RelNode right, JoinRelType joinType, boolean semiJoinDone) { |
| Preconditions.checkArgument(joinType == JoinRelType.SEMI); |
| final JoinInfo joinInfo = JoinInfo.of(left, right, condition); |
| Preconditions.checkArgument(joinInfo.isEqui()); |
| return new DrillSemiJoinRel(getCluster(), traitSet, left, right, condition, |
| joinInfo.leftKeys, joinInfo.rightKeys); |
| } |
| |
| @Override |
| public LogicalOperator implement(DrillImplementor implementor) { |
| List<String> fields = new ArrayList<>(); |
| fields.addAll(getInput(0).getRowType().getFieldNames()); |
| fields.addAll(getInput(1).getRowType().getFieldNames()); |
| Preconditions.checkArgument(DrillJoinRel.isUnique(fields)); |
| final int leftCount = left.getRowType().getFieldCount(); |
| final List<String> leftFields = fields.subList(0, leftCount); |
| final List<String> rightFields = fields.subList(leftCount, leftCount + right.getRowType().getFieldCount()); |
| |
| final LogicalOperator leftOp = DrillJoinRel.implementInput(implementor, 0, 0, left, this, fields); |
| final LogicalOperator rightOp = DrillJoinRel.implementInput(implementor, 1, leftCount, right, this, fields); |
| |
| Join.Builder builder = Join.builder(); |
| builder.type(joinType); |
| builder.left(leftOp); |
| builder.right(rightOp); |
| List<JoinCondition> conditions = Lists.newArrayList(); |
| for (Pair<Integer, Integer> pair : Pair.zip(leftKeys, rightKeys)) { |
| conditions.add(new JoinCondition(DrillJoinRel.EQUALITY_CONDITION, |
| new FieldReference(leftFields.get(pair.left)), new FieldReference(rightFields.get(pair.right)))); |
| } |
| |
| return new LogicalSemiJoin(leftOp, rightOp, conditions, joinType); |
| } |
| |
| @Override |
| public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { |
| return computeLogicalJoinCost(planner, mq); |
| } |
| |
| @Override |
| public double estimateRowCount(RelMetadataQuery mq) { |
| RexNode semiJoinSelectivity = |
| RelMdUtil.makeSemiJoinSelectivityRexNode(mq, this); |
| Double selectivity = mq.getSelectivity(getLeft(), semiJoinSelectivity); |
| return selectivity * mq.getRowCount(getLeft()); |
| } |
| } |