use of org.apache.calcite.rel.core.JoinInfo in project hive by apache.
the class EstimateUniqueKeys method getUniqueKeys.
private static Set<ImmutableBitSet> getUniqueKeys(HiveJoin rel) {
RelNode left = getRelNode(rel.getLeft());
RelNode right = getRelNode(rel.getRight());
// first add the different combinations of concatenated unique keys
// from the left and the right, adjusting the right hand side keys to
// reflect the addition of the left hand side
//
// NOTE zfong 12/18/06 - If the number of tables in a join is large,
// the number of combinations of unique key sets will explode. If
// that is undesirable, use RelMetadataQuery.areColumnsUnique() as
// an alternative way of getting unique key information.
final Set<ImmutableBitSet> retSet = new HashSet<>();
final Set<ImmutableBitSet> leftSet = getUniqueKeys(left);
Set<ImmutableBitSet> rightSet = null;
final Set<ImmutableBitSet> tmpRightSet = getUniqueKeys(right);
int nFieldsOnLeft = left.getRowType().getFieldCount();
if (tmpRightSet != null) {
rightSet = new HashSet<>();
for (ImmutableBitSet colMask : tmpRightSet) {
ImmutableBitSet.Builder tmpMask = ImmutableBitSet.builder();
for (int bit : colMask) {
tmpMask.set(bit + nFieldsOnLeft);
}
rightSet.add(tmpMask.build());
}
if (leftSet != null) {
for (ImmutableBitSet colMaskRight : rightSet) {
for (ImmutableBitSet colMaskLeft : leftSet) {
retSet.add(colMaskLeft.union(colMaskRight));
}
}
}
}
// locate the columns that participate in equijoins
final JoinInfo joinInfo = rel.analyzeCondition();
RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
// determine if either or both the LHS and RHS are unique on the
// equijoin columns
final Boolean leftUnique = mq.areColumnsUnique(left, joinInfo.leftSet());
final Boolean rightUnique = mq.areColumnsUnique(right, joinInfo.rightSet());
// generating
if ((rightUnique != null) && rightUnique && (leftSet != null) && !(rel.getJoinType().generatesNullsOnLeft())) {
retSet.addAll(leftSet);
}
// same as above except left and right are reversed
if ((leftUnique != null) && leftUnique && (rightSet != null) && !(rel.getJoinType().generatesNullsOnRight())) {
retSet.addAll(rightSet);
}
return retSet;
}
use of org.apache.calcite.rel.core.JoinInfo in project hive by apache.
the class HiveSemiJoinRule method perform.
protected void perform(RelOptRuleCall call, ImmutableBitSet topRefs, RelNode topOperator, Join join, RelNode left, Aggregate aggregate) {
LOG.debug("Matched HiveSemiJoinRule");
final RelOptCluster cluster = join.getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
final ImmutableBitSet rightBits = ImmutableBitSet.range(left.getRowType().getFieldCount(), join.getRowType().getFieldCount());
if (topRefs.intersects(rightBits)) {
return;
}
final JoinInfo joinInfo = join.analyzeCondition();
if (!joinInfo.rightSet().equals(ImmutableBitSet.range(aggregate.getGroupCount()))) {
// By the way, neither a super-set nor a sub-set would work.
return;
}
if (join.getJoinType() == JoinRelType.LEFT) {
// since for LEFT join we are only interested in rows from LEFT we can get rid of right side
call.transformTo(topOperator.copy(topOperator.getTraitSet(), ImmutableList.of(left)));
return;
}
if (join.getJoinType() != JoinRelType.INNER) {
return;
}
if (!joinInfo.isEqui()) {
return;
}
LOG.debug("All conditions matched for HiveSemiJoinRule. Going to apply transformation.");
final List<Integer> newRightKeyBuilder = Lists.newArrayList();
final List<Integer> aggregateKeys = aggregate.getGroupSet().asList();
for (int key : joinInfo.rightKeys) {
newRightKeyBuilder.add(aggregateKeys.get(key));
}
final ImmutableIntList newRightKeys = ImmutableIntList.copyOf(newRightKeyBuilder);
final RelNode newRight = aggregate.getInput();
final RexNode newCondition = RelOptUtil.createEquiJoinCondition(left, joinInfo.leftKeys, newRight, newRightKeys, rexBuilder);
RelNode semi = null;
// is not expected further down the pipeline. see jira for more details
if (aggregate.getInput() instanceof HepRelVertex && ((HepRelVertex) aggregate.getInput()).getCurrentRel() instanceof Join) {
Join rightJoin = (Join) (((HepRelVertex) aggregate.getInput()).getCurrentRel());
List<RexNode> projects = new ArrayList<>();
for (int i = 0; i < rightJoin.getRowType().getFieldCount(); i++) {
projects.add(rexBuilder.makeInputRef(rightJoin, i));
}
RelNode topProject = call.builder().push(rightJoin).project(projects, rightJoin.getRowType().getFieldNames(), true).build();
semi = call.builder().push(left).push(topProject).semiJoin(newCondition).build();
} else {
semi = call.builder().push(left).push(aggregate.getInput()).semiJoin(newCondition).build();
}
call.transformTo(topOperator.copy(topOperator.getTraitSet(), ImmutableList.of(semi)));
}
use of org.apache.calcite.rel.core.JoinInfo in project hive by apache.
the class HiveAggregateJoinTransposeRule method isGroupingUnique.
/**
* Determines weather the give grouping is unique.
*
* Consider a join which might produce non-unique rows; but later the results are aggregated again.
* This method determines if there are sufficient columns in the grouping which have been present previously as unique column(s).
*/
private boolean isGroupingUnique(RelNode input, ImmutableBitSet groups) {
if (groups.isEmpty()) {
return false;
}
if (input instanceof HepRelVertex) {
HepRelVertex vertex = (HepRelVertex) input;
return isGroupingUnique(vertex.getCurrentRel(), groups);
}
RelMetadataQuery mq = input.getCluster().getMetadataQuery();
Set<ImmutableBitSet> uKeys = mq.getUniqueKeys(input);
if (uKeys == null) {
return false;
}
for (ImmutableBitSet u : uKeys) {
if (groups.contains(u)) {
return true;
}
}
if (input instanceof Join) {
Join join = (Join) input;
JoinInfo ji = JoinInfo.of(join.getLeft(), join.getRight(), join.getCondition());
if (ji.isEqui()) {
ImmutableBitSet newGroup = groups.intersect(InputFinder.bits(join.getCondition()));
RelNode l = join.getLeft();
RelNode r = join.getRight();
int joinFieldCount = join.getRowType().getFieldCount();
int lFieldCount = l.getRowType().getFieldCount();
ImmutableBitSet groupL = newGroup.get(0, lFieldCount);
ImmutableBitSet groupR = newGroup.get(lFieldCount, joinFieldCount).shift(-lFieldCount);
if (isGroupingUnique(l, groupL)) {
return true;
}
if (isGroupingUnique(r, groupR)) {
return true;
}
}
}
if (input instanceof Project) {
Project project = (Project) input;
ImmutableBitSet.Builder newGroup = ImmutableBitSet.builder();
for (int g : groups.asList()) {
RexNode rex = project.getProjects().get(g);
if (rex instanceof RexInputRef) {
RexInputRef rexInputRef = (RexInputRef) rex;
newGroup.set(rexInputRef.getIndex());
}
}
return isGroupingUnique(project.getInput(), newGroup.build());
}
return false;
}
use of org.apache.calcite.rel.core.JoinInfo in project hive by apache.
the class HiveSemiJoin method copy.
@Override
public HiveSemiJoin copy(RelTraitSet traitSet, RexNode condition, RelNode left, RelNode right, JoinRelType joinType, boolean semiJoinDone) {
try {
final JoinInfo joinInfo = JoinInfo.of(left, right, condition);
HiveSemiJoin semijoin = new HiveSemiJoin(getCluster(), traitSet, left, right, condition);
// If available, copy state to registry for optimization rules
HiveRulesRegistry registry = semijoin.getCluster().getPlanner().getContext().unwrap(HiveRulesRegistry.class);
if (registry != null) {
registry.copyPushedPredicates(this, semijoin);
}
return semijoin;
} catch (InvalidRelException | CalciteSemanticException e) {
// internal error.
throw new AssertionError(e);
}
}
use of org.apache.calcite.rel.core.JoinInfo in project calcite by apache.
the class EnumerableMergeJoinRule method convert.
@Override
public RelNode convert(RelNode rel) {
LogicalJoin join = (LogicalJoin) rel;
final JoinInfo info = JoinInfo.of(join.getLeft(), join.getRight(), join.getCondition());
if (join.getJoinType() != JoinRelType.INNER) {
// (It supports non-equi join, using a post-filter; see below.)
return null;
}
if (info.pairs().size() == 0) {
// EnumerableMergeJoin CAN support cartesian join, but disable it for now.
return null;
}
final List<RelNode> newInputs = Lists.newArrayList();
final List<RelCollation> collations = Lists.newArrayList();
int offset = 0;
for (Ord<RelNode> ord : Ord.zip(join.getInputs())) {
RelTraitSet traits = ord.e.getTraitSet().replace(EnumerableConvention.INSTANCE);
if (!info.pairs().isEmpty()) {
final List<RelFieldCollation> fieldCollations = Lists.newArrayList();
for (int key : info.keys().get(ord.i)) {
fieldCollations.add(new RelFieldCollation(key, RelFieldCollation.Direction.ASCENDING, RelFieldCollation.NullDirection.LAST));
}
final RelCollation collation = RelCollations.of(fieldCollations);
collations.add(RelCollations.shift(collation, offset));
traits = traits.replace(collation);
}
newInputs.add(convert(ord.e, traits));
offset += ord.e.getRowType().getFieldCount();
}
final RelNode left = newInputs.get(0);
final RelNode right = newInputs.get(1);
final RelOptCluster cluster = join.getCluster();
RelNode newRel;
try {
RelTraitSet traits = join.getTraitSet().replace(EnumerableConvention.INSTANCE);
if (!collations.isEmpty()) {
traits = traits.replace(collations);
}
newRel = new EnumerableMergeJoin(cluster, traits, left, right, info.getEquiCondition(left, right, cluster.getRexBuilder()), info.leftKeys, info.rightKeys, join.getVariablesSet(), join.getJoinType());
} catch (InvalidRelException e) {
EnumerableRules.LOGGER.debug(e.toString());
return null;
}
if (!info.isEqui()) {
newRel = new EnumerableFilter(cluster, newRel.getTraitSet(), newRel, info.getRemaining(cluster.getRexBuilder()));
}
return newRel;
}
Aggregations