use of org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag in project asterixdb by apache.
the class CopyLimitDownRule method rewritePre.
@Override
public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
if (op.getOperatorTag() != LogicalOperatorTag.LIMIT) {
return false;
}
LimitOperator limitOp = (LimitOperator) op;
if (!limitOp.isTopmostLimitOp()) {
return false;
}
List<LogicalVariable> limitUsedVars = new ArrayList<>();
VariableUtilities.getUsedVariables(limitOp, limitUsedVars);
Mutable<ILogicalOperator> safeOpRef = null;
Mutable<ILogicalOperator> candidateOpRef = limitOp.getInputs().get(0);
List<LogicalVariable> candidateProducedVars = new ArrayList<>();
while (true) {
candidateProducedVars.clear();
ILogicalOperator candidateOp = candidateOpRef.getValue();
LogicalOperatorTag candidateOpTag = candidateOp.getOperatorTag();
if (candidateOp.getInputs().size() > 1 || !candidateOp.isMap() || candidateOpTag == LogicalOperatorTag.SELECT || candidateOpTag == LogicalOperatorTag.LIMIT || candidateOpTag == LogicalOperatorTag.UNNEST_MAP || !OperatorPropertiesUtil.disjoint(limitUsedVars, candidateProducedVars)) {
break;
}
safeOpRef = candidateOpRef;
candidateOpRef = safeOpRef.getValue().getInputs().get(0);
}
if (safeOpRef != null) {
ILogicalOperator safeOp = safeOpRef.getValue();
Mutable<ILogicalOperator> unsafeOpRef = safeOp.getInputs().get(0);
ILogicalOperator unsafeOp = unsafeOpRef.getValue();
LimitOperator limitCloneOp = null;
if (limitOp.getOffset().getValue() == null) {
limitCloneOp = new LimitOperator(limitOp.getMaxObjects().getValue(), false);
} else {
// Need to add an offset to the given limit value
// since the original topmost limit will use the offset value.
// We can't apply the offset multiple times.
IFunctionInfo finfoAdd = context.getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.NUMERIC_ADD);
List<Mutable<ILogicalExpression>> addArgs = new ArrayList<>();
addArgs.add(new MutableObject<ILogicalExpression>(limitOp.getMaxObjects().getValue().cloneExpression()));
addArgs.add(new MutableObject<ILogicalExpression>(limitOp.getOffset().getValue().cloneExpression()));
ScalarFunctionCallExpression maxPlusOffset = new ScalarFunctionCallExpression(finfoAdd, addArgs);
limitCloneOp = new LimitOperator(maxPlusOffset, false);
}
limitCloneOp.setPhysicalOperator(new StreamLimitPOperator());
limitCloneOp.getInputs().add(new MutableObject<ILogicalOperator>(unsafeOp));
limitCloneOp.setExecutionMode(unsafeOp.getExecutionMode());
OperatorPropertiesUtil.computeSchemaRecIfNull((AbstractLogicalOperator) unsafeOp);
limitCloneOp.recomputeSchema();
unsafeOpRef.setValue(limitCloneOp);
context.computeAndSetTypeEnvironmentForOperator(limitCloneOp);
context.addToDontApplySet(this, limitOp);
}
return safeOpRef != null;
}
use of org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag in project asterixdb by apache.
the class InlineLeftNtsInSubplanJoinFlatteningVisitor method visitSingleInputOperator.
private ILogicalOperator visitSingleInputOperator(ILogicalOperator op) throws AlgebricksException {
if (op.getInputs().size() == 1) {
// Deals with single input operators.
Mutable<ILogicalOperator> childRef = op.getInputs().get(0);
ILogicalOperator newChild = childRef.getValue().accept(this, null);
LogicalOperatorTag childOpTag = newChild.getOperatorTag();
if (childOpTag == LogicalOperatorTag.INNERJOIN || childOpTag == LogicalOperatorTag.LEFTOUTERJOIN) {
topJoinRef = childRef;
}
op.getInputs().get(0).setValue(newChild);
}
return op;
}
use of org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag in project asterixdb by apache.
the class PushSelectIntoJoinRule method rewritePost.
@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
Collection<LogicalVariable> joinLiveVarsLeft = new HashSet<LogicalVariable>();
Collection<LogicalVariable> joinLiveVarsRight = new HashSet<LogicalVariable>();
Collection<LogicalVariable> liveInOpsToPushLeft = new HashSet<LogicalVariable>();
Collection<LogicalVariable> liveInOpsToPushRight = new HashSet<LogicalVariable>();
List<ILogicalOperator> pushedOnLeft = new ArrayList<ILogicalOperator>();
List<ILogicalOperator> pushedOnRight = new ArrayList<ILogicalOperator>();
List<ILogicalOperator> pushedOnEither = new ArrayList<ILogicalOperator>();
LinkedList<ILogicalOperator> notPushedStack = new LinkedList<ILogicalOperator>();
Collection<LogicalVariable> usedVars = new HashSet<LogicalVariable>();
Collection<LogicalVariable> producedVars = new HashSet<LogicalVariable>();
AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
if (op.getOperatorTag() != LogicalOperatorTag.SELECT) {
return false;
}
SelectOperator select = (SelectOperator) op;
Mutable<ILogicalOperator> opRef2 = op.getInputs().get(0);
AbstractLogicalOperator son = (AbstractLogicalOperator) opRef2.getValue();
AbstractLogicalOperator op2 = son;
boolean needToPushOps = false;
while (son.isMap()) {
needToPushOps = true;
Mutable<ILogicalOperator> opRefLink = son.getInputs().get(0);
son = (AbstractLogicalOperator) opRefLink.getValue();
}
if (son.getOperatorTag() != LogicalOperatorTag.INNERJOIN && son.getOperatorTag() != LogicalOperatorTag.LEFTOUTERJOIN) {
return false;
}
boolean isLoj = son.getOperatorTag() == LogicalOperatorTag.LEFTOUTERJOIN;
AbstractBinaryJoinOperator join = (AbstractBinaryJoinOperator) son;
Mutable<ILogicalOperator> joinBranchLeftRef = join.getInputs().get(0);
Mutable<ILogicalOperator> joinBranchRightRef = join.getInputs().get(1);
if (needToPushOps) {
ILogicalOperator joinBranchLeft = joinBranchLeftRef.getValue();
ILogicalOperator joinBranchRight = joinBranchRightRef.getValue();
VariableUtilities.getLiveVariables(joinBranchLeft, joinLiveVarsLeft);
VariableUtilities.getLiveVariables(joinBranchRight, joinLiveVarsRight);
Mutable<ILogicalOperator> opIterRef = opRef2;
ILogicalOperator opIter = op2;
while (opIter != join) {
LogicalOperatorTag tag = ((AbstractLogicalOperator) opIter).getOperatorTag();
if (tag == LogicalOperatorTag.PROJECT) {
notPushedStack.addFirst(opIter);
} else {
VariableUtilities.getUsedVariables(opIter, usedVars);
VariableUtilities.getProducedVariables(opIter, producedVars);
if (usedVars.size() == 0) {
pushedOnEither.add(opIter);
} else if (joinLiveVarsLeft.containsAll(usedVars)) {
pushedOnLeft.add(opIter);
liveInOpsToPushLeft.addAll(producedVars);
} else if (joinLiveVarsRight.containsAll(usedVars)) {
pushedOnRight.add(opIter);
liveInOpsToPushRight.addAll(producedVars);
} else {
return false;
}
}
opIterRef = opIter.getInputs().get(0);
opIter = opIterRef.getValue();
}
if (isLoj && pushedOnLeft.isEmpty()) {
return false;
}
}
boolean intersectsAllBranches = true;
boolean[] intersectsBranch = new boolean[join.getInputs().size()];
LinkedList<LogicalVariable> selectVars = new LinkedList<LogicalVariable>();
select.getCondition().getValue().getUsedVariables(selectVars);
int i = 0;
for (Mutable<ILogicalOperator> branch : join.getInputs()) {
LinkedList<LogicalVariable> branchVars = new LinkedList<LogicalVariable>();
VariableUtilities.getLiveVariables(branch.getValue(), branchVars);
if (i == 0) {
branchVars.addAll(liveInOpsToPushLeft);
} else {
branchVars.addAll(liveInOpsToPushRight);
}
if (OperatorPropertiesUtil.disjoint(selectVars, branchVars)) {
intersectsAllBranches = false;
} else {
intersectsBranch[i] = true;
}
i++;
}
if (!intersectsBranch[0] && !intersectsBranch[1]) {
return false;
}
if (needToPushOps) {
//We should push independent ops into the first branch that the selection depends on
if (intersectsBranch[0]) {
pushOps(pushedOnEither, joinBranchLeftRef, context);
} else {
pushOps(pushedOnEither, joinBranchRightRef, context);
}
pushOps(pushedOnLeft, joinBranchLeftRef, context);
pushOps(pushedOnRight, joinBranchRightRef, context);
}
if (intersectsAllBranches) {
addCondToJoin(select, join, context);
} else {
// push down
Iterator<Mutable<ILogicalOperator>> branchIter = join.getInputs().iterator();
ILogicalExpression selectCondition = select.getCondition().getValue();
boolean lojToInner = false;
for (int j = 0; j < intersectsBranch.length; j++) {
Mutable<ILogicalOperator> branch = branchIter.next();
boolean inter = intersectsBranch[j];
if (!inter) {
continue;
}
// to inner join for this case.
if (j > 0 && isLoj && containsNotMissingFiltering(selectCondition)) {
lojToInner = true;
}
if ((j > 0 && isLoj) && containsMissingFiltering(selectCondition)) {
// Select "is-not-missing($$var)" cannot be pushed in the right branch of a LOJ;
notPushedStack.addFirst(select);
} else {
// Conditions for the left branch can always be pushed.
// Other conditions can be pushed to the right branch of a LOJ.
copySelectToBranch(select, branch, context);
}
}
if (lojToInner) {
// Rewrites left outer join to inner join.
InnerJoinOperator innerJoin = new InnerJoinOperator(join.getCondition());
innerJoin.getInputs().addAll(join.getInputs());
join = innerJoin;
context.computeAndSetTypeEnvironmentForOperator(join);
}
}
ILogicalOperator top = join;
for (ILogicalOperator npOp : notPushedStack) {
List<Mutable<ILogicalOperator>> npInpList = npOp.getInputs();
npInpList.clear();
npInpList.add(new MutableObject<ILogicalOperator>(top));
context.computeAndSetTypeEnvironmentForOperator(npOp);
top = npOp;
}
opRef.setValue(top);
return true;
}
use of org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag in project asterixdb by apache.
the class RemoveUnusedOneToOneEquiJoinRule method isSelectionAboveDataScan.
private boolean isSelectionAboveDataScan(Mutable<ILogicalOperator> opRef) {
boolean hasSelection = false;
AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
LogicalOperatorTag tag = op.getOperatorTag();
switch(tag) {
case DATASOURCESCAN:
return false;
case UNNEST_MAP:
case LEFT_OUTER_UNNEST_MAP:
case LIMIT:
case SELECT:
return true;
default:
for (Mutable<ILogicalOperator> inputOp : op.getInputs()) {
hasSelection |= isSelectionAboveDataScan(inputOp);
}
}
return hasSelection;
}
use of org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag in project asterixdb by apache.
the class PushProperJoinThroughProduct method rewritePost.
@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
LogicalOperatorTag tag1 = op.getOperatorTag();
if (tag1 != LogicalOperatorTag.INNERJOIN && tag1 != LogicalOperatorTag.LEFTOUTERJOIN) {
return false;
}
AbstractBinaryJoinOperator join1 = (AbstractBinaryJoinOperator) op;
ILogicalExpression cond1 = join1.getCondition().getValue();
// don't try to push a product down
if (OperatorPropertiesUtil.isAlwaysTrueCond(cond1)) {
return false;
}
Mutable<ILogicalOperator> opRef2 = op.getInputs().get(0);
AbstractLogicalOperator op2 = (AbstractLogicalOperator) opRef2.getValue();
while (op2.isMap()) {
opRef2 = op2.getInputs().get(0);
op2 = (AbstractLogicalOperator) opRef2.getValue();
}
if (op2.getOperatorTag() != LogicalOperatorTag.INNERJOIN) {
return false;
}
InnerJoinOperator product = (InnerJoinOperator) op2;
if (!OperatorPropertiesUtil.isAlwaysTrueCond(product.getCondition().getValue())) {
return false;
}
usedInCond1AndMaps.clear();
cond1.getUsedVariables(usedInCond1AndMaps);
Mutable<ILogicalOperator> opIterRef = op.getInputs().get(0);
ILogicalOperator opIter = opIterRef.getValue();
do {
VariableUtilities.getUsedVariables(opIter, usedInCond1AndMaps);
opIterRef = opIter.getInputs().get(0);
opIter = opIterRef.getValue();
} while (opIter.isMap());
productLeftBranchVars.clear();
ILogicalOperator opLeft = op2.getInputs().get(0).getValue();
VariableUtilities.getLiveVariables(opLeft, productLeftBranchVars);
if (!OperatorPropertiesUtil.disjoint(usedInCond1AndMaps, productLeftBranchVars)) {
return false;
}
// now push the operators from in between joins, too
opIterRef = op.getInputs().get(0);
opIter = opIterRef.getValue();
Mutable<ILogicalOperator> op3Ref = product.getInputs().get(1);
ILogicalOperator op3 = op3Ref.getValue();
opRef2.setValue(op3);
op3Ref.setValue(join1);
opRef.setValue(product);
return true;
}
Aggregations