Taewoo Kim has uploaded a new change for review.

  https://asterix-gerrit.ics.uci.edu/2854

Change subject: [ASTERIXDB-2437][COMP] Ensure the index-only plan on a 
composite index
......................................................................

[ASTERIXDB-2437][COMP] Ensure the index-only plan on a composite index

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
- Ensure the proper build of an index-only plan on a composite index
  where both fields are used in the SELECT condition and only one field
  is returned.

Change-Id: Idcc4cbe08323e0c6edb4a01637b2017128da1ab5
---
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-sidx-idxonly-10.sqlpp
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-sidx-idxonly-10.plan
3 files changed, 177 insertions(+), 11 deletions(-)


  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/54/2854/1

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
index c925b55..b1de3a1 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
@@ -1053,7 +1053,7 @@
                 constAssignOp.setSourceLocation(sourceLoc);
                 if (constantAssignVarUsedInTopOp) {
                     // Places this assign after the secondary index-search op.
-                    constAssignOp.getInputs().add(new 
MutableObject<ILogicalOperator>(inputOp));
+                    constAssignOp.getInputs().add(new 
MutableObject<>(inputOp));
                     constAssignOp.setExecutionMode(ExecutionMode.PARTITIONED);
                     
context.computeAndSetTypeEnvironmentForOperator(constAssignOp);
                     currentOp = constAssignOp;
@@ -1082,7 +1082,7 @@
         splitOp = new SplitOperator(2,
                 new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(condSplitVars.get(0))));
         splitOp.setSourceLocation(sourceLoc);
-        splitOp.getInputs().add(new 
MutableObject<ILogicalOperator>(currentOp));
+        splitOp.getInputs().add(new MutableObject<>(currentOp));
         splitOp.setExecutionMode(ExecutionMode.PARTITIONED);
         context.computeAndSetTypeEnvironmentForOperator(splitOp);
 
@@ -1189,11 +1189,40 @@
             LogicalVariable replacedVar = context.newVar();
             origPKRecAndSKVarToleftPathMap.put(tVar, replacedVar);
             origVarToOutputVarMap.put(skVarsFromSIdxUnnestMap.get(sIndexIdx), 
tVar);
-            unionVarMap.add(new Triple<LogicalVariable, LogicalVariable, 
LogicalVariable>(replacedVar,
+            unionVarMap.add(new Triple<>(replacedVar,
                     skVarsFromSIdxUnnestMap.get(sIndexIdx), tVar));
             // Constructs the mapping between the SK from the original 
data-scan
             // and the SK from the secondary index search since they are 
different logical variables.
             origVarToSIdxUnnestMapOpVarMap.put(tVar, 
skVarsFromSIdxUnnestMap.get(sIndexIdx));
+        }
+
+        // For B-Tree case: if the given secondary key field variable is used 
only in the select or
+        // join condition, we were not able to catch the mapping between the 
the SK from the original
+        // data-scan and the SK from the secondary index search since they are 
different logical variables.
+        // (E.g., we are sending a query on a composite index but returns only 
one field.)
+        List<LogicalVariable> varsUsedInTopOpButNotAfterwards = new 
ArrayList<>();
+        copyVarsToAnotherList(uniqueUsedVarsInTopOp, 
varsUsedInTopOpButNotAfterwards);
+        for (LogicalVariable v : usedVarsAfterTopOp) {
+            if (varsUsedInTopOpButNotAfterwards.contains(v)) {
+                varsUsedInTopOpButNotAfterwards.remove(v);
+            }
+        }
+        if (idxType == IndexType.BTREE) {
+            for (LogicalVariable v : varsUsedInTopOpButNotAfterwards) {
+                int sIndexIdx = 
chosenIndexFieldNames.indexOf(subTree.getVarsToFieldNameMap().get(v));
+                // For the join-case, the match might not exist.
+                // In this case, we just propagate the variables later.
+                if (sIndexIdx == -1) {
+                    continue;
+                }
+                // B-Tree case:
+                LogicalVariable replacedVar = context.newVar();
+                origPKRecAndSKVarToleftPathMap.put(v, replacedVar);
+                
origVarToOutputVarMap.put(skVarsFromSIdxUnnestMap.get(sIndexIdx), v);
+                // Constructs the mapping between the SK from the original 
data-scan
+                // and the SK from the secondary index search since they are 
different logical variables.
+                origVarToSIdxUnnestMapOpVarMap.put(v, 
skVarsFromSIdxUnnestMap.get(sIndexIdx));
+            }
         }
 
         // For R-Tree case: if the given secondary key field variable is used 
