use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.
the class RemoveUnusedOneToOneEquiJoinRule method removeJoinFromInputBranch.
private int removeJoinFromInputBranch(Mutable<ILogicalOperator> opRef) throws AlgebricksException {
AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
if (op.getOperatorTag() != LogicalOperatorTag.INNERJOIN) {
return -1;
}
AbstractBinaryJoinOperator joinOp = (AbstractBinaryJoinOperator) op;
// Make sure the join is an equi-join.
if (!isEquiJoin(joinOp.getCondition())) {
return -1;
}
int unusedJoinBranchIndex = -1;
for (int i = 0; i < joinOp.getInputs().size(); i++) {
liveVars.clear();
VariableUtilities.getLiveVariables(joinOp.getInputs().get(i).getValue(), liveVars);
if (liveVars.isEmpty()) {
// The branch does not produce any variable, i.e., it only contains an empty tuple source.
return i;
}
liveVars.retainAll(parentsUsedVars);
if (liveVars.isEmpty()) {
// None of the live variables from this branch are used by its parents.
unusedJoinBranchIndex = i;
break;
}
}
if (unusedJoinBranchIndex < 0) {
// The variables from both branches are used in the upstream plan. We cannot remove this join.
return -1;
}
// Check whether one of the join branches is unused.
usedVars.clear();
VariableUtilities.getUsedVariables(joinOp, usedVars);
// Check whether all used variables originate from primary keys of exactly the same dataset.
// Collect a list of datascans whose primary key variables are used in the join condition.
gatherProducingDataScans(opRef, usedVars, dataScans);
if (dataScans.size() < 2) {
// Either branch does not use its primary key in the join condition.
return -1;
}
// only used primary key variables of those datascans.
for (int i = 0; i < dataScans.size(); i++) {
if (i > 0) {
DatasetDataSource prevAqlDataSource = (DatasetDataSource) dataScans.get(i - 1).getDataSource();
DatasetDataSource currAqlDataSource = (DatasetDataSource) dataScans.get(i).getDataSource();
if (!prevAqlDataSource.getDataset().equals(currAqlDataSource.getDataset())) {
return -1;
}
}
// Remove from the used variables all the primary key vars of this dataset.
fillPKVars(dataScans.get(i), pkVars);
usedVars.removeAll(pkVars);
}
if (!usedVars.isEmpty()) {
// keys from datasource scans of the same dataset.
return -1;
}
// We expect the post-plan will NOT prune the join part derived from A.
if (unusedJoinBranchIndex >= 0 && isSelectionAboveDataScan(opRef.getValue().getInputs().get(unusedJoinBranchIndex))) {
unusedJoinBranchIndex = -1;
}
return unusedJoinBranchIndex;
}
use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.
the class BTreeAccessMethod method applyJoinPlanTransformation.
@Override
public boolean applyJoinPlanTransformation(Mutable<ILogicalOperator> joinRef, OptimizableOperatorSubTree leftSubTree, OptimizableOperatorSubTree rightSubTree, Index chosenIndex, AccessMethodAnalysisContext analysisCtx, IOptimizationContext context, boolean isLeftOuterJoin, boolean hasGroupBy) throws AlgebricksException {
AbstractBinaryJoinOperator joinOp = (AbstractBinaryJoinOperator) joinRef.getValue();
Mutable<ILogicalExpression> conditionRef = joinOp.getCondition();
// Determine if the index is applicable on the left or right side
// (if both, we arbitrarily prefer the left side).
Dataset dataset = analysisCtx.getDatasetFromIndexDatasetMap(chosenIndex);
OptimizableOperatorSubTree indexSubTree;
OptimizableOperatorSubTree probeSubTree;
// The following is just a sanity check.
if (rightSubTree.hasDataSourceScan() && dataset.getDatasetName().equals(rightSubTree.getDataset().getDatasetName())) {
indexSubTree = rightSubTree;
probeSubTree = leftSubTree;
} else {
return false;
}
LogicalVariable newNullPlaceHolderVar = null;
if (isLeftOuterJoin) {
//get a new null place holder variable that is the first field variable of the primary key
//from the indexSubTree's datasourceScanOp
newNullPlaceHolderVar = indexSubTree.getDataSourceVariables().get(0);
}
ILogicalOperator primaryIndexUnnestOp = createSecondaryToPrimaryPlan(conditionRef, indexSubTree, probeSubTree, chosenIndex, analysisCtx, true, isLeftOuterJoin, true, context);
if (primaryIndexUnnestOp == null) {
return false;
}
if (isLeftOuterJoin && hasGroupBy) {
//reset the null place holder variable
AccessMethodUtils.resetLOJNullPlaceholderVariableInGroupByOp(analysisCtx, newNullPlaceHolderVar, context);
}
// If there are conditions left, add a new select operator on top.
indexSubTree.getDataSourceRef().setValue(primaryIndexUnnestOp);
if (conditionRef.getValue() != null) {
SelectOperator topSelect = new SelectOperator(conditionRef, isLeftOuterJoin, newNullPlaceHolderVar);
topSelect.getInputs().add(indexSubTree.getRootRef());
topSelect.setExecutionMode(ExecutionMode.LOCAL);
context.computeAndSetTypeEnvironmentForOperator(topSelect);
// Replace the original join with the new subtree rooted at the select op.
joinRef.setValue(topSelect);
} else {
joinRef.setValue(indexSubTree.getRootRef().getValue());
}
return true;
}
use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.
the class InvertedIndexAccessMethod method createPanicNestedLoopJoinPlan.
private Mutable<ILogicalOperator> createPanicNestedLoopJoinPlan(Mutable<ILogicalOperator> joinRef, OptimizableOperatorSubTree indexSubTree, OptimizableOperatorSubTree probeSubTree, IOptimizableFuncExpr optFuncExpr, Index chosenIndex, Map<LogicalVariable, LogicalVariable> panicVarMap, IOptimizationContext context) throws AlgebricksException {
LogicalVariable inputSearchVar = getInputSearchVar(optFuncExpr, indexSubTree);
// We split the plan into two "branches", and add selections on each side.
AbstractLogicalOperator replicateOp = new ReplicateOperator(2);
replicateOp.getInputs().add(new MutableObject<ILogicalOperator>(probeSubTree.getRoot()));
replicateOp.setExecutionMode(ExecutionMode.PARTITIONED);
context.computeAndSetTypeEnvironmentForOperator(replicateOp);
// Create select ops for removing tuples that are filterable and not filterable, respectively.
IVariableTypeEnvironment probeTypeEnv = context.getOutputTypeEnvironment(probeSubTree.getRoot());
IAType inputSearchVarType;
if (chosenIndex.isEnforcingKeyFileds()) {
inputSearchVarType = optFuncExpr.getFieldType(optFuncExpr.findLogicalVar(inputSearchVar));
} else {
inputSearchVarType = (IAType) probeTypeEnv.getVarType(inputSearchVar);
}
Mutable<ILogicalOperator> isFilterableSelectOpRef = new MutableObject<ILogicalOperator>();
Mutable<ILogicalOperator> isNotFilterableSelectOpRef = new MutableObject<ILogicalOperator>();
createIsFilterableSelectOps(replicateOp, inputSearchVar, inputSearchVarType, optFuncExpr, chosenIndex, context, isFilterableSelectOpRef, isNotFilterableSelectOpRef);
List<LogicalVariable> originalLiveVars = new ArrayList<LogicalVariable>();
VariableUtilities.getLiveVariables(indexSubTree.getRoot(), originalLiveVars);
// Copy the scan subtree in indexSubTree.
LogicalOperatorDeepCopyWithNewVariablesVisitor deepCopyVisitor = new LogicalOperatorDeepCopyWithNewVariablesVisitor(context, context);
ILogicalOperator scanSubTree = deepCopyVisitor.deepCopy(indexSubTree.getRoot());
Map<LogicalVariable, LogicalVariable> copyVarMap = deepCopyVisitor.getInputToOutputVariableMapping();
panicVarMap.putAll(copyVarMap);
List<LogicalVariable> copyLiveVars = new ArrayList<LogicalVariable>();
VariableUtilities.getLiveVariables(scanSubTree, copyLiveVars);
// Replace the inputs of the given join op, and replace variables in its
// condition since we deep-copied one of the scanner subtrees which
// changed variables.
AbstractBinaryJoinOperator joinOp = (AbstractBinaryJoinOperator) joinRef.getValue();
for (Map.Entry<LogicalVariable, LogicalVariable> entry : copyVarMap.entrySet()) {
joinOp.getCondition().getValue().substituteVar(entry.getKey(), entry.getValue());
}
joinOp.getInputs().clear();
joinOp.getInputs().add(new MutableObject<ILogicalOperator>(scanSubTree));
// Make sure that the build input (which may be materialized causing blocking) comes from
// the split+select, otherwise the plan will have a deadlock.
joinOp.getInputs().add(isNotFilterableSelectOpRef);
context.computeAndSetTypeEnvironmentForOperator(joinOp);
// Return the new root of the probeSubTree.
return isFilterableSelectOpRef;
}
use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.
the class InlineLeftNtsInSubplanJoinFlatteningVisitor method visitInnerJoinOperator.
@Override
public ILogicalOperator visitInnerJoinOperator(InnerJoinOperator op, Void arg) throws AlgebricksException {
hasJoinAncestor = true;
boolean needToSwitch = false;
for (int i = 0; i < op.getInputs().size(); ++i) {
// Deals with single input operators.
ILogicalOperator newChild = op.getInputs().get(i).getValue().accept(this, null);
op.getInputs().get(i).setValue(newChild);
if (i == 1) {
needToSwitch = true;
}
if (rewritten) {
break;
}
}
// Checks whether there is a need to switch two join branches.
if (rewritten && needToSwitch) {
Mutable<ILogicalOperator> leftBranch = op.getInputs().get(0);
Mutable<ILogicalOperator> rightBranch = op.getInputs().get(1);
op.getInputs().set(0, rightBranch);
op.getInputs().set(1, leftBranch);
}
AbstractBinaryJoinOperator returnOp = op;
// After rewriting, the original inner join should become an left outer join.
if (rewritten) {
returnOp = new LeftOuterJoinOperator(op.getCondition());
returnOp.getInputs().addAll(op.getInputs());
injectNullCheckVars(returnOp);
}
return returnOp;
}
use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.
the class AqlPlusExpressionToPlanTranslator method visitJoinClause.
@Override
public Pair<ILogicalOperator, LogicalVariable> visitJoinClause(JoinClause jc, Mutable<ILogicalOperator> tupSource) throws CompilationException {
Mutable<ILogicalOperator> opRef = tupSource;
Pair<ILogicalOperator, LogicalVariable> leftSide = null;
for (Clause c : jc.getLeftClauses()) {
leftSide = c.accept(this, opRef);
opRef = new MutableObject<ILogicalOperator>(leftSide.first);
}
opRef = tupSource;
Pair<ILogicalOperator, LogicalVariable> rightSide = null;
for (Clause c : jc.getRightClauses()) {
rightSide = c.accept(this, opRef);
opRef = new MutableObject<ILogicalOperator>(rightSide.first);
}
Pair<ILogicalExpression, Mutable<ILogicalOperator>> whereCond = langExprToAlgExpression(jc.getWhereExpr(), tupSource);
AbstractBinaryJoinOperator join;
switch(jc.getKind()) {
case INNER:
join = new InnerJoinOperator(new MutableObject<ILogicalExpression>(whereCond.first));
break;
case LEFT_OUTER:
join = new LeftOuterJoinOperator(new MutableObject<ILogicalExpression>(whereCond.first));
break;
default:
throw new CompilationException(ErrorCode.COMPILATION_AQLPLUS_NO_SUCH_JOIN_TYPE);
}
join.getInputs().add(new MutableObject<ILogicalOperator>(leftSide.first));
join.getInputs().add(new MutableObject<ILogicalOperator>(rightSide.first));
return new Pair<ILogicalOperator, LogicalVariable>(join, null);
}
Aggregations