You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by bu...@apache.org on 2015/06/17 03:59:40 UTC

incubator-asterixdb git commit: AsterixDB changes for fixing issue873.

Repository: incubator-asterixdb
Updated Branches:
  refs/heads/master 1445153fd -> e05df7be2


AsterixDB changes for fixing issue873.

For example, in the following query plan, the change lets the optimizer recognize that $12 and $20 are equivalent.
Therefore, HASH_PARTITION_EXCHANGE [$$12] can be replaced by ONE_TO_ONE_EXCHANGE.

-- COMMIT  |PARTITIONED|
  project ([$$12])
  -- STREAM_PROJECT  |PARTITIONED|
    exchange
    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
      delete from TinySocial:TweetMessages from %0->$$4 partitioned by [%0->$$12]
      -- INSERT_DELETE  |PARTITIONED|
        exchange
        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
          materialize
          -- MATERIALIZE  |PARTITIONED|
            exchange
            -- HASH_PARTITION_EXCHANGE [$$12]  |PARTITIONED|
              assign [$$12] <- [function-call: asterix:field-access-by-index, Args:[%0->$$4, AInt32: {0}]]
              -- ASSIGN  |PARTITIONED|
                project ([$$4])
                -- STREAM_PROJECT  |PARTITIONED|
                  assign [$$4] <- [function-call: asterix:open-record-constructor, Args:[AString: {tweetid}, %0->$$14, AString: {user}, function-call: asterix:field-access-by-index, Args:[%0->$$0, AInt32: {1}], AString: {sender-location}, function-call: asterix:field-access-by-index, Args:[%0->$$0, AInt32: {2}], AString: {send-time}, function-call: asterix:field-access-by-index, Args:[%0->$$0, AInt32: {3}], AString: {referred-topics}, function-call: asterix:field-access-by-index, Args:[%0->$$0, AInt32: {4}], AString: {message-text}, function-call: asterix:field-access-by-index, Args:[%0->$$0, AInt32: {5}]]]
                  -- ASSIGN  |PARTITIONED|
                    exchange
                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                      unnest-map [$$14, $$0] <- function-call: asterix:index-search, Args:[AString: {TweetMessages}, AInt32: {0}, AString: {TinySocial}, AString: {TweetMessages}, ABoolean: {false}, ABoolean: {false}, ABoolean: {false}, AInt32: {1}, %0->$$20, AInt32: {1}, %0->$$21, TRUE, TRUE, TRUE]
                      -- BTREE_SEARCH  |PARTITIONED|
                        exchange
                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                          assign [$$20, $$21] <- [AString: {15}, AString: {15}]
                          -- ASSIGN  |PARTITIONED|
                            empty-tuple-source
                            -- EMPTY_TUPLE_SOURCE  |PARTITIONED|

Change-Id: Ife8c378a62cdbbcd8c19b521de246162f1f3d6ec
Reviewed-on: https://asterix-gerrit.ics.uci.edu/267
Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
Reviewed-by: Wenhai Li <lw...@yahoo.com>
Reviewed-by: Ildar Absalyamov <il...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/commit/e05df7be
Tree: http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/tree/e05df7be
Diff: http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/diff/e05df7be

Branch: refs/heads/master
Commit: e05df7be235057d706c79db6122e7e7235017f9b
Parents: 1445153
Author: Yingyi Bu <bu...@gmail.com>
Authored: Tue Jun 16 11:03:39 2015 -0700
Committer: Yingyi Bu <bu...@gmail.com>
Committed: Tue Jun 16 18:54:02 2015 -0700

