optimization for disjunctive selection predicates
- add rule to rewrite a disjunction of eq-comparisons on the
same variable in a selection to a join
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 c2469dc..aa60c74 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
@@ -53,6 +53,7 @@
import edu.uci.ics.asterix.optimizer.rules.RemoveSortInFeedIngestionRule;
import edu.uci.ics.asterix.optimizer.rules.RemoveUnusedOneToOneEquiJoinRule;
import edu.uci.ics.asterix.optimizer.rules.ReplaceSinkOpWithCommitOpRule;
+import edu.uci.ics.asterix.optimizer.rules.DisjunctivePredicateToJoinRule;
import edu.uci.ics.asterix.optimizer.rules.SetAsterixPhysicalOperatorsRule;
import edu.uci.ics.asterix.optimizer.rules.SetClosedRecordConstructorsRule;
import edu.uci.ics.asterix.optimizer.rules.SimilarityCheckRule;
@@ -158,6 +159,7 @@
condPushDownAndJoinInference.add(new SimpleUnnestToProductRule());
condPushDownAndJoinInference.add(new ComplexUnnestToProductRule());
condPushDownAndJoinInference.add(new ComplexJoinInferenceRule());
+ condPushDownAndJoinInference.add(new DisjunctivePredicateToJoinRule());
condPushDownAndJoinInference.add(new PushSelectIntoJoinRule());
condPushDownAndJoinInference.add(new IntroJoinInsideSubplanRule());
condPushDownAndJoinInference.add(new PushAssignDownThroughProductRule());
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
new file mode 100644
index 0000000..0fb205d
--- /dev/null
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2014 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.HashSet;
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+
+import edu.uci.ics.asterix.om.base.AOrderedList;
+import edu.uci.ics.asterix.om.constants.AsterixConstantValue;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.types.AOrderedListType;
+import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+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.AbstractFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IndexedNLJoinExpressionAnnotation;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
+import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+public class DisjunctivePredicateToJoinRule implements IAlgebraicRewriteRule {
+
+ @Override
+ public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+ throws AlgebricksException {
+
+ SelectOperator select;
+ if ((select = asSelectOperator(opRef)) == null) {
+ return false;
+ }
+
+ AbstractFunctionCallExpression condEx;
+ if ((condEx = asFunctionCallExpression(select.getCondition(), AlgebricksBuiltinFunctions.OR)) == null) {
+ return false;
+ }
+
+ List<Mutable<ILogicalExpression>> args = condEx.getArguments();
+
+ VariableReferenceExpression varEx = null;
+ IAType valType = null;
+ HashSet<AsterixConstantValue> values = new HashSet<AsterixConstantValue>();
+
+ for (Mutable<ILogicalExpression> arg : args) {
+ AbstractFunctionCallExpression fctCall;
+ if ((fctCall = asFunctionCallExpression(arg, AlgebricksBuiltinFunctions.EQ)) == null) {
+ return false;
+ }
+
+ boolean haveConst = false;
+ boolean haveVar = false;
+ List<Mutable<ILogicalExpression>> fctArgs = fctCall.getArguments();
+ for (Mutable<ILogicalExpression> fctArg : fctArgs) {
+ final ILogicalExpression argExpr = fctArg.getValue();
+ switch (argExpr.getExpressionTag()) {
+ case CONSTANT:
+ haveConst = true;
+ AsterixConstantValue value = (AsterixConstantValue) ((ConstantExpression) argExpr).getValue();
+ if (valType == null) {
+ valType = value.getObject().getType();
+ } else if (!isCompatible(valType, value.getObject().getType())) {
+ return false;
+ }
+ values.add(value);
+ break;
+ case VARIABLE:
+ haveVar = true;
+ final VariableReferenceExpression varArg = (VariableReferenceExpression) argExpr;
+ if (varEx == null) {
+ varEx = varArg;
+ } else if (!varEx.getVariableReference().equals(varArg.getVariableReference())) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ }
+ if (!(haveVar && haveConst)) {
+ return false;
+ }
+ }
+
+ AOrderedList list = new AOrderedList(new AOrderedListType(valType, "orderedlist"));
+ for (AsterixConstantValue value : values) {
+ list.add(value.getObject());
+ }
+
+ EmptyTupleSourceOperator ets = new EmptyTupleSourceOperator();
+ context.computeAndSetTypeEnvironmentForOperator(ets);
+
+ ILogicalExpression cExp = new ConstantExpression(new AsterixConstantValue(list));
+ Mutable<ILogicalExpression> mutCExp = new MutableObject<ILogicalExpression>(cExp);
+ IFunctionInfo scanFctInfo = AsterixBuiltinFunctions
+ .getAsterixFunctionInfo(AsterixBuiltinFunctions.SCAN_COLLECTION);
+ UnnestingFunctionCallExpression scanExp = new UnnestingFunctionCallExpression(scanFctInfo, mutCExp);
+ LogicalVariable scanVar = context.newVar();
+ UnnestOperator unn = new UnnestOperator(scanVar, new MutableObject<ILogicalExpression>(scanExp));
+ unn.getInputs().add(new MutableObject<ILogicalOperator>(ets));
+ context.computeAndSetTypeEnvironmentForOperator(unn);
+
+ IFunctionInfo eqFctInfo = AsterixBuiltinFunctions.getAsterixFunctionInfo(AlgebricksBuiltinFunctions.EQ);
+ AbstractFunctionCallExpression eqExp = new ScalarFunctionCallExpression(eqFctInfo);
+ eqExp.getArguments().add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression(scanVar)));
+ eqExp.getArguments().add(new MutableObject<ILogicalExpression>(varEx.cloneExpression()));
+ eqExp.getAnnotations().put(IndexedNLJoinExpressionAnnotation.INSTANCE,
+ IndexedNLJoinExpressionAnnotation.INSTANCE);
+
+ InnerJoinOperator jOp = new InnerJoinOperator(new MutableObject<ILogicalExpression>(eqExp));
+ jOp.getInputs().add(new MutableObject<ILogicalOperator>(unn));
+ jOp.getInputs().add(select.getInputs().get(0));
+
+ opRef.setValue(jOp);
+ context.computeAndSetTypeEnvironmentForOperator(jOp);
+
+ return true;
+ }
+
+ @Override
+ public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) {
+ return false;
+ }
+
+ /**
+ * This checks the compatibility the types of the constants to ensure that the comparison behaves as expected
+ * when joining. Right now this compatibility is defined as type equality, but it could we relaxed.
+ * Once type promotion works correctly in all parts of the system, this check should not be needed anymore.
+ * (see https://code.google.com/p/asterixdb/issues/detail?id=716)
+ *
+ * @param t1
+ * one type
+ * @param t2
+ * another type
+ * @return true, if types are equal
+ */
+ private static boolean isCompatible(IAType t1, IAType t2) {
+ return t1.equals(t2);
+ }
+
+ // some helpers
+
+ private static SelectOperator asSelectOperator(ILogicalOperator op) {
+ return op.getOperatorTag() == LogicalOperatorTag.SELECT ? (SelectOperator) op : null;
+ }
+
+ private static SelectOperator asSelectOperator(Mutable<ILogicalOperator> op) {
+ return asSelectOperator(op.getValue());
+ }
+
+ private static AbstractFunctionCallExpression asFunctionCallExpression(ILogicalExpression ex, FunctionIdentifier fi) {
+ AbstractFunctionCallExpression fctCall = (ex.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL ? (AbstractFunctionCallExpression) ex
+ : null);
+ if (fctCall != null && (fi == null || fctCall.getFunctionIdentifier().equals(fi)))
+ return fctCall;
+ return null;
+ }
+
+ private static AbstractFunctionCallExpression asFunctionCallExpression(Mutable<ILogicalExpression> ex,
+ FunctionIdentifier fi) {
+ return asFunctionCallExpression(ex.getValue(), fi);
+ }
+
+}
diff --git a/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-1.aql b/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-1.aql
new file mode 100644
index 0000000..e46bd85
--- /dev/null
+++ b/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-1.aql
@@ -0,0 +1,14 @@
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type TestType as {
+ "id" : string,
+ "idx" : string,
+ "no-idx" : string
+};
+
+create dataset TestSet(TestType) primary key "id";
+create index TestSetIndex on TestSet(idx);
+
+delete $x from dataset TestSet where $x.id = "one" or $x.id = "two";
diff --git a/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-2.aql b/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-2.aql
new file mode 100644
index 0000000..9166f7ec
--- /dev/null
+++ b/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-2.aql
@@ -0,0 +1,14 @@
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type TestType as {
+ "id" : string,
+ "idx" : string,
+ "no-idx" : string
+};
+
+create dataset TestSet(TestType) primary key "id";
+create index TestSetIndex on TestSet(idx);
+
+delete $x from dataset TestSet where $x.idx = "one" or $x.idx = "two";
diff --git a/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-3.aql b/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-3.aql
new file mode 100644
index 0000000..c048ce2
--- /dev/null
+++ b/asterix-app/src/test/resources/optimizerts/queries/disjunction-to-join-delete-3.aql
@@ -0,0 +1,14 @@
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type TestType as {
+ "id" : string,
+ "idx" : string,
+ "no-idx" : string
+};
+
+create dataset TestSet(TestType) primary key "id";
+create index TestSetIndex on TestSet(idx);
+
+delete $x from dataset TestSet where $x.no-idx = "one" or $x.no-idx = "two";
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
new file mode 100644
index 0000000..5bb2d07
--- /dev/null
+++ b/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
@@ -0,0 +1,23 @@
+-- COMMIT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INDEX_INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$12] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$15(ASC)] |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$15] |PARTITIONED|
+ -- UNNEST |UNPARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
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
new file mode 100644
index 0000000..5e1f889
--- /dev/null
+++ b/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
@@ -0,0 +1,30 @@
+-- COMMIT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INDEX_INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$12] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$19(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- BROADCAST_EXCHANGE |PARTITIONED|
+ -- UNNEST |UNPARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
diff --git a/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-3.plan b/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-3.plan
new file mode 100644
index 0000000..55fc23c
--- /dev/null
+++ b/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-3.plan
@@ -0,0 +1,28 @@
+-- COMMIT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INDEX_INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$12] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- HYBRID_HASH_JOIN [$$15][$$13] |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$15] |PARTITIONED|
+ -- UNNEST |UNPARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$13] |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/asterix-app/src/test/resources/runtimets/queries/cross-dataverse/cross-dv02/cross-dv02.3.query.aql b/asterix-app/src/test/resources/runtimets/queries/cross-dataverse/cross-dv02/cross-dv02.3.query.aql
index 66b6e61..d0a1829 100644
--- a/asterix-app/src/test/resources/runtimets/queries/cross-dataverse/cross-dv02/cross-dv02.3.query.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/cross-dataverse/cross-dv02/cross-dv02.3.query.aql
@@ -8,4 +8,5 @@
for $l in dataset('Metadata.Dataset')
where $l.DataverseName='student' or $l.DataverseName='teacher'
+order by $l.DatasetName
return $l
diff --git a/asterix-app/src/test/resources/runtimets/queries/cross-dataverse/cross-dv04/cross-dv04.3.query.aql b/asterix-app/src/test/resources/runtimets/queries/cross-dataverse/cross-dv04/cross-dv04.3.query.aql
index 3745d9c..e355f87 100644
--- a/asterix-app/src/test/resources/runtimets/queries/cross-dataverse/cross-dv04/cross-dv04.3.query.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/cross-dataverse/cross-dv04/cross-dv04.3.query.aql
@@ -11,4 +11,5 @@
for $l in dataset('Metadata.Dataset')
where $l.DataverseName='student' or $l.DataverseName='teacher'
+order by $l.DatasetName
return $l
diff --git a/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.1.ddl.aql b/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.1.ddl.aql
new file mode 100644
index 0000000..a841d97
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.1.ddl.aql
@@ -0,0 +1,12 @@
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type TestType as {
+ "id" : string,
+ "idx" : string,
+ "no-idx" : string
+};
+
+create dataset TestSet(TestType) primary key "id";
+create index TestSetIndex on TestSet(idx);
diff --git a/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.2.update.aql b/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.2.update.aql
new file mode 100644
index 0000000..a66da81
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.2.update.aql
@@ -0,0 +1,9 @@
+use dataverse test;
+
+insert into dataset TestSet
+for $x in {{ "one", "two", "three" }}
+return {
+ "id" : $x,
+ "idx" : $x,
+ "no-idx" : $x
+};
diff --git a/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.3.query.aql b/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.3.query.aql
new file mode 100644
index 0000000..ee82720
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.3.query.aql
@@ -0,0 +1,5 @@
+use dataverse test;
+
+for $x in dataset TestSet
+where $x.id = "one" or $x.id = "two" or $x.id = "two"
+return $x
diff --git a/asterix-app/src/test/resources/runtimets/results/cross-dataverse/cross-dv02/cross-dv02.1.adm b/asterix-app/src/test/resources/runtimets/results/cross-dataverse/cross-dv02/cross-dv02.1.adm
index c2674b7..aac07d7 100644
--- a/asterix-app/src/test/resources/runtimets/results/cross-dataverse/cross-dv02/cross-dv02.1.adm
+++ b/asterix-app/src/test/resources/runtimets/results/cross-dataverse/cross-dv02/cross-dv02.1.adm
@@ -1,4 +1,4 @@
-{ "DataverseName": "student", "DatasetName": "gdstd", "DataTypeName": "stdType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Tue Sep 24 22:20:30 PDT 2013", "DatasetId": 102, "PendingOp": 0 }
-{ "DataverseName": "student", "DatasetName": "ugdstd", "DataTypeName": "stdType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Tue Sep 24 22:20:30 PDT 2013", "DatasetId": 101, "PendingOp": 0 }
-{ "DataverseName": "teacher", "DatasetName": "prof", "DataTypeName": "tchrType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Tue Sep 24 22:20:31 PDT 2013", "DatasetId": 103, "PendingOp": 0 }
-{ "DataverseName": "teacher", "DatasetName": "pstdoc", "DataTypeName": "tchrType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Tue Sep 24 22:20:31 PDT 2013", "DatasetId": 104, "PendingOp": 0 }
+{ "DataverseName": "student", "DatasetName": "gdstd", "DataTypeName": "stdType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Wed Apr 30 14:23:30 PDT 2014", "DatasetId": 102, "PendingOp": 0 }
+{ "DataverseName": "teacher", "DatasetName": "prof", "DataTypeName": "tchrType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Wed Apr 30 14:23:30 PDT 2014", "DatasetId": 103, "PendingOp": 0 }
+{ "DataverseName": "teacher", "DatasetName": "pstdoc", "DataTypeName": "tchrType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Wed Apr 30 14:23:31 PDT 2014", "DatasetId": 104, "PendingOp": 0 }
+{ "DataverseName": "student", "DatasetName": "ugdstd", "DataTypeName": "stdType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Wed Apr 30 14:23:30 PDT 2014", "DatasetId": 101, "PendingOp": 0 }
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/results/cross-dataverse/cross-dv04/cross-dv04.1.adm b/asterix-app/src/test/resources/runtimets/results/cross-dataverse/cross-dv04/cross-dv04.1.adm
index 7ff96e2..aac07d7 100644
--- a/asterix-app/src/test/resources/runtimets/results/cross-dataverse/cross-dv04/cross-dv04.1.adm
+++ b/asterix-app/src/test/resources/runtimets/results/cross-dataverse/cross-dv04/cross-dv04.1.adm
@@ -1,4 +1,4 @@
-{ "DataverseName": "student", "DatasetName": "gdstd", "DataTypeName": "stdType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Tue Sep 24 22:22:48 PDT 2013", "DatasetId": 110, "PendingOp": 0 }
-{ "DataverseName": "student", "DatasetName": "ugdstd", "DataTypeName": "stdType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Tue Sep 24 22:22:48 PDT 2013", "DatasetId": 109, "PendingOp": 0 }
-{ "DataverseName": "teacher", "DatasetName": "prof", "DataTypeName": "tchrType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Tue Sep 24 22:22:48 PDT 2013", "DatasetId": 111, "PendingOp": 0 }
-{ "DataverseName": "teacher", "DatasetName": "pstdoc", "DataTypeName": "tchrType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Tue Sep 24 22:22:48 PDT 2013", "DatasetId": 112, "PendingOp": 0 }
+{ "DataverseName": "student", "DatasetName": "gdstd", "DataTypeName": "stdType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Wed Apr 30 14:23:30 PDT 2014", "DatasetId": 102, "PendingOp": 0 }
+{ "DataverseName": "teacher", "DatasetName": "prof", "DataTypeName": "tchrType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Wed Apr 30 14:23:30 PDT 2014", "DatasetId": 103, "PendingOp": 0 }
+{ "DataverseName": "teacher", "DatasetName": "pstdoc", "DataTypeName": "tchrType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Wed Apr 30 14:23:31 PDT 2014", "DatasetId": 104, "PendingOp": 0 }
+{ "DataverseName": "student", "DatasetName": "ugdstd", "DataTypeName": "stdType", "DatasetType": "INTERNAL", "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ "id" ], "PrimaryKey": [ "id" ], "GroupName": "DEFAULT_NG_ALL_NODES", "Autogenerated": false, "CompactionPolicy": "prefix", "CompactionPolicyProperties": [ { "Name": "max-mergable-component-size", "Value": "1073741824" }, { "Name": "max-tolerance-component-count", "Value": "5" } ] }, "ExternalDetails": null, "Hints": {{ }}, "Timestamp": "Wed Apr 30 14:23:30 PDT 2014", "DatasetId": 101, "PendingOp": 0 }
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/results/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.1.adm b/asterix-app/src/test/resources/runtimets/results/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.1.adm
new file mode 100644
index 0000000..72843b2
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/index-selection/disjunctive-predicate-1/disjunctive-predicate-1.1.adm
@@ -0,0 +1,2 @@
+{ "id": "one", "idx": "one", "no-idx": "one" }
+{ "id": "two", "idx": "two", "no-idx": "two" }
diff --git a/asterix-app/src/test/resources/runtimets/testsuite.xml b/asterix-app/src/test/resources/runtimets/testsuite.xml
index 33227b3..ea122c1 100644
--- a/asterix-app/src/test/resources/runtimets/testsuite.xml
+++ b/asterix-app/src/test/resources/runtimets/testsuite.xml
@@ -2419,6 +2419,11 @@
<output-dir compare="Text">rtree-secondary-index</output-dir>
</compilation-unit>
</test-case>
+ <test-case FilePath="index-selection">
+ <compilation-unit name="disjunctive-predicate-1">
+ <output-dir compare="Text">disjunctive-predicate-1</output-dir>
+ </compilation-unit>
+ </test-case>
</test-group>
<test-group name="inverted-index-join">
<test-case FilePath="inverted-index-join">