| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.apache.commons.lang3.mutable.Mutable; |
| import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; |
| import org.apache.hyracks.algebricks.common.utils.Pair; |
| import org.apache.hyracks.algebricks.common.utils.Triple; |
| import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; |
| import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator; |
| import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan; |
| import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag; |
| import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.AggregateOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.DataSourceScanOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistinctOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.DistributeResultOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteUpsertOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteUpsertOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.IntersectOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestMapOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.LimitOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.MaterializeOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator.IOrder; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.RunningAggregateOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.ScriptOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.SinkOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.SplitOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.TokenizeOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestMapOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteOperator; |
| import org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteResultOperator; |
| import org.apache.hyracks.algebricks.core.algebra.properties.IPartitioningProperty; |
| import org.apache.hyracks.algebricks.core.algebra.properties.IPhysicalPropertiesVector; |
| import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil; |
| import org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor; |
| |
| public class IsomorphismOperatorVisitor implements ILogicalOperatorVisitor<Boolean, ILogicalOperator> { |
| |
| private final Map<LogicalVariable, LogicalVariable> variableMapping = new HashMap<LogicalVariable, LogicalVariable>(); |
| |
| public IsomorphismOperatorVisitor() { |
| } |
| |
| @Override |
| public Boolean visitAggregateOperator(AggregateOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.AGGREGATE) { |
| return Boolean.FALSE; |
| } |
| AggregateOperator aggOpArg = (AggregateOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered( |
| getPairList(op.getVariables(), op.getExpressions()), |
| getPairList(aggOpArg.getVariables(), aggOpArg.getExpressions())); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitRunningAggregateOperator(RunningAggregateOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.RUNNINGAGGREGATE) { |
| return Boolean.FALSE; |
| } |
| RunningAggregateOperator aggOpArg = (RunningAggregateOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered( |
| getPairList(op.getVariables(), op.getExpressions()), |
| getPairList(aggOpArg.getVariables(), aggOpArg.getExpressions())); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) copyAndSubstituteVar(op, arg); |
| if (aop.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) { |
| return Boolean.FALSE; |
| } |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitExtensionOperator(ExtensionOperator op, ILogicalOperator arg) throws AlgebricksException { |
| ExtensionOperator aop = (ExtensionOperator) copyAndSubstituteVar(op, arg); |
| if (aop.getOperatorTag() != LogicalOperatorTag.EXTENSION_OPERATOR) { |
| return Boolean.FALSE; |
| } |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitGroupByOperator(GroupByOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| // require the same physical operator, otherwise delivers different data |
| // properties |
| if (aop.getOperatorTag() != LogicalOperatorTag.GROUP |
| || aop.getPhysicalOperator().getOperatorTag() != op.getPhysicalOperator().getOperatorTag()) { |
| return Boolean.FALSE; |
| } |
| |
| List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> keyLists = op.getGroupByList(); |
| GroupByOperator gbyOpArg = (GroupByOperator) copyAndSubstituteVar(op, arg); |
| List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> keyListsArg = gbyOpArg.getGroupByList(); |
| |
| List<Pair<LogicalVariable, ILogicalExpression>> listLeft = new ArrayList<Pair<LogicalVariable, ILogicalExpression>>(); |
| List<Pair<LogicalVariable, ILogicalExpression>> listRight = new ArrayList<Pair<LogicalVariable, ILogicalExpression>>(); |
| |
| for (Pair<LogicalVariable, Mutable<ILogicalExpression>> pair : keyLists) { |
| listLeft.add(new Pair<LogicalVariable, ILogicalExpression>(pair.first, pair.second.getValue())); |
| } |
| for (Pair<LogicalVariable, Mutable<ILogicalExpression>> pair : keyListsArg) { |
| listRight.add(new Pair<LogicalVariable, ILogicalExpression>(pair.first, pair.second.getValue())); |
| } |
| |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(listLeft, listRight); |
| |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| int sizeOp = op.getNestedPlans().size(); |
| int sizeArg = gbyOpArg.getNestedPlans().size(); |
| if (sizeOp != sizeArg) { |
| return Boolean.FALSE; |
| } |
| |
| GroupByOperator argOp = (GroupByOperator) arg; |
| List<ILogicalPlan> plans = op.getNestedPlans(); |
| List<ILogicalPlan> plansArg = argOp.getNestedPlans(); |
| for (int i = 0; i < plans.size(); i++) { |
| List<Mutable<ILogicalOperator>> roots = plans.get(i).getRoots(); |
| List<Mutable<ILogicalOperator>> rootsArg = plansArg.get(i).getRoots(); |
| if (roots.size() != rootsArg.size()) { |
| return Boolean.FALSE; |
| } |
| for (int j = 0; j < roots.size(); j++) { |
| ILogicalOperator topOp1 = roots.get(j).getValue(); |
| ILogicalOperator topOp2 = rootsArg.get(j).getValue(); |
| isomorphic = IsomorphismUtilities.isOperatorIsomorphicPlanSegment(topOp1, topOp2); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| } |
| } |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitLimitOperator(LimitOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.LIMIT) { |
| return Boolean.FALSE; |
| } |
| LimitOperator limitOpArg = (LimitOperator) copyAndSubstituteVar(op, arg); |
| if (op.getOffset() != limitOpArg.getOffset()) { |
| return Boolean.FALSE; |
| } |
| boolean isomorphic = op.getMaxObjects().getValue().equals(limitOpArg.getMaxObjects().getValue()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitInnerJoinOperator(InnerJoinOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.INNERJOIN) { |
| return Boolean.FALSE; |
| } |
| InnerJoinOperator joinOpArg = (InnerJoinOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = op.getCondition().getValue().equals(joinOpArg.getCondition().getValue()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitLeftOuterJoinOperator(LeftOuterJoinOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.LEFTOUTERJOIN) { |
| return Boolean.FALSE; |
| } |
| LeftOuterJoinOperator joinOpArg = (LeftOuterJoinOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = op.getCondition().getValue().equals(joinOpArg.getCondition().getValue()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitNestedTupleSourceOperator(NestedTupleSourceOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.NESTEDTUPLESOURCE) { |
| return Boolean.FALSE; |
| } |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitOrderOperator(OrderOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.ORDER) { |
| return Boolean.FALSE; |
| } |
| OrderOperator orderOpArg = (OrderOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = compareIOrderAndExpressions(op.getOrderExpressions(), orderOpArg.getOrderExpressions()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitAssignOperator(AssignOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.ASSIGN) { |
| return Boolean.FALSE; |
| } |
| AssignOperator assignOpArg = (AssignOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered( |
| getPairList(op.getVariables(), op.getExpressions()), |
| getPairList(assignOpArg.getVariables(), assignOpArg.getExpressions())); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitSelectOperator(SelectOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.SELECT) { |
| return Boolean.FALSE; |
| } |
| SelectOperator selectOpArg = (SelectOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = op.getCondition().getValue().equals(selectOpArg.getCondition().getValue()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitProjectOperator(ProjectOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.PROJECT) { |
| return Boolean.FALSE; |
| } |
| ProjectOperator projectOpArg = (ProjectOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), projectOpArg.getVariables()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitReplicateOperator(ReplicateOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.REPLICATE) { |
| return Boolean.FALSE; |
| } |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitSplitOperator(SplitOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.SPLIT) { |
| return Boolean.FALSE; |
| } |
| SplitOperator sOpArg = (SplitOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = op.getBranchingExpression().getValue().equals(sOpArg.getBranchingExpression().getValue()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitMaterializeOperator(MaterializeOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.MATERIALIZE) { |
| return Boolean.FALSE; |
| } |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitScriptOperator(ScriptOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.SCRIPT) { |
| return Boolean.FALSE; |
| } |
| ScriptOperator scriptOpArg = (ScriptOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = op.getScriptDescription().equals(scriptOpArg.getScriptDescription()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitSubplanOperator(SubplanOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.SUBPLAN) { |
| return Boolean.FALSE; |
| } |
| SubplanOperator subplanOpArg = (SubplanOperator) copyAndSubstituteVar(op, arg); |
| List<ILogicalPlan> plans = op.getNestedPlans(); |
| List<ILogicalPlan> plansArg = subplanOpArg.getNestedPlans(); |
| for (int i = 0; i < plans.size(); i++) { |
| List<Mutable<ILogicalOperator>> roots = plans.get(i).getRoots(); |
| List<Mutable<ILogicalOperator>> rootsArg = plansArg.get(i).getRoots(); |
| if (roots.size() == rootsArg.size()) { |
| return Boolean.FALSE; |
| } |
| for (int j = 0; j < roots.size(); j++) { |
| ILogicalOperator topOp1 = roots.get(j).getValue(); |
| ILogicalOperator topOp2 = rootsArg.get(j).getValue(); |
| boolean isomorphic = IsomorphismUtilities.isOperatorIsomorphicPlanSegment(topOp1, topOp2); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| } |
| } |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitUnionOperator(UnionAllOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.UNIONALL) { |
| return Boolean.FALSE; |
| } |
| UnionAllOperator unionOpArg = (UnionAllOperator) copyAndSubstituteVar(op, arg); |
| List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> mapping = op.getVariableMappings(); |
| List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> mappingArg = unionOpArg.getVariableMappings(); |
| if (mapping.size() != mappingArg.size()) { |
| return Boolean.FALSE; |
| } |
| return VariableUtilities.varListEqualUnordered(mapping, mappingArg); |
| } |
| |
| @Override |
| public Boolean visitIntersectOperator(IntersectOperator op, ILogicalOperator arg) throws AlgebricksException { |
| if (op.getOperatorTag() != LogicalOperatorTag.INTERSECT) { |
| return Boolean.FALSE; |
| } |
| IntersectOperator intersetOpArg = (IntersectOperator) copyAndSubstituteVar(op, arg); |
| List<LogicalVariable> variables = op.getOutputVars(); |
| List<LogicalVariable> variablesArg = intersetOpArg.getOutputVars(); |
| if (variables.size() != variablesArg.size()) { |
| return Boolean.FALSE; |
| } |
| if (!VariableUtilities.varListEqualUnordered(variables, variablesArg)) { |
| return Boolean.FALSE; |
| } |
| |
| if (op.getNumInput() != intersetOpArg.getNumInput()) { |
| return Boolean.FALSE; |
| } |
| for (int i = 0; i < op.getNumInput(); i++) { |
| if (!VariableUtilities.varListEqualUnordered(op.getInputVariables(i), intersetOpArg.getInputVariables(i))) { |
| return Boolean.FALSE; |
| } |
| } |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitUnnestOperator(UnnestOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.UNNEST) { |
| return Boolean.FALSE; |
| } |
| UnnestOperator unnestOpArg = (UnnestOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), unnestOpArg.getVariables()) |
| && variableEqual(op.getPositionalVariable(), unnestOpArg.getPositionalVariable()); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| isomorphic = op.getExpressionRef().getValue().equals(unnestOpArg.getExpressionRef().getValue()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitUnnestMapOperator(UnnestMapOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.UNNEST_MAP) { |
| return Boolean.FALSE; |
| } |
| UnnestMapOperator unnestOpArg = (UnnestMapOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), unnestOpArg.getVariables()); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| isomorphic = op.getExpressionRef().getValue().equals(unnestOpArg.getExpressionRef().getValue()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitLeftOuterUnnestMapOperator(LeftOuterUnnestMapOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.LEFT_OUTER_UNNEST_MAP) { |
| return Boolean.FALSE; |
| } |
| LeftOuterUnnestMapOperator loUnnestOpArg = (LeftOuterUnnestMapOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), loUnnestOpArg.getVariables()); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| isomorphic = op.getExpressionRef().getValue().equals(loUnnestOpArg.getExpressionRef().getValue()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitDataScanOperator(DataSourceScanOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.DATASOURCESCAN) { |
| return Boolean.FALSE; |
| } |
| DataSourceScanOperator argScan = (DataSourceScanOperator) arg; |
| if (!argScan.getDataSource().toString().equals(op.getDataSource().toString())) { |
| return Boolean.FALSE; |
| } |
| DataSourceScanOperator scanOpArg = (DataSourceScanOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), scanOpArg.getVariables()) |
| && op.getDataSource().toString().equals(scanOpArg.getDataSource().toString()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitDistinctOperator(DistinctOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.DISTINCT) { |
| return Boolean.FALSE; |
| } |
| DistinctOperator distinctOpArg = (DistinctOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = compareExpressions(op.getExpressions(), distinctOpArg.getExpressions()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitExchangeOperator(ExchangeOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.EXCHANGE) { |
| return Boolean.FALSE; |
| } |
| // require the same partition property |
| if (!(op.getPhysicalOperator().getOperatorTag() == aop.getPhysicalOperator().getOperatorTag())) { |
| return Boolean.FALSE; |
| } |
| variableMapping.clear(); |
| IsomorphismUtilities.mapVariablesTopDown(op, arg, variableMapping); |
| IPhysicalPropertiesVector properties = op.getPhysicalOperator().getDeliveredProperties(); |
| IPhysicalPropertiesVector propertiesArg = aop.getPhysicalOperator().getDeliveredProperties(); |
| if (properties == null && propertiesArg == null) { |
| return Boolean.TRUE; |
| } |
| if (properties == null || propertiesArg == null) { |
| return Boolean.FALSE; |
| } |
| IPartitioningProperty partProp = properties.getPartitioningProperty(); |
| IPartitioningProperty partPropArg = propertiesArg.getPartitioningProperty(); |
| if (!partProp.getPartitioningType().equals(partPropArg.getPartitioningType())) { |
| return Boolean.FALSE; |
| } |
| List<LogicalVariable> columns = new ArrayList<LogicalVariable>(); |
| partProp.getColumns(columns); |
| List<LogicalVariable> columnsArg = new ArrayList<LogicalVariable>(); |
| partPropArg.getColumns(columnsArg); |
| if (columns.size() != columnsArg.size()) { |
| return Boolean.FALSE; |
| } |
| if (columns.size() == 0) { |
| return Boolean.TRUE; |
| } |
| for (int i = 0; i < columnsArg.size(); i++) { |
| LogicalVariable rightVar = columnsArg.get(i); |
| LogicalVariable leftVar = variableMapping.get(rightVar); |
| if (leftVar != null) { |
| columnsArg.set(i, leftVar); |
| } |
| } |
| return VariableUtilities.varListEqualUnordered(columns, columnsArg); |
| } |
| |
| @Override |
| public Boolean visitWriteOperator(WriteOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.WRITE) { |
| return Boolean.FALSE; |
| } |
| WriteOperator writeOpArg = (WriteOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), writeOpArg.getSchema()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitDistributeResultOperator(DistributeResultOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.DISTRIBUTE_RESULT) { |
| return Boolean.FALSE; |
| } |
| DistributeResultOperator writeOpArg = (DistributeResultOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), writeOpArg.getSchema()); |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitWriteResultOperator(WriteResultOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.WRITE_RESULT) { |
| return Boolean.FALSE; |
| } |
| WriteResultOperator writeOpArg = (WriteResultOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), writeOpArg.getSchema()); |
| if (!op.getDataSource().equals(writeOpArg.getDataSource())) { |
| isomorphic = false; |
| } |
| if (!op.getPayloadExpression().equals(writeOpArg.getPayloadExpression())) { |
| isomorphic = false; |
| } |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitInsertDeleteUpsertOperator(InsertDeleteUpsertOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE_UPSERT) { |
| return Boolean.FALSE; |
| } |
| InsertDeleteUpsertOperator insertOpArg = (InsertDeleteUpsertOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), insertOpArg.getSchema()); |
| if (!op.getDataSource().equals(insertOpArg.getDataSource())) { |
| isomorphic = false; |
| } |
| if (!op.getPayloadExpression().equals(insertOpArg.getPayloadExpression())) { |
| isomorphic = false; |
| } |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitIndexInsertDeleteUpsertOperator(IndexInsertDeleteUpsertOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.INDEX_INSERT_DELETE_UPSERT) { |
| return Boolean.FALSE; |
| } |
| IndexInsertDeleteUpsertOperator insertOpArg = (IndexInsertDeleteUpsertOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), insertOpArg.getSchema()); |
| if (!op.getDataSourceIndex().equals(insertOpArg.getDataSourceIndex())) { |
| isomorphic = false; |
| } |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitTokenizeOperator(TokenizeOperator op, ILogicalOperator arg) throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.TOKENIZE) { |
| return Boolean.FALSE; |
| } |
| TokenizeOperator tokenizeOpArg = (TokenizeOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getSchema(), tokenizeOpArg.getSchema()); |
| if (!op.getDataSourceIndex().equals(tokenizeOpArg.getDataSourceIndex())) { |
| isomorphic = false; |
| } |
| return isomorphic; |
| } |
| |
| @Override |
| public Boolean visitSinkOperator(SinkOperator op, ILogicalOperator arg) throws AlgebricksException { |
| return true; |
| } |
| |
| private Boolean compareExpressions(List<Mutable<ILogicalExpression>> opExprs, |
| List<Mutable<ILogicalExpression>> argExprs) { |
| if (opExprs.size() != argExprs.size()) { |
| return Boolean.FALSE; |
| } |
| for (int i = 0; i < opExprs.size(); i++) { |
| boolean isomorphic = opExprs.get(i).getValue().equals(argExprs.get(i).getValue()); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| } |
| return Boolean.TRUE; |
| } |
| |
| private Boolean compareIOrderAndExpressions(List<Pair<IOrder, Mutable<ILogicalExpression>>> opOrderExprs, |
| List<Pair<IOrder, Mutable<ILogicalExpression>>> argOrderExprs) { |
| if (opOrderExprs.size() != argOrderExprs.size()) { |
| return Boolean.FALSE; |
| } |
| for (int i = 0; i < opOrderExprs.size(); i++) { |
| boolean isomorphic = opOrderExprs.get(i).first.equals(argOrderExprs.get(i).first); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| isomorphic = opOrderExprs.get(i).second.getValue().equals(argOrderExprs.get(i).second.getValue()); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| } |
| return Boolean.TRUE; |
| } |
| |
| private ILogicalOperator copyAndSubstituteVar(ILogicalOperator op, ILogicalOperator argOp) |
| throws AlgebricksException { |
| ILogicalOperator newOp = OperatorManipulationUtil.deepCopy(argOp); |
| variableMapping.clear(); |
| IsomorphismUtilities.mapVariablesTopDown(op, argOp, variableMapping); |
| |
| List<LogicalVariable> liveVars = new ArrayList<LogicalVariable>(); |
| if (argOp.getInputs().size() > 0) { |
| for (int i = 0; i < argOp.getInputs().size(); i++) { |
| VariableUtilities.getLiveVariables(argOp.getInputs().get(i).getValue(), liveVars); |
| } |
| } |
| List<LogicalVariable> producedVars = new ArrayList<LogicalVariable>(); |
| VariableUtilities.getProducedVariables(argOp, producedVars); |
| List<LogicalVariable> producedVarsNew = new ArrayList<LogicalVariable>(); |
| VariableUtilities.getProducedVariables(op, producedVarsNew); |
| |
| if (producedVars.size() != producedVarsNew.size()) { |
| return newOp; |
| } |
| for (Entry<LogicalVariable, LogicalVariable> map : variableMapping.entrySet()) { |
| if (liveVars.contains(map.getKey())) { |
| VariableUtilities.substituteVariables(newOp, map.getKey(), map.getValue(), null); |
| } |
| } |
| for (int i = 0; i < producedVars.size(); i++) { |
| VariableUtilities.substituteVariables(newOp, producedVars.get(i), producedVarsNew.get(i), null); |
| } |
| return newOp; |
| } |
| |
| public List<Pair<LogicalVariable, ILogicalExpression>> getPairList(List<LogicalVariable> vars, |
| List<Mutable<ILogicalExpression>> exprs) throws AlgebricksException { |
| List<Pair<LogicalVariable, ILogicalExpression>> list = new ArrayList<Pair<LogicalVariable, ILogicalExpression>>(); |
| if (vars.size() != exprs.size()) { |
| throw new AlgebricksException("variable list size does not equal to expression list size "); |
| } |
| for (int i = 0; i < vars.size(); i++) { |
| list.add(new Pair<LogicalVariable, ILogicalExpression>(vars.get(i), exprs.get(i).getValue())); |
| } |
| return list; |
| } |
| |
| private static boolean variableEqual(LogicalVariable var, LogicalVariable varArg) { |
| if (var == null && varArg == null) { |
| return true; |
| } |
| if (var.equals(varArg)) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| @Override |
| public Boolean visitLeftOuterUnnestOperator(LeftOuterUnnestOperator op, ILogicalOperator arg) |
| throws AlgebricksException { |
| AbstractLogicalOperator aop = (AbstractLogicalOperator) arg; |
| if (aop.getOperatorTag() != LogicalOperatorTag.LEFT_OUTER_UNNEST) { |
| return Boolean.FALSE; |
| } |
| LeftOuterUnnestOperator unnestOpArg = (LeftOuterUnnestOperator) copyAndSubstituteVar(op, arg); |
| boolean isomorphic = VariableUtilities.varListEqualUnordered(op.getVariables(), unnestOpArg.getVariables()) |
| && variableEqual(op.getPositionalVariable(), unnestOpArg.getPositionalVariable()); |
| if (!isomorphic) { |
| return Boolean.FALSE; |
| } |
| isomorphic = op.getExpressionRef().getValue().equals(unnestOpArg.getExpressionRef().getValue()); |
| return isomorphic; |
| } |
| |
| } |