----------------------------------------------------------------------
 .../asterix/optimizer/base/RuleCollections.java |   2 +
 ...quivalenceClassForRecordConstructorRule.java | 127 +++++++++++++++++++
 .../optimizer/rules/UnnestToDataScanRule.java   |  11 +-
 .../optimizer/rules/am/BTreeAccessMethod.java   |  11 +-
 .../rules/util/EquivalenceClassUtils.java       |  99 +++++++++++++++
 .../results/disjunction-to-join-delete-1.plan   |   2 +-
 .../results/disjunction-to-join-delete-2.plan   |   2 +-
 .../optimizerts/results/scan-delete-all.plan    |   4 +-
 .../scan-delete-rtree-secondary-index.plan      |   2 +-
 .../optimizerts/results/scan-delete.plan        |   4 +-
 ...ont-skip-primary-index-search-in-delete.plan |   2 +-
 .../skip-ngram-index-search-in-delete.plan      |   2 +-
 .../skip-rtree-index-search-in-delete.plan      |   2 +-
 ...-secondary-btree-index-search-in-delete.plan |   2 +-
 .../skip-word-index-search-in-delete.plan       |   2 +-
 15 files changed, 259 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/RuleCollections.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/RuleCollections.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/RuleCollections.java
index 7e58a9c..b90442f 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/RuleCollections.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/RuleCollections.java
@@ -32,6 +32,7 @@ import edu.uci.ics.asterix.optimizer.rules.ExtractOrderExpressionsRule;
 import edu.uci.ics.asterix.optimizer.rules.FeedScanCollectionToUnnest;
 import edu.uci.ics.asterix.optimizer.rules.FuzzyEqRule;
 import edu.uci.ics.asterix.optimizer.rules.IfElseToSwitchCaseFunctionRule;
+import edu.uci.ics.asterix.optimizer.rules.AddEquivalenceClassForRecordConstructorRule;
 import edu.uci.ics.asterix.optimizer.rules.InlineUnnestFunctionRule;
 import edu.uci.ics.asterix.optimizer.rules.IntroduceAutogenerateIDRule;
 import edu.uci.ics.asterix.optimizer.rules.IntroduceDynamicTypeCastForExternalFunctionRule;
