Search in sources :

Example 6 with AbstractBinaryJoinOperator

use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.

the class RTreeAccessMethod 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 {
    // 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);
    }
    // TODO: We can probably do something smarter here based on selectivity or MBR area.
    ILogicalOperator primaryIndexUnnestOp = createSecondaryToPrimaryPlan(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);
    }
    indexSubTree.getDataSourceRef().setValue(primaryIndexUnnestOp);
    // Change join into a select with the same condition.
    AbstractBinaryJoinOperator joinOp = (AbstractBinaryJoinOperator) joinRef.getValue();
    SelectOperator topSelect = new SelectOperator(joinOp.getCondition(), 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);
    return true;
}
Also used : LogicalVariable(org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable) SelectOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator) Dataset(org.apache.asterix.metadata.entities.Dataset) ILogicalOperator(org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator) AbstractBinaryJoinOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator)

Example 7 with AbstractBinaryJoinOperator

use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.

the class IntroduceJoinAccessMethodRule method checkAndApplyJoinTransformation.

/**
     * Recursively traverse the given plan and check whether a INNERJOIN or LEFTOUTERJOIN operator exists.
     * If one is found, maintain the path from the root to the given join operator and
     * optimize the path from the given join operator to the EMPTY_TUPLE_SOURCE operator
     * if it is not already optimized.
     */
