Jianfeng Jia has uploaded a new change for review.

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

Change subject: Change logical plan to apply filter from 2ndary index
......................................................................

Change logical plan to apply filter from 2ndary index

- Changes the IntroduceLSMComponentFilterRule to
replace the constant filter value from the query to the value
carried from 2ndary index search.
- Can use 2ndary index filter even the query doens't contain
any filter related condition.

Change-Id: I0e2fe0208662e5dcd49d1a22bfb58f96533e9497
---
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/IndexSearchPOperator.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/RTreeSearchPOperator.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/btree-btree-search-wo-query-filter.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/btree-btree-search.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/inverted-btree-search-wo-query-filter.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/inverted-btree-search.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/multi-index-btree-search-wo-query-filter.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/multi-index-btree-search.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/rtree-btree-search-wo-query-filter.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/rtree-btree-search.aql
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/btree-btree-search-wo-query-filter.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/btree-btree-search.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/inverted-btree-search-wo-query-filter.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/inverted-btree-search.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/multi-index-btree-search-wo-query-filter.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/multi-index-btree-search.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/rtree-btree-search-wo-query-filter.plan
A 
asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/rtree-btree-search.plan
M 
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
M 
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
M 
hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractScanOperator.java
M 
hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractUnnestMapOperator.java
M 
hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
M 
hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/am/rtree/AbstractRTreeOperatorTest.java
28 files changed, 744 insertions(+), 49 deletions(-)


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

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java
index 9dd57d5..5468856 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java
@@ -115,6 +115,7 @@
 
         int[] minFilterFieldIndexes = 
getKeyIndexes(unnestMap.getMinFilterVars(), inputSchemas);
         int[] maxFilterFieldIndexes = 
getKeyIndexes(unnestMap.getMaxFilterVars(), inputSchemas);
+        boolean propagateFilter = unnestMap.getPropagateIndexFilter();
 
         MetadataProvider metadataProvider = (MetadataProvider) 
context.getMetadataProvider();
         Dataset dataset = 
metadataProvider.findDataset(jobGenParams.getDataverseName(), 
jobGenParams.getDatasetName());
@@ -124,7 +125,7 @@
         Pair<IOperatorDescriptor, AlgebricksPartitionConstraint> btreeSearch = 
metadataProvider.buildBtreeRuntime(
                 builder.getJobSpec(), opSchema, typeEnv, context, 
jobGenParams.getRetainInput(), retainMissing,
                 dataset, jobGenParams.getIndexName(), lowKeyIndexes, 
highKeyIndexes, jobGenParams.isLowKeyInclusive(),
-                jobGenParams.isHighKeyInclusive(), minFilterFieldIndexes, 
maxFilterFieldIndexes);
+                jobGenParams.isHighKeyInclusive(), propagateFilter, 
minFilterFieldIndexes, maxFilterFieldIndexes);
 
         builder.contributeHyracksOperator(unnestMap, btreeSearch.first);
         builder.contributeAlgebricksPartitionConstraint(btreeSearch.first, 
btreeSearch.second);
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/IndexSearchPOperator.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/IndexSearchPOperator.java
index ce43480..9f46e6a 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/IndexSearchPOperator.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/IndexSearchPOperator.java
@@ -63,7 +63,7 @@
         IDataSource<?> ds = idx.getDataSource();
         IDataSourcePropertiesProvider dspp = ds.getPropertiesProvider();
         AbstractScanOperator as = (AbstractScanOperator) op;
-        deliveredProperties = dspp.computePropertiesVector(as.getVariables());
+        deliveredProperties = 
dspp.computePropertiesVector(as.getScanVariables());
     }
 
     protected int[] getKeyIndexes(List<LogicalVariable> keyVarList, 
IOperatorSchema[] inputSchemas) {
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java
index 3d7ba34..dd26865 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java
@@ -123,6 +123,7 @@
         }
         int[] keyIndexes = getKeyIndexes(jobGenParams.getKeyVarList(), 
inputSchemas);
 
+        boolean propagateIndexFilter = unnestMapOp.getPropagateIndexFilter();
         int[] minFilterFieldIndexes = 
getKeyIndexes(unnestMapOp.getMinFilterVars(), inputSchemas);
         int[] maxFilterFieldIndexes = 
getKeyIndexes(unnestMapOp.getMaxFilterVars(), inputSchemas);
         boolean retainNull = false;
@@ -136,7 +137,8 @@
                         jobGenParams.getRetainInput(), retainNull, 
jobGenParams.getDatasetName(), dataset,
                         jobGenParams.getIndexName(), 
jobGenParams.getSearchKeyType(), keyIndexes,
                         jobGenParams.getSearchModifierType(), 
jobGenParams.getSimilarityThreshold(),
-                        minFilterFieldIndexes, maxFilterFieldIndexes, 
jobGenParams.getIsFullTextSearch());
+                        propagateIndexFilter, minFilterFieldIndexes, 
maxFilterFieldIndexes,
+                        jobGenParams.getIsFullTextSearch());
 
         // Contribute operator in hyracks job.
         builder.contributeHyracksOperator(unnestMapOp, invIndexSearch.first);
@@ -150,8 +152,8 @@
             AbstractUnnestMapOperator unnestMap, IOperatorSchema opSchema, 
boolean retainInput, boolean retainMissing,
             String datasetName, Dataset dataset, String indexName, ATypeTag 
searchKeyType, int[] keyFields,
             SearchModifierType searchModifierType, IAlgebricksConstantValue 