@@ -286,6 +287,7 @@ public final class RuleCollections {
         physicalRewritesAllLevels.add(new SetAlgebricksPhysicalOperatorsRule());
         physicalRewritesAllLevels.add(new SetAsterixPhysicalOperatorsRule());
         physicalRewritesAllLevels.add(new IntroduceInstantLockSearchCallbackRule());
+        physicalRewritesAllLevels.add(new AddEquivalenceClassForRecordConstructorRule());
         physicalRewritesAllLevels.add(new EnforceStructuralPropertiesRule());
         physicalRewritesAllLevels.add(new RemoveSortInFeedIngestionRule());
         physicalRewritesAllLevels.add(new IntroHashPartitionMergeExchange());

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/AddEquivalenceClassForRecordConstructorRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/AddEquivalenceClassForRecordConstructorRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/AddEquivalenceClassForRecordConstructorRule.java
new file mode 100644
index 0000000..3ac3f6e
--- /dev/null
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/AddEquivalenceClassForRecordConstructorRule.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed 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 from
+ * 
+ *     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 edu.uci.ics.asterix.optimizer.rules;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.mortbay.util.SingletonList;
+
+import edu.uci.ics.asterix.aql.util.FunctionUtils;
+import edu.uci.ics.asterix.om.base.AInt32;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.EquivalenceClass;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+import edu.uci.ics.hyracks.algebricks.rewriter.util.PhysicalOptimizationsUtil;
+
+/**
+ * Adds equivalent classes for record-constructors.
+ * For example, for $x:=record-constructor("field1": $v, "field2": $t),
+ * two equivalent classes will be added:
+ * <$v, field-access-by-index($x, 0)>
+ * <$t, field-access-by-index($x, 1)>
+ * 
+ * @author yingyi
+ */
+public class AddEquivalenceClassForRecordConstructorRule implements IAlgebraicRewriteRule {
+
+    @Override
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+        return false;
+    }
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+        AbstractLogicalOperator op = (AbstractLogicalOperator) opRef.getValue();
+        if (op.getOperatorTag() != LogicalOperatorTag.ASSIGN) {
+            return false;
+        }
+        // Computes FDs and equivalence classes for the operator.
+        PhysicalOptimizationsUtil.computeFDsAndEquivalenceClasses(op, context);
+        AssignOperator assignOp = (AssignOperator) op;
+        List<LogicalVariable> vars = assignOp.getVariables();
+        List<Mutable<ILogicalExpression>> exprRefs = assignOp.getExpressions();
+        return addEquivalenceClassesForRecordConstructor(vars, exprRefs, assignOp, context);
+    }
+
+    private boolean addEquivalenceClassesForRecordConstructor(List<LogicalVariable> vars,
+            List<Mutable<ILogicalExpression>> exprRefs, AssignOperator assignOp, IOptimizationContext context) {
+        boolean changed = false;
+        for (int exprIndex = 0; exprIndex < exprRefs.size(); ++exprIndex) {
+            ILogicalExpression expr = exprRefs.get(exprIndex).getValue();
+            if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+                ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) expr;
+                FunctionIdentifier fid = funcExpr.getFunctionIdentifier();
+                if (fid == AsterixBuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR
+                        || fid == AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR) {
+                    changed |= propagateEquivalenceClassesForRecordConstructor(vars.get(exprIndex), funcExpr, assignOp,
+                            context);
+                }
+            }
+        }
+        return changed;
+    }
+
+    @SuppressWarnings("unchecked")
+    private boolean propagateEquivalenceClassesForRecordConstructor(LogicalVariable recordVar,
+            ScalarFunctionCallExpression funcExpr, AssignOperator assignOp, IOptimizationContext context) {
+        List<Mutable<ILogicalExpression>> argRefs = funcExpr.getArguments();
+        boolean changed = false;
+        // Only odd position arguments are field value expressions.
+        for (int parameterIndex = 1; parameterIndex < argRefs.size(); parameterIndex += 2) {
+            ILogicalExpression fieldExpr = argRefs.get(parameterIndex).getValue();
+            // Adds equivalent classes if a field is from a variable reference.
+            if (fieldExpr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+                VariableReferenceExpression varExpr = (VariableReferenceExpression) fieldExpr;
+                LogicalVariable fieldVar = varExpr.getVariableReference();
+                Map<LogicalVariable, EquivalenceClass> ecs = context.getEquivalenceClassMap(assignOp);
+                if (ecs == null) {
+                    ecs = new HashMap<LogicalVariable, EquivalenceClass>();
+                    context.putEquivalenceClassMap(assignOp, ecs);
+                }
+                ILogicalExpression expr = new ScalarFunctionCallExpression(
+                        FunctionUtils.getFunctionInfo(AsterixBuiltinFunctions.FIELD_ACCESS_BY_INDEX),
+                        new MutableObject<ILogicalExpression>(new VariableReferenceExpression(recordVar)),
+                        new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(
+                                new AInt32(parameterIndex / 2))))); // Every two parameters corresponds to a field.
+                EquivalenceClass equivClass = new EquivalenceClass(SingletonList.newSingletonList(fieldVar), fieldVar,
+                        SingletonList.newSingletonList(expr));
+                ecs.put(fieldVar, equivClass);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/UnnestToDataScanRule.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/UnnestToDataScanRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/UnnestToDataScanRule.java
index e644459..1104c53 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/UnnestToDataScanRule.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/UnnestToDataScanRule.java
@@ -34,8 +34,10 @@ import edu.uci.ics.asterix.metadata.utils.DatasetUtils;
 import edu.uci.ics.asterix.om.base.AString;
 import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
 import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.types.ARecordType;
 import edu.uci.ics.asterix.om.types.ATypeTag;
 import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.asterix.optimizer.rules.util.EquivalenceClassUtils;
 import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
 import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
@@ -116,13 +118,19 @@ public class UnnestToDataScanRule implements IAlgebraicRewriteRule {
                     }
                 }
                 v.add(unnest.getVariable());
-                DataSourceScanOperator scan = new DataSourceScanOperator(v, metadataProvider.findDataSource(asid));
+                AqlDataSource dataSource = metadataProvider.findDataSource(asid);
+                DataSourceScanOperator scan = new DataSourceScanOperator(v, dataSource);
                 List<Mutable<ILogicalOperator>> scanInpList = scan.getInputs();
                 scanInpList.addAll(unnest.getInputs());
                 opRef.setValue(scan);
                 addPrimaryKey(v, context);
                 context.computeAndSetTypeEnvironmentForOperator(scan);
 