only in the select or join condition,
@@ -1248,7 +1277,7 @@
         ILogicalExpression conditionRefExpr = 
conditionRef.getValue().cloneExpression();
         // The retainMissing variable contains the information whether we are 
optimizing a left-outer join or not.
         LogicalVariable newMissingPlaceHolderVar = retainMissing ? 
newMissingPlaceHolderForLOJ : null;
-        newSelectOpInLeftPath = new SelectOperator(new 
MutableObject<ILogicalExpression>(conditionRefExpr),
+        newSelectOpInLeftPath = new SelectOperator(new 
MutableObject<>(conditionRefExpr),
                 retainMissing, newMissingPlaceHolderVar);
         
newSelectOpInLeftPath.setSourceLocation(conditionRefExpr.getSourceLocation());
         VariableUtilities.substituteVariables(newSelectOpInLeftPath, 
origVarToNewVarInLeftPathMap, context);
@@ -1273,7 +1302,7 @@
             }
             newSelectOpInLeftPath.getInputs().clear();
             newSelectOpInLeftPath.getInputs()
-                    .add(new 
MutableObject<ILogicalOperator>(assignsBeforeTopOpRef.get(0).getValue()));
+                    .add(new 
MutableObject<>(assignsBeforeTopOpRef.get(0).getValue()));
         } else {
             newSelectOpInLeftPath.getInputs().add(new 
MutableObject<ILogicalOperator>(primaryIndexUnnestMapOp));
         }
@@ -1308,10 +1337,10 @@
             // since we need to change the variable reference in the SELECT 
operator.
             // For the index-nested-loop join case, we copy the condition of 
the join operator.
             ILogicalExpression conditionRefExpr2 = 