protected boolean checkAndApplyJoinTransformation(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
    AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
    boolean joinFoundAndOptimizationApplied;
    // Check the current operator pattern to see whether it is a JOIN or not.
    boolean isThisOpInnerJoin = isInnerJoin(op);
    boolean isThisOpLeftOuterJoin = isLeftOuterJoin(op);
    boolean isParentOpGroupBy = hasGroupBy;
    Mutable<ILogicalOperator> joinRefFromThisOp = null;
    AbstractBinaryJoinOperator joinOpFromThisOp = null;
    if (isThisOpInnerJoin) {
        // Set join operator.
        joinRef = opRef;
        joinOp = (InnerJoinOperator) op;
        joinRefFromThisOp = opRef;
        joinOpFromThisOp = (InnerJoinOperator) op;
    } else if (isThisOpLeftOuterJoin) {
        // Set left-outer-join op.
        // The current operator is GROUP and the child of this op is LEFTOUERJOIN.
        joinRef = op.getInputs().get(0);
        joinOp = (LeftOuterJoinOperator) joinRef.getValue();
        joinRefFromThisOp = op.getInputs().get(0);
        joinOpFromThisOp = (LeftOuterJoinOperator) joinRefFromThisOp.getValue();
    }
    // to make sure an earlier join in the path is optimized first.
    for (Mutable<ILogicalOperator> inputOpRef : op.getInputs()) {
        joinFoundAndOptimizationApplied = checkAndApplyJoinTransformation(inputOpRef, context);
        if (joinFoundAndOptimizationApplied) {
            return true;
        }
    }
    // For a JOIN case, try to transform the given plan.
    if (isThisOpInnerJoin || isThisOpLeftOuterJoin) {
        // Restore the information from this operator since it might have been be set to null
        // if there are other join operators in the earlier path.
        joinRef = joinRefFromThisOp;
        joinOp = joinOpFromThisOp;
        boolean continueCheck = true;
        // Already checked? If not, this operator may be optimized.
        if (context.checkIfInDontApplySet(this, joinOp)) {
            continueCheck = false;
        }
        // For each access method, this contains the information about
        // whether an available index can be applicable or not.
        Map<IAccessMethod, AccessMethodAnalysisContext> analyzedAMs = null;
        if (continueCheck) {
            analyzedAMs = new HashMap<>();
        }
        // whether the given plan is truly optimizable or not.
        if (continueCheck && !checkJoinOpConditionAndInitSubTree(context)) {
            continueCheck = false;
        }
        // Analyze the condition of SELECT operator and initialize analyzedAMs.
        // Check whether the function in the SELECT operator can be truly transformed.
        boolean matchInLeftSubTree = false;
        boolean matchInRightSubTree = false;
        if (continueCheck) {
            if (leftSubTree.hasDataSource()) {
                matchInLeftSubTree = analyzeSelectOrJoinOpConditionAndUpdateAnalyzedAM(joinCond, leftSubTree.getAssignsAndUnnests(), analyzedAMs, context, typeEnvironment);
            }
            if (rightSubTree.hasDataSource()) {
                matchInRightSubTree = analyzeSelectOrJoinOpConditionAndUpdateAnalyzedAM(joinCond, rightSubTree.getAssignsAndUnnests(), analyzedAMs, context, typeEnvironment);
            }
        }
        // Find the dataset from the data-source and the record type of the dataset from the metadata.
        // This will be used to find an applicable index on the dataset.
        boolean checkLeftSubTreeMetadata = false;
        boolean checkRightSubTreeMetadata = false;
        if (continueCheck && (matchInLeftSubTree || matchInRightSubTree)) {
            // Set dataset and type metadata.
            if (matchInLeftSubTree) {
                checkLeftSubTreeMetadata = leftSubTree.setDatasetAndTypeMetadata(metadataProvider);
            }
            if (matchInRightSubTree) {
                checkRightSubTreeMetadata = rightSubTree.setDatasetAndTypeMetadata(metadataProvider);
            }
        }
        if (continueCheck && (checkLeftSubTreeMetadata || checkRightSubTreeMetadata)) {
            // Then find the applicable indexes for the variables used in the JOIN condition.
            if (checkLeftSubTreeMetadata) {
                fillSubTreeIndexExprs(leftSubTree, analyzedAMs, context);
            }
            if (checkRightSubTreeMetadata) {
                fillSubTreeIndexExprs(rightSubTree, analyzedAMs, context);
            }
            // Prune the access methods based on the function expression and access methods.
            pruneIndexCandidates(analyzedAMs, context, typeEnvironment);
            // If the right subtree (inner branch) has indexes, one of those indexes will be used.
            // Remove the indexes from the outer branch in the optimizer's consideration list for this rule.
            pruneIndexCandidatesFromOuterBranch(analyzedAMs);
            // We are going to use indexes from the inner branch.
            // If no index is available, then we stop here.
            Pair<IAccessMethod, Index> chosenIndex = chooseBestIndex(analyzedAMs);
            if (chosenIndex == null) {
                context.addToDontApplySet(this, joinOp);
                continueCheck = false;
            }
            if (continueCheck) {
                // Apply plan transformation using chosen index.
                AccessMethodAnalysisContext analysisCtx = analyzedAMs.get(chosenIndex.first);
                // in GroupByOp.
                if (isThisOpLeftOuterJoin && isParentOpGroupBy) {
                    analysisCtx.setLOJGroupbyOpRef(opRef);
                    ScalarFunctionCallExpression isNullFuncExpr = AccessMethodUtils.findLOJIsMissingFuncInGroupBy((GroupByOperator) opRef.getValue());
                    analysisCtx.setLOJIsNullFuncInGroupBy(isNullFuncExpr);
                }
                Dataset indexDataset = analysisCtx.getDatasetFromIndexDatasetMap(chosenIndex.second);
                // from the right subtree. The following is just a sanity check.
                if (!rightSubTree.hasDataSourceScan() && !indexDataset.getDatasetName().equals(rightSubTree.getDataset().getDatasetName())) {
                    return false;
                }
                // Finally, try to apply plan transformation using chosen index.
                boolean res = chosenIndex.first.applyJoinPlanTransformation(joinRef, leftSubTree, rightSubTree, chosenIndex.second, analysisCtx, context, isThisOpLeftOuterJoin, isParentOpGroupBy);
                // will find them.
                if (res) {
                    return res;
                }
            }
        }
        joinRef = null;
        joinOp = null;
    }
    return false;
}
Also used : AbstractLogicalOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator) Dataset(org.apache.asterix.metadata.entities.Dataset) ILogicalOperator(org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator) LeftOuterJoinOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator) Index(org.apache.asterix.metadata.entities.Index) AbstractBinaryJoinOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator) ScalarFunctionCallExpression(org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression)

Example 8 with AbstractBinaryJoinOperator

use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.