similarityThreshold,
-            int[] minFilterFieldIndexes, int[] maxFilterFieldIndexes, boolean 
isFullTextSearchQuery)
-            throws AlgebricksException {
+            boolean propagateIndexFilter, int[] minFilterFieldIndexes, int[] 
maxFilterFieldIndexes,
+            boolean isFullTextSearchQuery) throws AlgebricksException {
         try {
             IAObject simThresh = ((AsterixConstantValue) 
similarityThreshold).getObject();
             IAType itemType = 
MetadataManager.INSTANCE.getDatatype(metadataProvider.getMetadataTxnContext(),
@@ -260,7 +262,7 @@
                     
dataset.getSearchCallbackFactory(metadataProvider.getStorageComponentProvider(),
 secondaryIndex,
                             ((JobEventListenerFactory) 
jobSpec.getJobletEventListenerFactory()).getJobId(),
                             IndexOperation.SEARCH, null),
-                    minFilterFieldIndexes, maxFilterFieldIndexes,
+                    propagateIndexFilter, minFilterFieldIndexes, 
maxFilterFieldIndexes,
                     
metadataProvider.getStorageComponentProvider().getMetadataPageManagerFactory(),
                     isFullTextSearchQuery);
             return new Pair<>(invIndexSearchOp, 
secondarySplitsAndConstraint.second);
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/RTreeSearchPOperator.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/RTreeSearchPOperator.java
index f9d4c80..ff26c9a 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/RTreeSearchPOperator.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/RTreeSearchPOperator.java
@@ -66,7 +66,7 @@
     @Override
     public void contributeRuntimeOperator(IHyracksJobBuilder builder, 
JobGenContext context, ILogicalOperator op,
             IOperatorSchema opSchema, IOperatorSchema[] inputSchemas, 
IOperatorSchema outerPlanSchema)
-                    throws AlgebricksException {
+            throws AlgebricksException {
         AbstractUnnestMapOperator unnestMap = (AbstractUnnestMapOperator) op;
         ILogicalExpression unnestExpr = 
unnestMap.getExpressionRef().getValue();
         if (unnestExpr.getExpressionTag() != 
LogicalExpressionTag.FUNCTION_CALL) {
@@ -81,6 +81,7 @@
         jobGenParams.readFromFuncArgs(unnestFuncExpr.getArguments());
         int[] keyIndexes = getKeyIndexes(jobGenParams.getKeyVarList(), 
inputSchemas);
 
+        boolean propagateIndexFilter = unnestMap.getPropagateIndexFilter();
         int[] minFilterFieldIndexes = 
getKeyIndexes(unnestMap.getMinFilterVars(), inputSchemas);
         int[] maxFilterFieldIndexes = 
getKeyIndexes(unnestMap.getMaxFilterVars(), inputSchemas);
 
@@ -97,9 +98,10 @@
             // By nature, LEFT_OUTER_UNNEST_MAP should generate null values 
for non-matching tuples.
             retainNull = true;
         }
-        Pair<IOperatorDescriptor, AlgebricksPartitionConstraint> rtreeSearch = 
mp.buildRtreeRuntime(
-                builder.getJobSpec(), outputVars, opSchema, typeEnv, context, 
jobGenParams.getRetainInput(), retainNull,
-                dataset, jobGenParams.getIndexName(), keyIndexes, 
minFilterFieldIndexes, maxFilterFieldIndexes);
+        Pair<IOperatorDescriptor, AlgebricksPartitionConstraint> rtreeSearch =
+                mp.buildRtreeRuntime(builder.getJobSpec(), outputVars, 
opSchema, typeEnv, context,
+                        jobGenParams.getRetainInput(), retainNull, dataset, 
jobGenParams.getIndexName(), keyIndexes,
+                        propagateIndexFilter, minFilterFieldIndexes, 
maxFilterFieldIndexes);
 
         builder.contributeHyracksOperator(unnestMap, rtreeSearch.first);
         builder.contributeAlgebricksPartitionConstraint(rtreeSearch.first, 
rtreeSearch.second);
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 e059574..2c5e358 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
@@ -355,6 +355,7 @@
         sourceVars = ((AbstractUnnestMapOperator) unnestMapOp).getVariables();
 
         // Assumes the primary keys are located at the end.
+        // TODO look at here about the variables
         int start = sourceVars.size() - numPrimaryKeys;
         int stop = sourceVars.size();
         for (int i = start; i < stop; i++) {
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
index 18641e5..b6d7115 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
@@ -19,9 +19,12 @@
 package org.apache.asterix.optimizer.rules.am;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Queue;
+import java.util.logging.Logger;
 
 import org.apache.asterix.common.config.DatasetConfig.DatasetType;
 import org.apache.asterix.metadata.declared.DataSource;
@@ -63,6 +66,8 @@
 
 public class IntroduceLSMComponentFilterRule implements IAlgebraicRewriteRule {
 
+    static final Logger LOGGER = 
Logger.getLogger(IntroduceLSMComponentFilterRule.class.getName());
+
     protected IVariableTypeEnvironment typeEnvironment = null;
 
     @Override
@@ -80,12 +85,6 @@
         }
 
         AbstractLogicalOperator op = (AbstractLogicalOperator) 
opRef.getValue();
-        typeEnvironment = context.getOutputTypeEnvironment(op);
-        ILogicalExpression condExpr = ((SelectOperator) 
op).getCondition().getValue();
-        AccessMethodAnalysisContext analysisCtx = analyzeCondition(condExpr, 
context, typeEnvironment);
-        if (analysisCtx.getMatchedFuncExprs().isEmpty()) {
-            return false;
-        }
 
         Dataset dataset = getDataset(op, context);
         List<String> filterFieldName = null;
@@ -101,22 +100,33 @@
         if (filterFieldName == null || recType == null) {
             return false;
         }
-        List<Index> datasetIndexes = ((MetadataProvider) 
context.getMetadataProvider())
-                .getDatasetIndexes(dataset.getDataverseName(), 
dataset.getDatasetName());
+
+        IAType filterType = recType.getSubFieldType(filterFieldName);
+
+        typeEnvironment = context.getOutputTypeEnvironment(op);
+        ILogicalExpression condExpr = ((SelectOperator) 
op).getCondition().getValue();
+        AccessMethodAnalysisContext analysisCtx = analyzeCondition(condExpr, 
context, typeEnvironment);
 
         List<IOptimizableFuncExpr> optFuncExprs = new ArrayList<>();
 
-        for (int i = 0; i < analysisCtx.getMatchedFuncExprs().size(); i++) {
-            IOptimizableFuncExpr optFuncExpr = 
analysisCtx.getMatchedFuncExpr(i);
-            boolean found = findMacthedExprFieldName(optFuncExpr, op, dataset, 
recType, datasetIndexes, context);
-            if (found && optFuncExpr.getFieldName(0).equals(filterFieldName)) {
-                optFuncExprs.add(optFuncExpr);
+        if (!analysisCtx.getMatchedFuncExprs().isEmpty()) {
+            List<Index> datasetIndexes = ((MetadataProvider) 
context.getMetadataProvider())
+                    .getDatasetIndexes(dataset.getDataverseName(), 
dataset.getDatasetName());
+
+            for (int i = 0; i < analysisCtx.getMatchedFuncExprs().size(); i++) 
{
+                IOptimizableFuncExpr optFuncExpr = 
analysisCtx.getMatchedFuncExpr(i);
+                boolean found = findMacthedExprFieldName(optFuncExpr, op, 
dataset, recType, datasetIndexes, context);
+                if (found && 
optFuncExpr.getFieldName(0).equals(filterFieldName)) {
+                    optFuncExprs.add(optFuncExpr);
+                }
             }
         }
+
         if (optFuncExprs.isEmpty()) {
-            return false;
+            assignFilterFromSecondaryUnnest(op, dataset, context, filterType);
+        } else {
+            assignFilterFromQuery(optFuncExprs, op, dataset, context, 
filterType);
         }
-        changePlan(optFuncExprs, op, dataset, context);
 
         OperatorPropertiesUtil.typeOpRec(opRef, context);
         context.addToDontApplySet(this, op);
@@ -129,8 +139,8 @@
         List<Mutable<ILogicalExpression>> assignKeyExprList = new 
ArrayList<>();
 
         for (IOptimizableFuncExpr optFuncExpr : optFuncExprs) {
-            ComparisonKind ck = AlgebricksBuiltinFunctions
-                    
.getComparisonType(optFuncExpr.getFuncExpr().getFunctionIdentifier());
+            ComparisonKind ck =
+                    
AlgebricksBuiltinFunctions.getComparisonType(optFuncExpr.getFuncExpr().getFunctionIdentifier());
             ILogicalExpression searchKeyExpr = optFuncExpr.getConstantExpr(0);
             LogicalVariable var = context.newVar();
             assignKeyExprList.add(new 
MutableObject<ILogicalExpression>(searchKeyExpr));
@@ -147,9 +157,11 @@
         return new AssignOperator(assignKeyVarList, assignKeyExprList);
     }
 
-    private void changePlan(List<IOptimizableFuncExpr> optFuncExprs, 
AbstractLogicalOperator op, Dataset dataset,
-            IOptimizationContext context) throws AlgebricksException {
+    private void assignFilterFromQuery(List<IOptimizableFuncExpr> 
optFuncExprs, AbstractLogicalOperator op,
+            Dataset dataset, IOptimizationContext context, IAType filterType) 
throws AlgebricksException {
 
+        ArrayList<UnnestMapOperator> primaryUnnestMapOps = new ArrayList<>();
+        boolean hasSecondaryIndexMap = false;
         Queue<Mutable<ILogicalOperator>> queue = new 
LinkedList<>(op.getInputs());
         while (!queue.isEmpty()) {
             AbstractLogicalOperator descendantOp = (AbstractLogicalOperator) 
queue.poll().getValue();
@@ -195,8 +207,8 @@
                         List<LogicalVariable> minFilterVars = new 
ArrayList<>();
                         List<LogicalVariable> maxFilterVars = new 
ArrayList<>();
 
-                        AssignOperator assignOp = 
createAssignOperator(optFuncExprs, minFilterVars, maxFilterVars,
-                                context);
+                        AssignOperator assignOp =
+                                createAssignOperator(optFuncExprs, 
minFilterVars, maxFilterVars, context);
 
                         unnestMapOp.setMinFilterVars(minFilterVars);
                         unnestMapOp.setMaxFilterVars(maxFilterVars);
@@ -210,10 +222,135 @@
                         assignOp.getInputs()
                                 .add(new 
MutableObject<ILogicalOperator>(unnestMapOp.getInputs().get(0).getValue()));
                         unnestMapOp.getInputs().get(0).setValue(assignOp);
+
+                        if (jobGenParams.isPrimaryIndex) {
+                            primaryUnnestMapOps.add(unnestMapOp);
+                        } else {
+                            hasSecondaryIndexMap = true;
+                        }
                     }
                 }
             }
             queue.addAll(descendantOp.getInputs());
+        }
+        if (hasSecondaryIndexMap && !primaryUnnestMapOps.isEmpty()) {
+            propagateFilterToPrimaryIndex(primaryUnnestMapOps, filterType, 
context);
+        }
+    }
+
+    private void propagateFilterToPrimaryIndex(ArrayList<UnnestMapOperator> 
primaryUnnestMapOps, IAType filterType,
+            IOptimizationContext context) throws AlgebricksException {
+        for (UnnestMapOperator primaryOp : primaryUnnestMapOps) {
+            Mutable<ILogicalOperator> assignOrOrderOrIntersect = 
primaryOp.getInputs().get(0);
+            Mutable<ILogicalOperator> intersectOrSort = null;
+            switch (assignOrOrderOrIntersect.getValue().getOperatorTag()) {
+                case ASSIGN: // already has the filter condition value from 
the query
+                    intersectOrSort = 
assignOrOrderOrIntersect.getValue().getInputs().get(0);
+                    break;
+                case INTERSECT:
+                case ORDER:
+                    intersectOrSort = assignOrOrderOrIntersect;
+                    break;
+                default:
+                    LOGGER.warning("Unexpected operator:" + 
assignOrOrderOrIntersect.getValue().getOperatorTag()
+                            + " between secondary to primary index access 
path, expected ASSIGN, ORDER, or INTERSECT");
+                    return;
+            }
+
+            boolean indeedSecondaryToPrimaryPath = false;
+
+            switch (intersectOrSort.getValue().getOperatorTag()) {
+                case INTERSECT:
+                    for (Mutable<ILogicalOperator> mutableOp : 
intersectOrSort.getValue().getInputs()) {
+                        ILogicalOperator child = mutableOp.getValue();
+                        if 
(child.getOperatorTag().equals(LogicalOperatorTag.UNNEST_MAP)) {
+                            indeedSecondaryToPrimaryPath = true;
+                            
propagateFilterInSecondaryUnnest((UnnestMapOperator) child, filterType, 
context);
+                        }
+                    }
+                    break;
+                case ORDER:
+                    ILogicalOperator child = 
intersectOrSort.getValue().getInputs().get(0).getValue();
+                    if 
(child.getOperatorTag().equals(LogicalOperatorTag.UNNEST_MAP)) {
+                        indeedSecondaryToPrimaryPath = true;
+                        propagateFilterInSecondaryUnnest((UnnestMapOperator) 
child, filterType, context);
+                    }
+                    break;
+                default:
+                    LOGGER.warning("Unexpected operator:" + 
intersectOrSort.getValue().getOperatorTag()
+                            + " between secondary to primary index access 
path, expected ORDER or INTERSECT");
+                    break;
+            }
+
+            if (indeedSecondaryToPrimaryPath) {
+                setFilterValueFromSecondaryUnnest(primaryOp, intersectOrSort, 
context);
+            }
+        }
+    }
+
+    private void propagateFilterInSecondaryUnnest(UnnestMapOperator 
secondaryUnnest, IAType filterType,
+            IOptimizationContext context) throws AlgebricksException {
+
+        LogicalVariable minIndexFilterVar = context.newVar();
+        LogicalVariable maxIndexFilterVar = context.newVar();
+        secondaryUnnest.setPropagateIndexFilter(true);
+        secondaryUnnest.getVariables().add(minIndexFilterVar);
+        secondaryUnnest.getVariableTypes().add(filterType);
+        secondaryUnnest.getVariables().add(maxIndexFilterVar);
+        secondaryUnnest.getVariableTypes().add(filterType);
+
+        context.computeAndSetTypeEnvironmentForOperator(secondaryUnnest);
+    }
+
+    private void setFilterValueFromSecondaryUnnest(UnnestMapOperator primaryOp,
+            Mutable<ILogicalOperator> intersectOrSort, IOptimizationContext 
context) throws AlgebricksException {
+        UnnestMapOperator secondaryMap = (UnnestMapOperator) 
intersectOrSort.getValue().getInputs().get(0).getValue();
+        
primaryOp.setMinFilterVars(Collections.singletonList(secondaryMap.getPropagateIndexMinFilterVar()));
+        
primaryOp.setMaxFilterVars(Collections.singletonList(secondaryMap.getPropagateIndexMaxFilterVar()));
+
+        List<Mutable<ILogicalExpression>> indexFilterExpression = 
Arrays.asList(
+                (new MutableObject<>(new 
VariableReferenceExpression(secondaryMap.getPropagateIndexMinFilterVar()))),
+                (new MutableObject<>(new 
VariableReferenceExpression(secondaryMap.getPropagateIndexMaxFilterVar()))));
+
+        primaryOp.setAdditionalFilteringExpressions(indexFilterExpression);
+        primaryOp.getInputs().set(0, intersectOrSort);
+        context.computeAndSetTypeEnvironmentForOperator(primaryOp);
+    }
+
+    private void assignFilterFromSecondaryUnnest(AbstractLogicalOperator op, 
Dataset dataset,
+            IOptimizationContext context, IAType filterType) throws 
AlgebricksException {
+        ArrayList<UnnestMapOperator> primaryUnnestMapOps = new ArrayList<>();
+        boolean hasSecondaryIndexMap = false;
+        Queue<Mutable<ILogicalOperator>> queue = new 
LinkedList<>(op.getInputs());
+        while (!queue.isEmpty()) {
+            AbstractLogicalOperator descendantOp = (AbstractLogicalOperator) 
queue.poll().getValue();
+            if (descendantOp == null) {
+                continue;
+            }
+            if (descendantOp.getOperatorTag() == 
LogicalOperatorTag.UNNEST_MAP) {
+                UnnestMapOperator unnestMapOp = (UnnestMapOperator) 
descendantOp;
+                ILogicalExpression unnestExpr = 
unnestMapOp.getExpressionRef().getValue();
+                if (unnestExpr.getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
+                    AbstractFunctionCallExpression f = 
(AbstractFunctionCallExpression) unnestExpr;
+                    FunctionIdentifier fid = f.getFunctionIdentifier();
+                    if (!fid.equals(BuiltinFunctions.INDEX_SEARCH)) {
+                        throw new IllegalStateException();
+                    }
+                    AccessMethodJobGenParams jobGenParams = new 
AccessMethodJobGenParams();
+                    jobGenParams.readFromFuncArgs(f.getArguments());
+                    if 
(dataset.getDatasetName().compareTo(jobGenParams.datasetName) == 0) {
+                        if (jobGenParams.isPrimaryIndex) {
+                            primaryUnnestMapOps.add(unnestMapOp);
+                        } else {
+                            hasSecondaryIndexMap = true;
+                        }
+                    }
+                }
+            }
+            queue.addAll(descendantOp.getInputs());
+        }
+        if (hasSecondaryIndexMap && !primaryUnnestMapOps.isEmpty()) {
+            propagateFilterToPrimaryIndex(primaryUnnestMapOps, filterType, 
context);
         }
     }
 
@@ -246,8 +383,7 @@
                     } else {
                         throw new AlgebricksException("Unexpected function for 
Unnest Map: " + fid);
                     }
-                    return ((MetadataProvider) 
context.getMetadataProvider()).findDataset(dataverseName,
-                            datasetName);
+                    return ((MetadataProvider) 
context.getMetadataProvider()).findDataset(dataverseName, datasetName);
                 }
             }
             if (descendantOp.getInputs().isEmpty()) {
@@ -318,8 +454,8 @@
                     if (funcVarIndex == -1) {
                         continue;
                     }
-                    List<String> fieldName = 
getFieldNameFromSubAssignTree(optFuncExpr, descendantOp, varIndex,
-                            recType).second;
+                    List<String> fieldName =
+                            getFieldNameFromSubAssignTree(optFuncExpr, 
descendantOp, varIndex, recType).second;
                     if (fieldName == null) {
                         return false;
                     }
@@ -411,8 +547,7 @@
         }
         AbstractFunctionCallExpression funcExpr = 
(AbstractFunctionCallExpression) expr;
         FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier();
-        if (funcIdent == BuiltinFunctions.FIELD_ACCESS_BY_NAME
-                || funcIdent == BuiltinFunctions.FIELD_ACCESS_BY_INDEX) {
+        if (funcIdent == BuiltinFunctions.FIELD_ACCESS_BY_NAME || funcIdent == 
BuiltinFunctions.FIELD_ACCESS_BY_INDEX) {
 
             //get the variable from here. Figure out which input it came from. 
Go to that input!!!
             ArrayList<LogicalVariable> usedVars = new ArrayList<>();
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/btree-btree-search-wo-query-filter.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/btree-btree-search-wo-query-filter.aql
new file mode 100644
index 0000000..f5500d9
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/btree-btree-search-wo-query-filter.aql
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type tTweet as closed {
+  id: int32,
+  location: point,
+  message: string,
+  create_at: datetime,
+  misc: string
+}
+
+create dataset dsTweet(tTweet) primary key id with filter on create_at;
+
+create index misc_index on dsTweet(misc) type btree;
+
+write output to nc1:"rttest/filter/btree-btree-search-wo-query-filter.adm";
+
+for $t in dataset dsTweet
+where $t.misc = "xyz"
+return $t
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/btree-btree-search.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/btree-btree-search.aql
new file mode 100644
index 0000000..2d8253e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/btree-btree-search.aql
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type tTweet as closed {
+  id: int32,
+  location: point,
+  message: string,
+  create_at: datetime,
+  misc: string
+}
+
+create dataset dsTweet(tTweet) primary key id with filter on create_at;
+
+create index misc_index on dsTweet(misc) type btree;
+
+write output to nc1:"rttest/filter/btree-btree-search.adm";
+
+let $ts_start := datetime("2015-11-11T00:00:00Z")
+let $ts_end := datetime("2015-12-18T23:59:59Z")
+
+for $t in dataset dsTweet
+where $t.create_at >= $ts_start and $t.create_at < $ts_end
+  and $t.misc = "xyz"
+return $t
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/inverted-btree-search-wo-query-filter.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/inverted-btree-search-wo-query-filter.aql
new file mode 100644
index 0000000..3286078
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/inverted-btree-search-wo-query-filter.aql
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type tTweet as closed {
+  id: int32,
+  location: point,
+  message: string,
+  create_at: datetime,
+  misc: string
+}
+
+create dataset dsTweet(tTweet) primary key id with filter on create_at;
+
+create index ft_index on dsTweet(message) type fulltext;
+
+write output to nc1:"rttest/filter/inverted-btree-search-wo-query-filter.adm";
+
+let $keyword := "hello"
+
+for $t in dataset dsTweet
+where ftcontains($t.message, $keyword)
+return $t
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/inverted-btree-search.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/inverted-btree-search.aql
new file mode 100644
index 0000000..c7ebfb1
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/inverted-btree-search.aql
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type tTweet as closed {
+  id: int32,
+  location: point,
+  message: string,
+  create_at: datetime,
+  misc: string
+}
+
+create dataset dsTweet(tTweet) primary key id with filter on create_at;
+
+create index ft_index on dsTweet(message) type fulltext;
+
+write output to nc1:"rttest/filter/inverted-btree-search.adm";
+
+let $ts_start := datetime("2015-11-11T00:00:00Z")
+let $ts_end := datetime("2015-12-18T23:59:59Z")
+let $keyword := "hello"
+
+for $t in dataset dsTweet
+where $t.create_at >= $ts_start and $t.create_at < $ts_end
+  and ftcontains($t.message, $keyword)
+return $t
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/multi-index-btree-search-wo-query-filter.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/multi-index-btree-search-wo-query-filter.aql
new file mode 100644
index 0000000..7864d9a
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/multi-index-btree-search-wo-query-filter.aql
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type tTweet as closed {
+  id: int32,
+  location: point,
+  message: string,
+  create_at: datetime,
+  misc: string
+}
+
+create dataset dsTweet(tTweet) primary key id with filter on create_at;
+
+create index ft_index on dsTweet(message) type fulltext;
+create index misc_index on dsTweet(misc) type btree;
+create index location_index on dsTweet(location) type rtree;
+
+write output to 
nc1:"rttest/filter/multi-index-btree-search-wo-query-filter.adm";
+
+let $region := create-rectangle(create-point(-128.43,20.29), 
create-point(-64.26,54.56))
+let $keyword := "hello"
+
+for $t in dataset dsTweet
+where  $t.misc < "xzy"
+  and spatial-intersect($t.location, $region)
+  and ftcontains($t.message, $keyword)
+return $t
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/multi-index-btree-search.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/multi-index-btree-search.aql
new file mode 100644
index 0000000..8ebb597
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/multi-index-btree-search.aql
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type tTweet as closed {
+  id: int32,
+  location: point,
+  message: string,
+  create_at: datetime,
+  misc: string
+}
+
+create dataset dsTweet(tTweet) primary key id with filter on create_at;
+
+create index ft_index on dsTweet(message) type fulltext;
+create index misc_index on dsTweet(misc) type btree;
+create index location_index on dsTweet(location) type rtree;
+
+write output to nc1:"rttest/filter/multi-index-btree-search.adm";
+
+let $region := create-rectangle(create-point(-128.43,20.29), 
create-point(-64.26,54.56))
+let $ts_start := datetime("2015-11-11T00:00:00Z")
+let $ts_end := datetime("2015-12-18T23:59:59Z")
+let $keyword := "hello"
+
+for $t in dataset dsTweet
+where $t.create_at >= $ts_start and $t.create_at < $ts_end
+  and $t.misc < "xzy"
+  and spatial-intersect($t.location, $region)
+  and ftcontains($t.message, $keyword)
+return $t
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/rtree-btree-search-wo-query-filter.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/rtree-btree-search-wo-query-filter.aql
new file mode 100644
index 0000000..e36290e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/rtree-btree-search-wo-query-filter.aql
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type tTweet as closed {
+  id: int32,
+  location: point,
+  message: string,
+  create_at: datetime,
+  misc: string
+}
+
+create dataset dsTweet(tTweet) primary key id with filter on create_at;
+
+create index location_index on dsTweet(location) type rtree;
+
+write output to nc1:"rttest/filter/rtree-btree-search-wo-query-filter.adm";
+
+let $region := create-rectangle(create-point(-128.43,20.29), 
create-point(-64.26,54.56))
+
+for $t in dataset dsTweet
+where spatial-intersect($t.location, $region)
+return $t
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/rtree-btree-search.aql
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/rtree-btree-search.aql
new file mode 100644
index 0000000..909e36e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/filter/rtree-btree-search.aql
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type tTweet as closed {
+  id: int32,
+  location: point,
+  message: string,
+  create_at: datetime,
+  misc: string
+}
+
+create dataset dsTweet(tTweet) primary key id with filter on create_at;
+
+create index location_index on dsTweet(location) type rtree;
+
+write output to nc1:"rttest/filter/rtree-btree-search.adm";
+
+let $region := create-rectangle(create-point(-128.43,20.29), 
create-point(-64.26,54.56))
+let $ts_start := datetime("2015-11-11T00:00:00Z")
+let $ts_end := datetime("2015-12-18T23:59:59Z")
+
+for $t in dataset dsTweet
+where $t.create_at >= $ts_start and $t.create_at < $ts_end
+  and spatial-intersect($t.location, $region)
+return $t
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/btree-btree-search-wo-query-filter.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/btree-btree-search-wo-query-filter.plan
new file mode 100644
index 0000000..d7667d6
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/btree-btree-search-wo-query-filter.plan
@@ -0,0 +1,15 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_SELECT  |PARTITIONED|
+      -- STREAM_PROJECT  |PARTITIONED|
+        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+          -- BTREE_SEARCH  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- STABLE_SORT [$$9(ASC)]  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- BTREE_SEARCH  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- ASSIGN  |PARTITIONED|
+                            -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/btree-btree-search.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/btree-btree-search.plan
new file mode 100644
index 0000000..0d9a257
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/btree-btree-search.plan
@@ -0,0 +1,17 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |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|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- ASSIGN  |PARTITIONED|
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/inverted-btree-search-wo-query-filter.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/inverted-btree-search-wo-query-filter.plan
new file mode 100644
index 0000000..1b99cd6
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/inverted-btree-search-wo-query-filter.plan
@@ -0,0 +1,13 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_SELECT  |PARTITIONED|
+      -- STREAM_PROJECT  |PARTITIONED|
+        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+          -- BTREE_SEARCH  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- STABLE_SORT [$$8(ASC)]  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- SINGLE_PARTITION_INVERTED_INDEX_SEARCH  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/inverted-btree-search.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/inverted-btree-search.plan
new file mode 100644
index 0000000..7b03ff5
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/inverted-btree-search.plan
@@ -0,0 +1,15 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |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 [$$18(ASC)]  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- SINGLE_PARTITION_INVERTED_INDEX_SEARCH  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- ASSIGN  |PARTITIONED|
+                            -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/multi-index-btree-search-wo-query-filter.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/multi-index-btree-search-wo-query-filter.plan
new file mode 100644
index 0000000..8c799fa
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/multi-index-btree-search-wo-query-filter.plan
@@ -0,0 +1,33 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_SELECT  |PARTITIONED|
+      -- STREAM_PROJECT  |PARTITIONED|
+        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+          -- BTREE_SEARCH  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- INTERSECT  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- STABLE_SORT [$$22(ASC)]  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- STREAM_PROJECT  |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|
+                  -- STABLE_SORT [$$24(ASC)]  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- SINGLE_PARTITION_INVERTED_INDEX_SEARCH  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- ASSIGN  |PARTITIONED|
+                            -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- STABLE_SORT [$$33(ASC)]  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- RTREE_SEARCH  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- ASSIGN  |PARTITIONED|
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/multi-index-btree-search.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/multi-index-btree-search.plan
new file mode 100644
index 0000000..b7e3da8
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/multi-index-btree-search.plan
@@ -0,0 +1,37 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |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|
+                  -- ASSIGN  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- INTERSECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- STABLE_SORT [$$31(ASC)]  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- STREAM_PROJECT  |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|
+                          -- STABLE_SORT [$$33(ASC)]  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- SINGLE_PARTITION_INVERTED_INDEX_SEARCH  
|PARTITIONED|
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  -- ASSIGN  |PARTITIONED|
+                                    -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- STABLE_SORT [$$42(ASC)]  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- STREAM_PROJECT  |PARTITIONED|
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  -- RTREE_SEARCH  |PARTITIONED|
+                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                      -- ASSIGN  |PARTITIONED|
+                                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/rtree-btree-search-wo-query-filter.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/rtree-btree-search-wo-query-filter.plan
new file mode 100644
index 0000000..59443b5
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/rtree-btree-search-wo-query-filter.plan
@@ -0,0 +1,15 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_SELECT  |PARTITIONED|
+      -- STREAM_PROJECT  |PARTITIONED|
+        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+          -- BTREE_SEARCH  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- STABLE_SORT [$$20(ASC)]  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- RTREE_SEARCH  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- ASSIGN  |PARTITIONED|
+                            -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/rtree-btree-search.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/rtree-btree-search.plan
new file mode 100644
index 0000000..8f346d3
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/filter/rtree-btree-search.plan
@@ -0,0 +1,17 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |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 [$$30(ASC)]  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- RTREE_SEARCH  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- ASSIGN  |PARTITIONED|
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
index 68c7e22..e2b1761 100644
--- 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
+++ 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
@@ -120,7 +120,7 @@
                 int[] maxFilterFieldIndexes = 
createFilterIndexes(maxFilterVars, opSchema);
                 return metadataProvider.buildBtreeRuntime(jobSpec, opSchema, 
typeEnv, context, true,
                         false, ((DatasetDataSource) dataSource).getDataset(), 
primaryIndex.getIndexName(), null, null,
-                        true, true, minFilterFieldIndexes, 
maxFilterFieldIndexes);
+                        true, true, false, minFilterFieldIndexes, 
maxFilterFieldIndexes);
             default:
                 throw new AlgebricksException("Unknown datasource type");
         }
diff --git 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
index d111eb2..498c717 100644
--- 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
+++ 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
@@ -447,8 +447,8 @@
     public Pair<IOperatorDescriptor, AlgebricksPartitionConstraint> 
buildBtreeRuntime(JobSpecification jobSpec,
             IOperatorSchema opSchema, IVariableTypeEnvironment typeEnv, 
JobGenContext context, boolean retainInput,
             boolean retainMissing, Dataset dataset, String indexName, int[] 
lowKeyFields, int[] highKeyFields,
-            boolean lowKeyInclusive, boolean highKeyInclusive, int[] 
minFilterFieldIndexes, int[] maxFilterFieldIndexes)
-            throws AlgebricksException {
+            boolean lowKeyInclusive, boolean highKeyInclusive, boolean 
propagateFilter, int[] minFilterFieldIndexes,
+            int[] maxFilterFieldIndexes) throws AlgebricksException {
         boolean isSecondary = true;
         int numSecondaryKeys = 0;
         try {
@@ -533,7 +533,7 @@
                         lowKeyInclusive, highKeyInclusive,
                         dataset.getIndexDataflowHelperFactory(this, theIndex, 
itemType, metaType, compactionInfo.first,
                                 compactionInfo.second),
-                        retainInput, retainMissing, 
context.getMissingWriterFactory(), searchCallbackFactory,
+                        retainInput, retainMissing, 
context.getMissingWriterFactory(), searchCallbackFactory, propagateFilter,
                         minFilterFieldIndexes, maxFilterFieldIndexes, 
metadataPageManagerFactory);
             } else {
                 IIndexDataflowHelperFactory indexDataflowHelperFactory = 
dataset.getIndexDataflowHelperFactory(this,
@@ -553,7 +553,8 @@
     public Pair<IOperatorDescriptor, AlgebricksPartitionConstraint> 
buildRtreeRuntime(JobSpecification jobSpec,
             List<LogicalVariable> outputVars, IOperatorSchema opSchema, 
IVariableTypeEnvironment typeEnv,
             JobGenContext context, boolean retainInput, boolean retainMissing, 
Dataset dataset, String indexName,
-            int[] keyFields, int[] minFilterFieldIndexes, int[] 
maxFilterFieldIndexes) throws AlgebricksException {
+            int[] keyFields, boolean propagateFilter, int[] 
minFilterFieldIndexes, int[] maxFilterFieldIndexes)
+            throws AlgebricksException {
         try {
             ARecordType recType = (ARecordType) 
findType(dataset.getItemTypeDataverseName(), dataset.getItemTypeName());
             int numPrimaryKeys = 
DatasetUtil.getPartitioningKeys(dataset).size();
@@ -638,7 +639,7 @@
                 rtreeSearchOp = new RTreeSearchOperatorDescriptor(jobSpec, 
outputRecDesc,
                         appContext.getStorageManager(), 
appContext.getIndexLifecycleManagerProvider(), spPc.first,
                         typeTraits, comparatorFactories, keyFields, 
indexDataflowHelperFactory, retainInput,
-                        retainMissing, context.getMissingWriterFactory(), 
searchCallbackFactory, minFilterFieldIndexes,
+                        retainMissing, context.getMissingWriterFactory(), 
searchCallbackFactory, propagateFilter, minFilterFieldIndexes,
                         maxFilterFieldIndexes, metadataPageManagerFactory);
             } else {
                 // Create the operator
diff --git 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractScanOperator.java
 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractScanOperator.java
index 9cd7138..5d6f40c 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractScanOperator.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractScanOperator.java
@@ -36,6 +36,11 @@
         return variables;
     }
 
+    public List<LogicalVariable> getScanVariables() {
+        return variables;
+    }
+
+
     public void setVariables(List<LogicalVariable> variables) {
         this.variables = variables;
     }
diff --git 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractUnnestMapOperator.java
 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractUnnestMapOperator.java
index 8a2981d..5ed7103 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractUnnestMapOperator.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/AbstractUnnestMapOperator.java
@@ -35,12 +35,24 @@
     protected List<LogicalVariable> minFilterVars;
     protected List<LogicalVariable> maxFilterVars;
 
+    protected boolean propagateIndexFilter;
+
     public AbstractUnnestMapOperator(List<LogicalVariable> variables, 
Mutable<ILogicalExpression> expression,
             List<Object> variableTypes, boolean propagateInput) {
         super(variables, expression);
         this.expression = expression;
         this.variableTypes = variableTypes;
         this.propagateInput = propagateInput;
+        this.propagateIndexFilter = false;
+    }
+
+    @Override
+    public List<LogicalVariable> getScanVariables() {
+        if (propagateIndexFilter) {
+            return variables.subList(0, variables.size() - 2);
+        } else {
+            return variables;
+        }
     }
 
     public List<Object> getVariableTypes() {
@@ -98,4 +110,27 @@
         return additionalFilteringExpressions;
     }
 
+    public void setPropagateIndexFilter(boolean propagateIndexFilter) {
+        this.propagateIndexFilter = propagateIndexFilter;
+    }
+
+    public boolean getPropagateIndexFilter() {
+        return this.propagateIndexFilter;
+    }
+
+    public LogicalVariable getPropagateIndexMinFilterVar() {
+        if (propagateIndexFilter) {
+            return variables.get(variables.size() - 2);
+        } else {
+            return null;
+        }
+    }
+
+    public LogicalVariable getPropagateIndexMaxFilterVar() {
+        if (propagateIndexFilter) {
+            return variables.get(variables.size() - 1);
+        } else {
+            return null;
+        }
+    }
 }
diff --git 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
index 89e2423..e7fb6c0 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnnestMapOperator.java
@@ -51,7 +51,7 @@
     // this operator propagates all input variables.
     @Override
     public IVariableTypeEnvironment 
computeOutputTypeEnvironment(ITypingContext ctx) throws AlgebricksException {
-        IVariableTypeEnvironment env = null;
+        IVariableTypeEnvironment env;
         if (propagateInput) {
             env = createPropagatingAllInputsTypeEnvironment(ctx);
         } else {
diff --git 
a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/am/rtree/AbstractRTreeOperatorTest.java
 
b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/am/rtree/AbstractRTreeOperatorTest.java
index 0d4bf92..03647e7 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/am/rtree/AbstractRTreeOperatorTest.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/am/rtree/AbstractRTreeOperatorTest.java
@@ -20,11 +20,7 @@
 package org.apache.hyracks.tests.am.rtree;
 
 import org.apache.hyracks.api.constraints.PartitionConstraintHelper;
-import org.apache.hyracks.api.dataflow.value.IBinaryComparatorFactory;
-import org.apache.hyracks.api.dataflow.value.ILinearizeComparatorFactory;
-import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
-import org.apache.hyracks.api.dataflow.value.ITypeTraits;
-import org.apache.hyracks.api.dataflow.value.RecordDescriptor;
+import org.apache.hyracks.api.dataflow.value.*;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.io.FileSplit;
 import org.apache.hyracks.api.io.ManagedFileSplit;

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0e2fe0208662e5dcd49d1a22bfb58f96533e9497
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Jianfeng Jia <[email protected]>

Reply via email to