+                // Adds equivalence classes --- one equivalent class between a primary key
+                // variable and a record field-access expression.
+                IAType[] schemaTypes = dataSource.getSchemaTypes();
+                ARecordType recordType = (ARecordType) schemaTypes[schemaTypes.length - 1];
+                EquivalenceClassUtils.addEquivalenceClassesForPrimaryIndexAccess(scan, v, recordType, dataset, context);
                 return true;
             }
 
@@ -235,4 +243,5 @@ public class UnnestToDataScanRule implements IAlgebraicRewriteRule {
         String argument = ((AString) acv2.getObject()).getStringValue();
         return argument;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/am/BTreeAccessMethod.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/am/BTreeAccessMethod.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/am/BTreeAccessMethod.java
index e6a3470..22f3b80 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/am/BTreeAccessMethod.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/am/BTreeAccessMethod.java
@@ -34,6 +34,7 @@ import edu.uci.ics.asterix.common.config.DatasetConfig.IndexType;
 import edu.uci.ics.asterix.metadata.entities.Dataset;
 import edu.uci.ics.asterix.metadata.entities.Index;
 import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.optimizer.rules.util.EquivalenceClassUtils;
 import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
 import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
@@ -493,8 +494,9 @@ public class BTreeAccessMethod implements IAccessMethod {
             } catch (IOException e) {
                 throw new AlgebricksException(e);
             }
-            primaryIndexUnnestOp = new UnnestMapOperator(dataSourceOp.getVariables(),
-                    secondaryIndexUnnestOp.getExpressionRef(), primaryIndexOutputTypes, retainInput);
+            List<LogicalVariable> scanVariables = dataSourceOp.getVariables();
+            primaryIndexUnnestOp = new UnnestMapOperator(scanVariables, secondaryIndexUnnestOp.getExpressionRef(),
+                    primaryIndexOutputTypes, retainInput);
             primaryIndexUnnestOp.getInputs().add(new MutableObject<ILogicalOperator>(inputOp));
 
             if (!primaryIndexPostProccessingIsNeeded) {
@@ -508,6 +510,11 @@ public class BTreeAccessMethod implements IAccessMethod {
                     conditionRef.setValue(null);
                 }
             }
+
+            // Adds equivalence classes --- one equivalent class between a primary key
+            // variable and a record field-access expression.
+            EquivalenceClassUtils.addEquivalenceClassesForPrimaryIndexAccess(primaryIndexUnnestOp, scanVariables,
+                    recordType, dataset, context);
         }
 
         return primaryIndexUnnestOp;

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/util/EquivalenceClassUtils.java
----------------------------------------------------------------------
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/util/EquivalenceClassUtils.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/util/EquivalenceClassUtils.java
new file mode 100644
index 0000000..4eab720
--- /dev/null
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/util/EquivalenceClassUtils.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed 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 from
+ * 
+ *     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 edu.uci.ics.asterix.optimizer.rules.util;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.mortbay.util.SingletonList;
+
+import edu.uci.ics.asterix.aql.util.FunctionUtils;
+import edu.uci.ics.asterix.common.config.DatasetConfig.DatasetType;
+import edu.uci.ics.asterix.metadata.entities.Dataset;
+import edu.uci.ics.asterix.metadata.entities.InternalDatasetDetails;
+import edu.uci.ics.asterix.om.base.AInt32;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.EquivalenceClass;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+
+public class EquivalenceClassUtils {
+
+    /**
+     * Adds equivalent classes for primary index accesses, including unnest-map for
+     * primary index access and data source scan through primary index ---
+     * one equivalent class between a primary key variable and a record field-access expression.
+     * 
+     * @param operator
+     *            , the primary index access operator.
+     * @param indexSearchVars
+     *            , the returned variables from primary index access. The last variable
+     *            is the record variable.
+     * @param recordType
+     *            , the record type of an index payload record.
+     * @param dataset
+     *            , the accessed dataset.
+     * @param context
+     *            , the optimization context.
+     * @throws AlgebricksException
+     */
+    @SuppressWarnings("unchecked")
+    public static void addEquivalenceClassesForPrimaryIndexAccess(ILogicalOperator operator,
+            List<LogicalVariable> indexSearchVars, ARecordType recordType, Dataset dataset, IOptimizationContext context)
+            throws AlgebricksException {
+        if (dataset.getDatasetDetails().getDatasetType() != DatasetType.INTERNAL) {
+            return;
+        }
+        InternalDatasetDetails datasetDetails = (InternalDatasetDetails) dataset.getDatasetDetails();
+        List<List<String>> primaryKey = datasetDetails.getPrimaryKey();
+        Map<String, Integer> fieldNameToIndexMap = new HashMap<String, Integer>();
+        String[] fieldNames = recordType.getFieldNames();
+        for (int fieldIndex = 0; fieldIndex < fieldNames.length; ++fieldIndex) {
+            fieldNameToIndexMap.put(fieldNames[fieldIndex], fieldIndex);
+        }
+
+        LogicalVariable recordVar = indexSearchVars.get(indexSearchVars.size() - 1);
+        for (int pkIndex = 0; pkIndex < primaryKey.size(); ++pkIndex) {
+            String pkFieldName = primaryKey.get(pkIndex).get(0);
+            int fieldIndexInRecord = fieldNameToIndexMap.get(pkFieldName);
+            LogicalVariable var = indexSearchVars.get(pkIndex);
+            ILogicalExpression expr = new ScalarFunctionCallExpression(
+                    FunctionUtils.getFunctionInfo(AsterixBuiltinFunctions.FIELD_ACCESS_BY_INDEX),
+                    new MutableObject<ILogicalExpression>(new VariableReferenceExpression(recordVar)),
+                    new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(new AInt32(
+                            fieldIndexInRecord)))));
+            EquivalenceClass equivClass = new EquivalenceClass(SingletonList.newSingletonList(var), var,
+                    SingletonList.newSingletonList(expr));
+            Map<LogicalVariable, EquivalenceClass> equivalenceMap = context.getEquivalenceClassMap(operator);
+            if (equivalenceMap == null) {
+                equivalenceMap = new HashMap<LogicalVariable, EquivalenceClass>();
+                context.putEquivalenceClassMap(operator, equivalenceMap);
+            }
+            equivalenceMap.put(var, equivClass);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan b/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
index 5bb2d07..563a75b 100644
--- a/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
@@ -9,7 +9,7 @@
                 -- INSERT_DELETE  |PARTITIONED|
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                     -- MATERIALIZE  |PARTITIONED|
-                      -- HASH_PARTITION_EXCHANGE [$$12]  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                         -- ASSIGN  |PARTITIONED|
                           -- STREAM_PROJECT  |PARTITIONED|
                             -- ASSIGN  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan b/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
index 5e1f889..ba4c536 100644
--- a/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
@@ -9,7 +9,7 @@
                 -- INSERT_DELETE  |PARTITIONED|
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                     -- MATERIALIZE  |PARTITIONED|
-                      -- HASH_PARTITION_EXCHANGE [$$12]  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                         -- ASSIGN  |PARTITIONED|
                           -- STREAM_PROJECT  |PARTITIONED|
                             -- ASSIGN  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/scan-delete-all.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/scan-delete-all.plan b/asterix-app/src/test/resources/optimizerts/results/scan-delete-all.plan
index c241913..c2173fb 100644
--- a/asterix-app/src/test/resources/optimizerts/results/scan-delete-all.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/scan-delete-all.plan
@@ -4,11 +4,11 @@
       -- INSERT_DELETE  |PARTITIONED|
         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
           -- MATERIALIZE  |PARTITIONED|
-            -- HASH_PARTITION_EXCHANGE [$$20]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
               -- ASSIGN  |PARTITIONED|
                 -- STREAM_PROJECT  |PARTITIONED|
                   -- ASSIGN  |PARTITIONED|
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                       -- DATASOURCE_SCAN  |PARTITIONED|
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+                          -- EMPTY_TUPLE_SOURCE  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan b/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
index 2d3d8fc..691761d 100644
--- a/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
@@ -22,7 +22,7 @@
                     -- INSERT_DELETE  |PARTITIONED|
                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                         -- MATERIALIZE  |PARTITIONED|
-                          -- HASH_PARTITION_EXCHANGE [$$15]  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                             -- ASSIGN  |PARTITIONED|
                               -- STREAM_PROJECT  |PARTITIONED|
                                 -- ASSIGN  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/scan-delete.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/scan-delete.plan b/asterix-app/src/test/resources/optimizerts/results/scan-delete.plan
index 3a4bc84..cfe5d35 100644
--- a/asterix-app/src/test/resources/optimizerts/results/scan-delete.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/scan-delete.plan
@@ -4,7 +4,7 @@
       -- INSERT_DELETE  |PARTITIONED|
         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
           -- MATERIALIZE  |PARTITIONED|
-            -- HASH_PARTITION_EXCHANGE [$$22]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
               -- ASSIGN  |PARTITIONED|
                 -- STREAM_PROJECT  |PARTITIONED|
                   -- ASSIGN  |PARTITIONED|
@@ -13,4 +13,4 @@
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                           -- DATASOURCE_SCAN  |PARTITIONED|
                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/skip-index/dont-skip-primary-index-search-in-delete.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/skip-index/dont-skip-primary-index-search-in-delete.plan b/asterix-app/src/test/resources/optimizerts/results/skip-index/dont-skip-primary-index-search-in-delete.plan
index 0a66ccb..e2e6dff 100644
--- a/asterix-app/src/test/resources/optimizerts/results/skip-index/dont-skip-primary-index-search-in-delete.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/skip-index/dont-skip-primary-index-search-in-delete.plan
@@ -4,7 +4,7 @@
       -- INSERT_DELETE  |PARTITIONED|
         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
           -- MATERIALIZE  |PARTITIONED|
-            -- HASH_PARTITION_EXCHANGE [$$12]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
               -- ASSIGN  |PARTITIONED|
                 -- STREAM_PROJECT  |PARTITIONED|
                   -- ASSIGN  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan b/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
index 37c6587..c882d81 100644
--- a/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
@@ -9,7 +9,7 @@
                 -- INSERT_DELETE  |PARTITIONED|
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                     -- MATERIALIZE  |PARTITIONED|
-                      -- HASH_PARTITION_EXCHANGE [$$11]  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                         -- ASSIGN  |PARTITIONED|
                           -- STREAM_PROJECT  |PARTITIONED|
                             -- ASSIGN  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan b/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
index cf609cb..b69dfa3 100644
--- a/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
@@ -11,7 +11,7 @@
                     -- INSERT_DELETE  |PARTITIONED|
                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                         -- MATERIALIZE  |PARTITIONED|
-                          -- HASH_PARTITION_EXCHANGE [$$17]  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                             -- ASSIGN  |PARTITIONED|
                               -- STREAM_PROJECT  |PARTITIONED|
                                 -- ASSIGN  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan b/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
index 67ec849..c882d81 100644
--- a/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
@@ -9,7 +9,7 @@
                 -- INSERT_DELETE  |PARTITIONED|
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                     -- MATERIALIZE  |PARTITIONED|
-                      -- HASH_PARTITION_EXCHANGE [$$12]  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                         -- ASSIGN  |PARTITIONED|
                           -- STREAM_PROJECT  |PARTITIONED|
                             -- ASSIGN  |PARTITIONED|

http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/e05df7be/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
----------------------------------------------------------------------
diff --git a/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan b/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
index c3b9264..c882d81 100644
--- a/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
+++ b/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
@@ -9,7 +9,7 @@
                 -- INSERT_DELETE  |PARTITIONED|
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                     -- MATERIALIZE  |PARTITIONED|
-                      -- HASH_PARTITION_EXCHANGE [$$14]  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                         -- ASSIGN  |PARTITIONED|
                           -- STREAM_PROJECT  |PARTITIONED|
                             -- ASSIGN  |PARTITIONED|