the class InvertedIndexAccessMethod 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 {
    // Figure out 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;
    }
    IOptimizableFuncExpr optFuncExpr = AccessMethodUtils.chooseFirstOptFuncExpr(chosenIndex, analysisCtx);
    // if the dataset of index subtree and the dataset of first argument's subtree is the same
    if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.EDIT_DISTANCE_CONTAINS && optFuncExpr.getOperatorSubTree(0).getDataset() != null && !optFuncExpr.getOperatorSubTree(0).getDataset().getDatasetName().equals(indexSubTree.getDataset().getDatasetName())) {
        return false;
    }
    //if LOJ, reset null place holder variable
    LogicalVariable newNullPlaceHolderVar = null;
    if (isLeftOuterJoin && hasGroupBy) {
        //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);
        //reset the null place holder variable
        AccessMethodUtils.resetLOJNullPlaceholderVariableInGroupByOp(analysisCtx, newNullPlaceHolderVar, context);
    }
    AbstractBinaryJoinOperator join = (AbstractBinaryJoinOperator) joinRef.getValue();
    // Remember the original probe subtree, and its primary-key variables,
    // so we can later retrieve the missing attributes via an equi join.
    List<LogicalVariable> originalSubTreePKs = new ArrayList<>();
    // Remember the primary-keys of the new probe subtree for the top-level equi join.
    List<LogicalVariable> surrogateSubTreePKs = new ArrayList<>();
    // Copy probe subtree, replacing their variables with new ones. We will use the original variables
    // to stitch together a top-level equi join.
    Mutable<ILogicalOperator> originalProbeSubTreeRootRef = copyAndReinitProbeSubTree(probeSubTree, join.getCondition().getValue(), optFuncExpr, originalSubTreePKs, surrogateSubTreePKs, context);
    // Remember original live variables from the index sub tree.
    List<LogicalVariable> indexSubTreeLiveVars = new ArrayList<>();
    VariableUtilities.getLiveVariables(indexSubTree.getRoot(), indexSubTreeLiveVars);
    // Clone the original join condition because we may have to modify it (and we also need the original).
    ILogicalExpression joinCond = join.getCondition().getValue().cloneExpression();
    // Create "panic" (non indexed) nested-loop join path if necessary.
    Mutable<ILogicalOperator> panicJoinRef = null;
    Map<LogicalVariable, LogicalVariable> panicVarMap = null;
    if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.EDIT_DISTANCE_CHECK || optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.EDIT_DISTANCE_CONTAINS) {
        panicJoinRef = new MutableObject<>(joinRef.getValue());
        panicVarMap = new HashMap<>();
        Mutable<ILogicalOperator> newProbeRootRef = createPanicNestedLoopJoinPlan(panicJoinRef, indexSubTree, probeSubTree, optFuncExpr, chosenIndex, panicVarMap, context);
        probeSubTree.getRootRef().setValue(newProbeRootRef.getValue());
        probeSubTree.setRoot(newProbeRootRef.getValue());
    }
    // Create regular indexed-nested loop join path.
    ILogicalOperator indexPlanRootOp = createSecondaryToPrimaryPlan(null, indexSubTree, probeSubTree, chosenIndex, analysisCtx, true, isLeftOuterJoin, true, context);
    indexSubTree.getDataSourceRef().setValue(indexPlanRootOp);
    // Change join into a select with the same condition.
    SelectOperator topSelect = new SelectOperator(new MutableObject<ILogicalExpression>(joinCond), isLeftOuterJoin, newNullPlaceHolderVar);
    topSelect.getInputs().add(indexSubTree.getRootRef());
    topSelect.setExecutionMode(ExecutionMode.LOCAL);
    context.computeAndSetTypeEnvironmentForOperator(topSelect);
    ILogicalOperator topOp = topSelect;
    // Hook up the indexed-nested loop join path with the "panic" (non indexed) nested-loop join path by putting a union all on top.
    if (panicJoinRef != null) {
        LogicalVariable inputSearchVar = getInputSearchVar(optFuncExpr, indexSubTree);
        indexSubTreeLiveVars.addAll(originalSubTreePKs);
        indexSubTreeLiveVars.add(inputSearchVar);
        List<LogicalVariable> panicPlanLiveVars = new ArrayList<>();
        VariableUtilities.getLiveVariables(panicJoinRef.getValue(), panicPlanLiveVars);
        // Create variable mapping for union all operator.
        List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> varMap = new ArrayList<>();
        for (int i = 0; i < indexSubTreeLiveVars.size(); i++) {
            LogicalVariable indexSubTreeVar = indexSubTreeLiveVars.get(i);
            LogicalVariable panicPlanVar = panicVarMap.get(indexSubTreeVar);
            if (panicPlanVar == null) {
                panicPlanVar = indexSubTreeVar;
            }
            varMap.add(new Triple<LogicalVariable, LogicalVariable, LogicalVariable>(indexSubTreeVar, panicPlanVar, indexSubTreeVar));
        }
        UnionAllOperator unionAllOp = new UnionAllOperator(varMap);
        unionAllOp.getInputs().add(new MutableObject<ILogicalOperator>(topOp));
        unionAllOp.getInputs().add(panicJoinRef);
        unionAllOp.setExecutionMode(ExecutionMode.PARTITIONED);
        context.computeAndSetTypeEnvironmentForOperator(unionAllOp);
        topOp = unionAllOp;
    }
    // Place a top-level equi-join on top to retrieve the missing variables from the original probe subtree.
    // The inner (build) branch of the join is the subtree with the data scan, since the result of the similarity join could potentially be big.
    // This choice may not always be the most efficient, but it seems more robust than the alternative.
    Mutable<ILogicalExpression> eqJoinConditionRef = createPrimaryKeysEqJoinCondition(originalSubTreePKs, surrogateSubTreePKs);
    InnerJoinOperator topEqJoin = new InnerJoinOperator(eqJoinConditionRef, originalProbeSubTreeRootRef, new MutableObject<ILogicalOperator>(topOp));
    topEqJoin.setExecutionMode(ExecutionMode.PARTITIONED);
    joinRef.setValue(topEqJoin);
    context.computeAndSetTypeEnvironmentForOperator(topEqJoin);
    return true;
}
Also used : LogicalVariable(org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable) Dataset(org.apache.asterix.metadata.entities.Dataset) ILogicalOperator(org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator) ArrayList(java.util.ArrayList) InnerJoinOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator) AbstractBinaryJoinOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator) Triple(org.apache.hyracks.algebricks.common.utils.Triple) ILogicalExpression(org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression) SelectOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator) UnionAllOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator)