conditionRef.getValue().cloneExpression();
-            newSelectOpInRightPath = new SelectOperator(new 
MutableObject<ILogicalExpression>(conditionRefExpr2),
+            newSelectOpInRightPath = new SelectOperator(new 
MutableObject<>(conditionRefExpr2),
                     retainMissing, newMissingPlaceHolderVar);
             
newSelectOpInRightPath.setSourceLocation(conditionRefExpr2.getSourceLocation());
-            newSelectOpInRightPath.getInputs().add(new 
MutableObject<ILogicalOperator>(currentTopOpInRightPath));
+            newSelectOpInRightPath.getInputs().add(new 
MutableObject<>(currentTopOpInRightPath));
             VariableUtilities.substituteVariables(newSelectOpInRightPath, 
origVarToSIdxUnnestMapOpVarMap, context);
             VariableUtilities.substituteVariables(newSelectOpInRightPath, 
origSKFieldVarToNewSKFieldVarMap, context);
             newSelectOpInRightPath.setExecutionMode(ExecutionMode.PARTITIONED);
@@ -1331,7 +1360,7 @@
         unionAllOp = new UnionAllOperator(unionVarMap);
         unionAllOp.setSourceLocation(sourceLoc);
         unionAllOp.getInputs().add(new 
MutableObject<ILogicalOperator>(newSelectOpInLeftPath));
-        unionAllOp.getInputs().add(new 
MutableObject<ILogicalOperator>(currentTopOpInRightPath));
+        unionAllOp.getInputs().add(new 
MutableObject<>(currentTopOpInRightPath));
 
         unionAllOp.setExecutionMode(ExecutionMode.PARTITIONED);
         context.computeAndSetTypeEnvironmentForOperator(unionAllOp);
@@ -1429,7 +1458,7 @@
         // Common part for the non-index-only plan and index-only plan
         // Variables and types for the primary-index search.
         List<LogicalVariable> primaryIndexUnnestVars = new ArrayList<>();
-        List<Object> primaryIndexOutputTypes = new ArrayList<Object>();
+        List<Object> primaryIndexOutputTypes = new ArrayList<>();
         // Appends output variables/types generated by the primary-index 
search (not forwarded from input).
         primaryIndexUnnestVars.addAll(dataSourceOp.getVariables());
         appendPrimaryIndexTypes(dataset, recordType, metaRecordType, 
primaryIndexOutputTypes);
@@ -2479,9 +2508,9 @@
         if (LOJVarExist && LOJVarCanBeDeleted) {
             UnionAllOperator newUnionAllOp = new UnionAllOperator(varMap);
             newUnionAllOp.getInputs()
-                    .add(new 
MutableObject<ILogicalOperator>(unionAllOp.getInputs().get(0).getValue()));
+                    .add(new 
MutableObject<>(unionAllOp.getInputs().get(0).getValue()));
             newUnionAllOp.getInputs()
-                    .add(new 
MutableObject<ILogicalOperator>(unionAllOp.getInputs().get(1).getValue()));
+                    .add(new 
MutableObject<>(unionAllOp.getInputs().get(1).getValue()));
             context.computeAndSetTypeEnvironmentForOperator(newUnionAllOp);
             return newUnionAllOp;
         } else {
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-sidx-idxonly-10.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-sidx-idxonly-10.sqlpp
new file mode 100644
index 0000000..6242a27
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index/btree-sidx-idxonly-10.sqlpp
@@ -0,0 +1,102 @@
+/*
+ * 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     : Secondary BTree Index index-only selection plan 
verification test
+ *                  : The test is intended to verify that the secondary BTree 
index is used in the optimized query plan.
+ *                  : In this plan, we fetch PK and SK based on a select 
condition that utilizes a secondary index.
+ *                  : The plan should have two paths after the secondary 
index-lookup.
+ *                  : The left path:
+ *                      ... -> unnest-map (sidx) -> split -> unnest-map (pidx) 
-> select -> union -> ...
+ *                  : The right path:
+ *                      ... -> unnest-map (sidx) -> split ->                   
          -> union -> ...
+ *  Expected Result : Success
+ *
+*/
+
+drop dataverse twitter if exists;
+create dataverse twitter if not exists;
+use twitter;
+
+create type typeUser if not exists as open {
+    id: int64,
+    name: string,
+    screen_name : string,
+    profile_image_url : string,
+    lang : string,
+    location: string,
+    create_at: date,
+    description: string,
+    followers_count: int32,
+    friends_count: int32,
+    statues_count: int64
+};
+
+create type typePlace if not exists as open{
+    country : string,
+    country_code : string,
+    full_name : string,
+    id : string,
+    name : string,
+    place_type : string,
+    bounding_box : rectangle
+};
+
+create type typeGeoTag if not exists as open {
+    stateID: int32,
+    stateName: string,
+    countyID: int32,
+    countyName: string,
+    cityID: int32?,
+    cityName: string?
+};
+
+create type typeTweet if not exists as open {
+    create_at : datetime,
+    id: int64,
+    text: string,
+    in_reply_to_status : int64,
+    in_reply_to_user : int64,
+    favorite_count : int64,
+    coordinate: point?,
+    retweet_count : int64,
+    lang : string,
+    is_retweet: boolean,
+    hashtags : {{ string }} ?,
+    user_mentions : {{ int64 }} ? ,
+    user : typeUser,
+    place : typePlace?,
+    geo_tag: typeGeoTag
+};
+
+create dataset ds_tweet(typeTweet) if not exists primary key id;
+
+create index create_at_status_count_idx on ds_tweet(user.create_at, 
user.statues_count);
+
+select value count(first.create_at) from (
+select t.user.create_at, t.user.statues_count, t.id from ds_tweet t
+where
+      t.user.create_at   >=
+      date_from_unix_time_in_days(10000) and
+      t.user.create_at   <
+      date_from_unix_time_in_days(12000) and
+          t.user.statues_count  >= 0 and
+          t.user.statues_count  <  1000000
+) first;
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-sidx-idxonly-10.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-sidx-idxonly-10.plan
new file mode 100644
index 0000000..89e06cc
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index/btree-sidx-idxonly-10.plan
@@ -0,0 +1,35 @@
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    -- AGGREGATE  |UNPARTITIONED|
+      -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+        -- AGGREGATE  |PARTITIONED|
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            -- UNION_ALL  |PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- STREAM_SELECT  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          -- ASSIGN  |PARTITIONED|
+                            -- STREAM_PROJECT  |PARTITIONED|
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                -- BTREE_SEARCH  |PARTITIONED|
+                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                    -- SPLIT  |PARTITIONED|
+                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                        -- BTREE_SEARCH  |PARTITIONED|
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                            -- ASSIGN  |PARTITIONED|
+                                              -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- STREAM_SELECT  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        -- SPLIT  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- BTREE_SEARCH  |PARTITIONED|
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                -- ASSIGN  |PARTITIONED|
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/2854
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Idcc4cbe08323e0c6edb4a01637b2017128da1ab5
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Taewoo Kim <[email protected]>

Reply via email to