[NO ISSUE][COMP] Support skip-index for IN operator
Details:
- Support skip-index hint for IN operator:
WHERE indexed_field /*+ skip-index */ IN [...]
Change-Id: Ib76f43b53c2bc1b0f5c12e03f555a8d2c1d75701
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/7603
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
index 916fd75..fe03d75 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/DisjunctivePredicateToJoinRule.java
@@ -18,9 +18,13 @@
*/
package org.apache.asterix.optimizer.rules;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import org.apache.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation;
import org.apache.asterix.metadata.declared.MetadataProvider;
import org.apache.asterix.om.base.AOrderedList;
import org.apache.asterix.om.constants.AsterixConstantValue;
@@ -39,6 +43,7 @@
import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.BroadcastExpressionAnnotation;
import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
import org.apache.hyracks.algebricks.core.algebra.expressions.IndexedNLJoinExpressionAnnotation;
import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
@@ -89,6 +94,7 @@
VariableReferenceExpression varEx = null;
IAType valType = null;
HashSet<AsterixConstantValue> values = new HashSet<AsterixConstantValue>();
+ Map<Object, IExpressionAnnotation> allAnnotations = Collections.emptyMap();
for (Mutable<ILogicalExpression> arg : args) {
AbstractFunctionCallExpression fctCall;
@@ -128,6 +134,12 @@
if (!(haveVar && haveConst)) {
return false;
}
+ if (!fctCall.getAnnotations().isEmpty()) {
+ if (allAnnotations.isEmpty()) {
+ allAnnotations = new HashMap<>();
+ }
+ allAnnotations.putAll(fctCall.getAnnotations());
+ }
}
SourceLocation sourceLoc = select.getSourceLocation();
@@ -142,8 +154,9 @@
ILogicalExpression cExp = new ConstantExpression(new AsterixConstantValue(list));
Mutable<ILogicalExpression> mutCExp = new MutableObject<>(cExp);
- IFunctionInfo scanFctInfo = BuiltinFunctions.getAsterixFunctionInfo(BuiltinFunctions.SCAN_COLLECTION);
- UnnestingFunctionCallExpression scanExp = new UnnestingFunctionCallExpression(scanFctInfo, mutCExp);
+ UnnestingFunctionCallExpression scanExp = new UnnestingFunctionCallExpression(
+ BuiltinFunctions.getAsterixFunctionInfo(BuiltinFunctions.SCAN_COLLECTION));
+ scanExp.getArguments().add(mutCExp);
scanExp.setSourceLocation(sourceLoc);
LogicalVariable scanVar = context.newVar();
UnnestOperator unn = new UnnestOperator(scanVar, new MutableObject<>(scanExp));
@@ -158,11 +171,14 @@
scanVarRef.setSourceLocation(sourceLoc);
eqExp.getArguments().add(new MutableObject<>(scanVarRef));
eqExp.getArguments().add(new MutableObject<>(varEx.cloneExpression()));
- eqExp.getAnnotations().put(IndexedNLJoinExpressionAnnotation.INSTANCE,
- IndexedNLJoinExpressionAnnotation.INSTANCE);
+ if (!allAnnotations.containsKey(SkipSecondaryIndexSearchExpressionAnnotation.INSTANCE)) {
+ eqExp.getAnnotations().put(IndexedNLJoinExpressionAnnotation.INSTANCE,
+ IndexedNLJoinExpressionAnnotation.INSTANCE);
+ }
BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation();
bcast.setObject(BroadcastExpressionAnnotation.BroadcastSide.LEFT); // Broadcast the OR predicates branch.
eqExp.getAnnotations().put(bcast, bcast);
+ eqExp.getAnnotations().putAll(allAnnotations);
InnerJoinOperator jOp = new InnerJoinOperator(new MutableObject<>(eqExp));
jOp.setSourceLocation(sourceLoc);
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
index 5363ae2..2cd402f 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
@@ -109,6 +109,7 @@
import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractLogicalExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.AggregateFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
@@ -978,7 +979,9 @@
QuantifiedPair qp = qe.getQuantifiedList().get(0);
VariableExpr varExpr = qp.getVarExpr();
- List<Expression> operandExprs = ((OperatorExpr) qe.getSatisfiesExpr()).getExprList();
+ OperatorExpr condExpr = (OperatorExpr) qe.getSatisfiesExpr();
+ List<IExpressionAnnotation> condExprHints = condExpr.getHints();
+ List<Expression> operandExprs = condExpr.getExprList();
int varIdx = operandExprs.indexOf(varExpr);
Expression operandExpr = operandExprs.get(1 - varIdx);
@@ -1011,7 +1014,7 @@
throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc,
itemExpr.getKind());
}
- ILogicalExpression eqExpr = createEqExpr(operandVar, inValue, sourceLoc);
+ ILogicalExpression eqExpr = createEqExpr(operandVar, inValue, condExprHints, sourceLoc);
disjuncts.add(new MutableObject<>(eqExpr));
}
break;
@@ -1022,7 +1025,7 @@
inVarCursor.reset();
while (inVarCursor.next()) {
IAObject inValue = inVarCursor.get();
- ILogicalExpression eqExpr = createEqExpr(operandVar, inValue, sourceLoc);
+ ILogicalExpression eqExpr = createEqExpr(operandVar, inValue, condExprHints, sourceLoc);
disjuncts.add(new MutableObject<>(eqExpr));
}
break;
@@ -1030,25 +1033,25 @@
throw new IllegalStateException(String.valueOf(inExpr.getKind()));
}
- MutableObject<ILogicalExpression> condExpr;
+ MutableObject<ILogicalExpression> disjunctiveExpr;
if (disjuncts.size() == 1) {
- condExpr = disjuncts.get(0);
+ disjunctiveExpr = disjuncts.get(0);
} else {
AbstractFunctionCallExpression orExpr =
createFunctionCallExpressionForBuiltinOperator(OperatorType.OR, sourceLoc);
orExpr.getArguments().addAll(disjuncts);
- condExpr = new MutableObject<>(orExpr);
+ disjunctiveExpr = new MutableObject<>(orExpr);
}
LogicalVariable assignVar = context.newVar();
- AssignOperator assignOp = new AssignOperator(assignVar, condExpr);
+ AssignOperator assignOp = new AssignOperator(assignVar, disjunctiveExpr);
assignOp.getInputs().add(topOp);
assignOp.setSourceLocation(sourceLoc);
return new Pair<>(assignOp, assignVar);
}
- private ILogicalExpression createEqExpr(LogicalVariable lhsVar, IAObject rhsValue, SourceLocation sourceLoc)
- throws CompilationException {
+ private ILogicalExpression createEqExpr(LogicalVariable lhsVar, IAObject rhsValue,
+ List<IExpressionAnnotation> hints, SourceLocation sourceLoc) throws CompilationException {
VariableReferenceExpression lhsExpr = new VariableReferenceExpression(lhsVar);
lhsExpr.setSourceLocation(sourceLoc);
ILogicalExpression rhsExpr = translateConstantValue(rhsValue, sourceLoc);
@@ -1056,6 +1059,11 @@
createFunctionCallExpressionForBuiltinOperator(OperatorType.EQ, sourceLoc);
opExpr.getArguments().add(new MutableObject<>(lhsExpr));
opExpr.getArguments().add(new MutableObject<>(rhsExpr));
+ if (hints != null) {
+ for (IExpressionAnnotation hint : hints) {
+ opExpr.getAnnotations().put(hint, hint);
+ }
+ }
return opExpr;
}
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/skip-index/skip-secondary-btree-index-3.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/skip-index/skip-secondary-btree-index-3.sqlpp
new file mode 100644
index 0000000..d634a26
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/skip-index/skip-secondary-btree-index-3.sqlpp
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+/*
+ * Description : Skip secondary index for IN operator
+ * Expected Res : Success
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+
+use test;
+
+create type test.TestType as
+{
+ id : integer,
+ fname : string,
+ lname : string
+};
+
+create dataset testdst(TestType) primary key id;
+
+create index sec_Idx on testdst (fname) type btree;
+
+select element emp
+from testdst as emp
+where emp.fname /*+ skip-index */ in ['Max', 'Roger']
+;
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-3.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-3.plan
new file mode 100644
index 0000000..87bb65f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-3.plan
@@ -0,0 +1,15 @@
+-- DISTRIBUTE_RESULT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- HYBRID_HASH_JOIN [$$14][$$17] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- BROADCAST_EXCHANGE |PARTITIONED|
+ -- UNNEST |UNPARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java
index 23b4d60..9c49071 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java
@@ -103,6 +103,7 @@
comparison.addOperand(itemExpr);
comparison.addOperand(bindingVar);
comparison.setCurrentop(true);
+ comparison.addHints(operatorExpr.getHints());
comparison.setSourceLocation(operatorExpr.getSourceLocation());
if (opType == OperatorType.IN) {
comparison.addOperator(OperatorType.EQ);