Example 9 with AbstractBinaryJoinOperator

use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator 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;
}
Also used : LogicalVariable(org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable) AbstractLogicalOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator) ILogicalOperator(org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator) ArrayList(java.util.ArrayList) InnerJoinOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator) LinkedList(java.util.LinkedList) AbstractBinaryJoinOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator) Mutable(org.apache.commons.lang3.mutable.Mutable) ILogicalExpression(org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression) SelectOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator) LogicalOperatorTag(org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag) HashSet(java.util.HashSet)

Example 10 with AbstractBinaryJoinOperator

use of org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator in project asterixdb by apache.

the class PushMapOperatorDownThroughProductRule method rewritePost.

@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
    AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
    // since a new LIMIT under a join can't generate the original result.
    if (!op1.isMap() || op1.getOperatorTag() == LogicalOperatorTag.LIMIT) {
        return false;
    }
    if (!OperatorPropertiesUtil.isMovable(op1)) {
        return false;
    }
    ;
    Mutable<ILogicalOperator> op2Ref = op1.getInputs().get(0);
    AbstractLogicalOperator op2 = (AbstractLogicalOperator) op2Ref.getValue();
    if (op2.getOperatorTag() != LogicalOperatorTag.INNERJOIN) {
        return false;
    }
    AbstractBinaryJoinOperator join = (AbstractBinaryJoinOperator) op2;
    if (!OperatorPropertiesUtil.isAlwaysTrueCond(join.getCondition().getValue())) {
        return false;
    }
    List<LogicalVariable> used = new ArrayList<LogicalVariable>();
    VariableUtilities.getUsedVariables(op1, used);
    Mutable<ILogicalOperator> b0Ref = op2.getInputs().get(0);
    ILogicalOperator b0 = b0Ref.getValue();
    List<LogicalVariable> b0Scm = new ArrayList<LogicalVariable>();
    VariableUtilities.getLiveVariables(b0, b0Scm);
    if (b0Scm.containsAll(used)) {
        // push operator on left branch
        op2Ref.setValue(b0);
        b0Ref.setValue(op1);
        opRef.setValue(op2);
        return true;
    } else {
        Mutable<ILogicalOperator> b1Ref = op2.getInputs().get(1);
        ILogicalOperator b1 = b1Ref.getValue();
        List<LogicalVariable> b1Scm = new ArrayList<LogicalVariable>();
        VariableUtilities.getLiveVariables(b1, b1Scm);
        if (b1Scm.containsAll(used)) {
            // push operator on right branch
            op2Ref.setValue(b1);
            b1Ref.setValue(op1);
            opRef.setValue(op2);
            return true;
        } else {
            return false;
        }
    }
}
Also used : LogicalVariable(org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable) AbstractLogicalOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator) ILogicalOperator(org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator) ArrayList(java.util.ArrayList) AbstractBinaryJoinOperator(org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator)

Aggregations

AbstractBinaryJoinOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator)27 ILogicalOperator (org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator)24 AbstractLogicalOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator)18 LogicalVariable (org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable)14 ILogicalExpression (org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression)11 ArrayList (java.util.ArrayList)9 SelectOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator)9 Mutable (org.apache.commons.lang3.mutable.Mutable)7 MutableObject (org.apache.commons.lang3.mutable.MutableObject)5 InnerJoinOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator)5 Dataset (org.apache.asterix.metadata.entities.Dataset)4 ILogicalPlan (org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan)4 VariableReferenceExpression (org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression)4 AggregateOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator)4 LeftOuterJoinOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator)4 HashSet (java.util.HashSet)3 AssignOperator (org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator)3 Clause (org.apache.asterix.lang.common.base.Clause)2 MetadataProvider (org.apache.asterix.metadata.declared.MetadataProvider)2 IAType (org.apache.asterix.om.types.IAType)2