use of org.apache.calcite.rel.core.Join in project hive by apache.
the class HiveJoinSwapConstraintsRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final Join topJoin = call.rel(0);
final Join bottomJoin = call.rel(1);
final RexBuilder rexBuilder = topJoin.getCluster().getRexBuilder();
// 1) Check whether these joins can be swapped.
if (topJoin.getJoinType().generatesNullsOnLeft() || bottomJoin.getJoinType().generatesNullsOnLeft() || bottomJoin.isSemiJoin()) {
// Nothing to do
return;
}
// 2) Check whether the bottom is a non-filtering column appending join.
// - If the top one is a non-filtering column appending join, we do not
// trigger the optimization, since we do not want to swap this type of
// joins.
// - If the bottom one is not a non-filtering column appending join,
// we cannot trigger the optimization.
RewritablePKFKJoinInfo topInfo = HiveRelOptUtil.isRewritablePKFKJoin(topJoin, topJoin.getLeft(), topJoin.getRight(), call.getMetadataQuery());
RewritablePKFKJoinInfo bottomInfo = HiveRelOptUtil.isRewritablePKFKJoin(bottomJoin, bottomJoin.getLeft(), bottomJoin.getRight(), call.getMetadataQuery());
if (topInfo.rewritable || !bottomInfo.rewritable) {
// Nothing to do
return;
}
// 3) Rewrite.
// X is the left child of the join below
// Y is the right child of the join below
// Z is the right child of the top join
int nFieldsX = bottomJoin.getLeft().getRowType().getFieldList().size();
int nFieldsY = bottomJoin.getRight().getRowType().getFieldList().size();
int nFieldsZ = topJoin.getRight().getRowType().getFieldList().size();
int nTotalFields = nFieldsX + nFieldsY + nFieldsZ;
List<RelDataTypeField> fields = new ArrayList<>();
// create a list of fields for the full join result; note that
// we can't simply use the fields because the row-type of a
// semi-join would only include the left hand side fields
List<RelDataTypeField> joinFields = topJoin.getRowType().getFieldList();
for (int i = 0; i < (nFieldsX + nFieldsY); i++) {
fields.add(joinFields.get(i));
}
joinFields = topJoin.getRight().getRowType().getFieldList();
for (int i = 0; i < nFieldsZ; i++) {
fields.add(joinFields.get(i));
}
// determine which operands below the join are the actual
// rels that participate in it
final Set<Integer> leftKeys = HiveCalciteUtil.getInputRefs(topJoin.getCondition());
leftKeys.removeIf(i -> i >= topJoin.getLeft().getRowType().getFieldCount());
int nKeysFromX = 0;
for (int leftKey : leftKeys) {
if (leftKey < nFieldsX) {
nKeysFromX++;
}
}
// the keys must all originate from the left
if (nKeysFromX != leftKeys.size()) {
// Nothing to do
return;
}
// need to convert the conditions
// (X, Y, Z) --> (X, Z, Y)
int[] adjustments = new int[nTotalFields];
setJoinAdjustments(adjustments, nFieldsX, nFieldsY, nFieldsZ, nFieldsZ, -nFieldsY);
final RexNode newBottomCondition = topJoin.getCondition().accept(new RelOptUtil.RexInputConverter(rexBuilder, fields, adjustments));
// create the new joins
final Join newBottomJoin = topJoin.copy(topJoin.getTraitSet(), newBottomCondition, bottomJoin.getLeft(), topJoin.getRight(), topJoin.getJoinType(), topJoin.isSemiJoinDone());
final RexNode newTopCondition;
if (newBottomJoin.isSemiJoin()) {
newTopCondition = bottomJoin.getCondition();
} else {
newTopCondition = bottomJoin.getCondition().accept(new RelOptUtil.RexInputConverter(rexBuilder, fields, adjustments));
}
final Join newTopJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newTopCondition, newBottomJoin, bottomJoin.getRight(), bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
if (newBottomJoin.isSemiJoin()) {
call.transformTo(newTopJoin);
} else {
// need to swap the columns to match the original join
// (X, Y, Z) --> (X, Z, Y)
List<RexNode> exprs = new ArrayList<>();
for (int i = 0; i < nFieldsX; i++) {
exprs.add(rexBuilder.makeInputRef(newTopJoin, i));
}
for (int i = nFieldsX + nFieldsZ; i < topJoin.getRowType().getFieldCount(); i++) {
exprs.add(rexBuilder.makeInputRef(newTopJoin, i));
}
for (int i = nFieldsX; i < nFieldsX + nFieldsZ; i++) {
exprs.add(rexBuilder.makeInputRef(newTopJoin, i));
}
call.transformTo(call.builder().push(newTopJoin).project(exprs).build());
}
}
use of org.apache.calcite.rel.core.Join in project hive by apache.
the class HiveProjectJoinTransposeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
Project origProj = call.rel(0);
final Join join = call.rel(1);
if (join.getJoinType() == JoinRelType.SEMI || join.getJoinType() == JoinRelType.ANTI) {
// TODO: support SemiJoin
return;
}
// locate all fields referenced in the projection and join condition;
// determine which inputs are referenced in the projection and
// join condition; if all fields are being referenced and there are no
// special expressions, no point in proceeding any further
PushProjector pushProject = new PushProjector(origProj, join.getCondition(), join, preserveExprCondition, call.builder());
if (pushProject.locateAllRefs()) {
return;
}
// create left and right projections, projecting only those
// fields referenced on each side
RelNode leftProjRel = pushProject.createProjectRefsAndExprs(join.getLeft(), true, false);
RelNode rightProjRel = pushProject.createProjectRefsAndExprs(join.getRight(), true, true);
// convert the join condition to reference the projected columns
RexNode newJoinFilter = null;
int[] adjustments = pushProject.getAdjustments();
if (join.getCondition() != null) {
List<RelDataTypeField> projJoinFieldList = new ArrayList<>();
projJoinFieldList.addAll(join.getSystemFieldList());
projJoinFieldList.addAll(leftProjRel.getRowType().getFieldList());
projJoinFieldList.addAll(rightProjRel.getRowType().getFieldList());
newJoinFilter = pushProject.convertRefsAndExprs(join.getCondition(), projJoinFieldList, adjustments);
}
// create a new join with the projected children
Join newJoinRel = join.copy(join.getTraitSet(), newJoinFilter, leftProjRel, rightProjRel, join.getJoinType(), join.isSemiJoinDone());
// put the original project on top of the join, converting it to
// reference the modified projection list
RelNode topProject = pushProject.createNewProject(newJoinRel, adjustments);
call.transformTo(topProject);
}
use of org.apache.calcite.rel.core.Join in project hive by apache.
the class HiveRemoveGBYSemiJoinRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final Join join = call.rel(0);
if (join.getJoinType() != JoinRelType.SEMI && join.getJoinType() != JoinRelType.ANTI) {
return;
}
final RelNode left = call.rel(1);
final Aggregate rightAggregate = call.rel(2);
// if grouping sets are involved do early return
if (rightAggregate.getGroupType() != Aggregate.Group.SIMPLE) {
return;
}
if (rightAggregate.indicator) {
return;
}
// if there is any aggregate function this group by is not un-necessary
if (!rightAggregate.getAggCallList().isEmpty()) {
return;
}
JoinPredicateInfo joinPredInfo;
try {
joinPredInfo = HiveCalciteUtil.JoinPredicateInfo.constructJoinPredicateInfo(join);
} catch (CalciteSemanticException e) {
LOG.warn("Exception while extracting predicate info from {}", join);
return;
}
if (!joinPredInfo.getNonEquiJoinPredicateElements().isEmpty()) {
return;
}
ImmutableBitSet.Builder rightKeys = ImmutableBitSet.builder();
for (JoinLeafPredicateInfo leftPredInfo : joinPredInfo.getEquiJoinPredicateElements()) {
rightKeys.addAll(leftPredInfo.getProjsFromRightPartOfJoinKeysInChildSchema());
}
boolean shouldTransform = rightKeys.build().equals(ImmutableBitSet.range(rightAggregate.getGroupCount()));
if (shouldTransform) {
final RelBuilder relBuilder = call.builder();
RelNode newRightInput = relBuilder.project(relBuilder.push(rightAggregate.getInput()).fields(rightAggregate.getGroupSet().asList())).build();
RelNode newJoin;
if (join.getJoinType() == JoinRelType.SEMI) {
newJoin = call.builder().push(left).push(newRightInput).semiJoin(join.getCondition()).build();
} else {
newJoin = call.builder().push(left).push(newRightInput).antiJoin(join.getCondition()).build();
}
call.transformTo(newJoin);
}
}
use of org.apache.calcite.rel.core.Join in project hive by apache.
the class HiveSemiJoinProjectTransposeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
Join semiJoin = call.rel(0);
Project project = call.rel(1);
// Convert the LHS semi-join keys to reference the child projection
// expression; all projection expressions must be RexInputRefs,
// otherwise, we wouldn't have created this semi-join.
// convert the semijoin condition to reflect the LHS with the project
// pulled up
RexNode newCondition = adjustCondition(project, semiJoin);
Join newSemiJoin = HiveSemiJoin.getSemiJoin(project.getCluster(), project.getTraitSet(), project.getInput(), semiJoin.getRight(), newCondition);
// Create the new projection. Note that the projection expressions
// are the same as the original because they only reference the LHS
// of the semijoin and the semijoin only projects out the LHS
final RelBuilder relBuilder = call.builder();
relBuilder.push(newSemiJoin);
relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());
call.transformTo(relBuilder.build());
}
use of org.apache.calcite.rel.core.Join in project hive by apache.
the class HiveAntiSemiJoinRule method perform.
protected void perform(RelOptRuleCall call, Project project, Filter filter, Join join) {
LOG.debug("Start Matching HiveAntiJoinRule");
// https://issues.apache.org/jira/browse/HIVE-23991
if (join.getCondition().isAlwaysTrue()) {
return;
}
// We support conversion from left outer join only.
if (join.getJoinType() != JoinRelType.LEFT) {
return;
}
assert (filter != null);
List<RexNode> filterList = getResidualFilterNodes(filter, join);
if (filterList == null) {
return;
}
// If any projection is there from right side, then we can not convert to anti join.
boolean hasProjection = HiveCalciteUtil.hasAnyExpressionFromRightSide(join, project.getProjects());
if (hasProjection) {
return;
}
LOG.debug("Matched HiveAntiJoinRule");
// Build anti join with same left, right child and condition as original left outer join.
Join anti = HiveAntiJoin.getAntiJoin(join.getLeft().getCluster(), join.getLeft().getTraitSet(), join.getLeft(), join.getRight(), join.getCondition());
RelNode newProject;
if (filterList.isEmpty()) {
newProject = project.copy(project.getTraitSet(), anti, project.getProjects(), project.getRowType());
} else {
// Collate the filter condition using AND as the filter was decomposed based
// on AND condition (RelOptUtil.conjunctions).
RexNode condition = filterList.size() == 1 ? filterList.get(0) : join.getCluster().getRexBuilder().makeCall(SqlStdOperatorTable.AND, filterList);
Filter newFilter = filter.copy(filter.getTraitSet(), anti, condition);
newProject = project.copy(project.getTraitSet(), newFilter, project.getProjects(), project.getRowType());
}
call.transformTo(newProject);
}
Aggregations