use of org.apache.calcite.rel.metadata.RelColumnOrigin in project calcite by apache.
the class LoptMultiJoin method addRemovableSelfJoinPair.
/**
* Adds to a map that keeps track of removable self-join pairs.
*
* @param factor1 one of the factors in the self-join
* @param factor2 the second factor in the self-join
*/
public void addRemovableSelfJoinPair(int factor1, int factor2) {
int leftFactor;
int rightFactor;
// preserved after the self-join is removed.
if (getNumFieldsInJoinFactor(factor1) > getNumFieldsInJoinFactor(factor2)) {
leftFactor = factor1;
rightFactor = factor2;
} else {
leftFactor = factor2;
rightFactor = factor1;
}
// Compute a column mapping such that if a column from the right
// factor is also referenced in the left factor, we will map the
// right reference to the left to avoid redundant references.
final Map<Integer, Integer> columnMapping = new HashMap<>();
// First, locate the originating column for all simple column
// references in the left factor.
final RelNode left = getJoinFactor(leftFactor);
final RelMetadataQuery mq = left.getCluster().getMetadataQuery();
final Map<Integer, Integer> leftFactorColMapping = new HashMap<>();
for (int i = 0; i < left.getRowType().getFieldCount(); i++) {
final RelColumnOrigin colOrigin = mq.getColumnOrigin(left, i);
if (colOrigin != null) {
leftFactorColMapping.put(colOrigin.getOriginColumnOrdinal(), i);
}
}
// Then, see if the right factor references any of the same columns
// by locating their originating columns. If there are matches,
// then we want to store the corresponding offset into the left
// factor.
RelNode right = getJoinFactor(rightFactor);
for (int i = 0; i < right.getRowType().getFieldCount(); i++) {
final RelColumnOrigin colOrigin = mq.getColumnOrigin(right, i);
if (colOrigin == null) {
continue;
}
Integer leftOffset = leftFactorColMapping.get(colOrigin.getOriginColumnOrdinal());
if (leftOffset == null) {
continue;
}
columnMapping.put(i, leftOffset);
}
RemovableSelfJoin selfJoin = new RemovableSelfJoin(leftFactor, rightFactor, columnMapping);
removableSelfJoinPairs.put(leftFactor, selfJoin);
removableSelfJoinPairs.put(rightFactor, selfJoin);
}
use of org.apache.calcite.rel.metadata.RelColumnOrigin in project calcite by apache.
the class LoptOptimizeJoinRule method areSelfJoinKeysUnique.
/**
* Determines if the equality portion of a self-join condition is between
* identical keys that are unique.
*
* @param mq Metadata query
* @param leftRel left side of the join
* @param rightRel right side of the join
* @param joinFilters the join condition
*
* @return true if the equality join keys are the same and unique
*/
private static boolean areSelfJoinKeysUnique(RelMetadataQuery mq, RelNode leftRel, RelNode rightRel, RexNode joinFilters) {
final JoinInfo joinInfo = JoinInfo.of(leftRel, rightRel, joinFilters);
// corresponding key on the right
for (IntPair pair : joinInfo.pairs()) {
final RelColumnOrigin leftOrigin = mq.getColumnOrigin(leftRel, pair.source);
if (leftOrigin == null) {
return false;
}
final RelColumnOrigin rightOrigin = mq.getColumnOrigin(rightRel, pair.target);
if (rightOrigin == null) {
return false;
}
if (leftOrigin.getOriginColumnOrdinal() != rightOrigin.getOriginColumnOrdinal()) {
return false;
}
}
// it's ok if there are nulls in the unique key.
return RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(mq, leftRel, joinInfo.leftSet());
}
use of org.apache.calcite.rel.metadata.RelColumnOrigin in project calcite by apache.
the class LoptSemiJoinOptimizer method validateKeys.
/**
* Validates the candidate semijoin keys corresponding to the fact table.
* Ensure the keys all originate from the same underlying table, and they
* all correspond to simple column references. If unsuitable keys are found,
* they're removed from the key list and a new list corresponding to the
* remaining valid keys is returned.
*
* @param factRel fact table RelNode
* @param leftKeys fact table semijoin keys
* @param rightKeys dimension table semijoin keys
* @param actualLeftKeys the remaining valid fact table semijoin keys
*
* @return the underlying fact table if the semijoin keys are valid;
* otherwise null
*/
private LcsTable validateKeys(RelNode factRel, List<Integer> leftKeys, List<Integer> rightKeys, List<Integer> actualLeftKeys) {
int keyIdx = 0;
RelOptTable theTable = null;
ListIterator<Integer> keyIter = leftKeys.listIterator();
while (keyIter.hasNext()) {
boolean removeKey = false;
final RelColumnOrigin colOrigin = mq.getColumnOrigin(factRel, keyIter.next());
// can't use the rid column as a semijoin key
if ((colOrigin == null) || LucidDbSpecialOperators.isLcsRidColumnId(colOrigin.getOriginColumnOrdinal())) {
removeKey = true;
} else {
RelOptTable table = colOrigin.getOriginTable();
if (theTable == null) {
if (!(table instanceof LcsTable)) {
// not a column store table
removeKey = true;
} else {
theTable = table;
}
} else {
// a simple origin
assert table == theTable;
}
}
if (!removeKey) {
actualLeftKeys.add(colOrigin.getOriginColumnOrdinal());
keyIdx++;
} else {
keyIter.remove();
rightKeys.remove(keyIdx);
}
}
// keys
if (actualLeftKeys.isEmpty()) {
return null;
} else {
return (LcsTable) theTable;
}
}
use of org.apache.calcite.rel.metadata.RelColumnOrigin in project calcite by apache.
the class RelMetadataTest method checkSingleColumnOrigin.
private void checkSingleColumnOrigin(String sql, String expectedTableName, String expectedColumnName, boolean expectedDerived) {
Set<RelColumnOrigin> result = checkColumnOrigin(sql);
assertTrue(result != null);
assertEquals(1, result.size());
RelColumnOrigin rco = result.iterator().next();
checkColumnOrigin(rco, expectedTableName, expectedColumnName, expectedDerived);
}
use of org.apache.calcite.rel.metadata.RelColumnOrigin in project hive by apache.
the class HiveExpandDistinctAggregatesRule method onMatch.
// ~ Methods ----------------------------------------------------------------
@Override
public void onMatch(RelOptRuleCall call) {
final Aggregate aggregate = call.rel(0);
int numCountDistinct = getNumCountDistinctCall(aggregate);
if (numCountDistinct == 0 || numCountDistinct + aggregate.getGroupCount() >= Long.SIZE || aggregate.getGroupType() != Group.SIMPLE) {
return;
}
// Find all of the agg expressions. We use a List (for all count(distinct))
// as well as a Set (for all others) to ensure determinism.
int nonDistinctCount = 0;
List<List<Integer>> argListList = new ArrayList<List<Integer>>();
Set<List<Integer>> argListSets = new LinkedHashSet<List<Integer>>();
ImmutableBitSet.Builder newGroupSet = ImmutableBitSet.builder();
newGroupSet.addAll(aggregate.getGroupSet());
for (AggregateCall aggCall : aggregate.getAggCallList()) {
if (!aggCall.isDistinct()) {
++nonDistinctCount;
continue;
}
ArrayList<Integer> argList = new ArrayList<Integer>();
for (Integer arg : aggCall.getArgList()) {
argList.add(arg);
newGroupSet.set(arg);
}
// Aggr checks for sorted argList.
argListList.add(argList);
argListSets.add(argList);
}
Preconditions.checkArgument(argListSets.size() > 0, "containsDistinctCall lied");
if (numCountDistinct > 1 && numCountDistinct == aggregate.getAggCallList().size()) {
LOG.debug("Trigger countDistinct rewrite. numCountDistinct is " + numCountDistinct);
// now positions contains all the distinct positions, i.e., $5, $4, $6
// we need to first sort them as group by set
// and then get their position later, i.e., $4->1, $5->2, $6->3
cluster = aggregate.getCluster();
rexBuilder = cluster.getRexBuilder();
try {
call.transformTo(convert(aggregate, argListList, newGroupSet.build()));
} catch (CalciteSemanticException e) {
LOG.debug(e.toString());
throw new RuntimeException(e);
}
return;
}
// If all of the agg expressions are distinct and have the same
// arguments then we can use a more efficient form.
final RelMetadataQuery mq = call.getMetadataQuery();
if ((nonDistinctCount == 0) && (argListSets.size() == 1)) {
for (Integer arg : argListSets.iterator().next()) {
Set<RelColumnOrigin> colOrigs = mq.getColumnOrigins(aggregate.getInput(), arg);
if (null != colOrigs) {
for (RelColumnOrigin colOrig : colOrigs) {
RelOptHiveTable hiveTbl = (RelOptHiveTable) colOrig.getOriginTable();
if (hiveTbl.getPartColInfoMap().containsKey(colOrig.getOriginColumnOrdinal())) {
// Encountered partitioning column, this will be better handled by MetadataOnly optimizer.
return;
}
}
}
}
RelNode converted = convertMonopole(aggregate, argListSets.iterator().next());
call.transformTo(converted);
return;
}
}
Aggregations