You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2017/07/28 13:15:43 UTC

svn commit: r1803272 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/pro...

Author: thomasm
Date: Fri Jul 28 13:15:43 2017
New Revision: 1803272

URL: http://svn.apache.org/viewvc?rev=1803272&view=rev
Log:
OAK-937 Query engine index selection tweaks: shortcut and hint

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java Fri Jul 28 13:15:43 2017
@@ -103,4 +103,10 @@ public interface IndexConstants {
      * The time is in string for as per Type.DATE
      */
     String CHECKPOINT_CREATION_TIME = "indexingCheckpointTime";
+    
+    /**
+     * The index name hint (when using "option(index abc)", this is "abc")
+     */
+    String INDEX_NAME_OPTION = ":indexName";
+    
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java Fri Jul 28 13:15:43 2017
@@ -18,12 +18,16 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.nodetype;
 
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_NAME_OPTION;
+
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.Cursors;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
+import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
@@ -63,6 +67,11 @@ class NodeTypeIndex implements QueryInde
             // doesn't have a node type restriction
             return Double.POSITIVE_INFINITY;
         }
+        PropertyRestriction indexName = filter.getPropertyRestriction(INDEX_NAME_OPTION);
+        if (wrongIndexName(indexName)) {
+            return Double.POSITIVE_INFINITY;
+        }
+        
         NodeTypeIndexLookup lookup = new NodeTypeIndexLookup(root, mountInfoProvider);
         if (lookup.isIndexed(filter.getPath(), filter)) {
             return lookup.getCost(filter);
@@ -70,6 +79,13 @@ class NodeTypeIndex implements QueryInde
             return Double.POSITIVE_INFINITY;
         }
     }
+    
+    private static boolean wrongIndexName(PropertyRestriction indexName) {
+        if (indexName == null || indexName.first == null) {
+            return false;
+        }
+        return !"nodetype".equals(indexName.first.getValue(Type.STRING));
+    }
 
     @Override
     public Cursor query(Filter filter, NodeState root) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndex.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndex.java Fri Jul 28 13:15:43 2017
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.plugin
 import static com.google.common.base.Preconditions.checkState;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_NAME_OPTION;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
 
 import java.io.UnsupportedEncodingException;
@@ -31,6 +32,7 @@ import org.apache.jackrabbit.oak.api.Typ
 import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Filter;
+import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -173,7 +175,11 @@ class PropertyIndex implements QueryInde
         // TODO support indexes on a path
         // currently, only indexes on the root node are supported
         NodeState state = root.getChildNode(INDEX_DEFINITIONS_NAME);
+        PropertyRestriction indexName = filter.getPropertyRestriction(INDEX_NAME_OPTION);
         for (ChildNodeEntry entry : state.getChildNodeEntries()) {
+            if (wrongIndexName(entry, indexName)) {
+                continue;
+            }
             NodeState definition = entry.getNodeState();
             if (PROPERTY.equals(definition.getString(TYPE_PROPERTY_NAME))
                     && definition.hasChildNode(INDEX_CONTENT_NODE_NAME)) {
@@ -195,6 +201,13 @@ class PropertyIndex implements QueryInde
 
         return bestPlan;
     }
+    
+    private static boolean wrongIndexName(ChildNodeEntry entry, PropertyRestriction indexName) {
+        if (indexName == null || indexName.first == null) {
+            return false;
+        }
+        return !entry.getName().equals(indexName.first.getValue(Type.STRING));
+    }
 
     //--------------------------------------------------------< QueryIndex >--
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java Fri Jul 28 13:15:43 2017
@@ -1360,4 +1360,8 @@ public class QueryImpl implements Query
         return constraint.containsUnfilteredFullTextCondition();
     }
 
+    public QueryOptions getQueryOptions() {
+        return queryOptions;
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java Fri Jul 28 13:15:43 2017
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.query;
 public class QueryOptions {
     
     public Traversal traversal = Traversal.DEFAULT;
+    public String indexName;
     
     public enum Traversal {
         // traversing without index is OK for this query, and does not fail or log a warning

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java Fri Jul 28 13:15:43 2017
@@ -168,9 +168,17 @@ public class SQL2Parser {
         QueryOptions options = new QueryOptions();
         if (readIf("OPTION")) {
             read("(");
-            if (readIf("TRAVERSAL")) {
-                String n = readName().toUpperCase(Locale.ENGLISH);
-                options.traversal = Traversal.valueOf(n);
+            while (true) {
+                if (readIf("TRAVERSAL")) {
+                    String n = readName().toUpperCase(Locale.ENGLISH);
+                    options.traversal = Traversal.valueOf(n);
+                } else if (readIf("INDEX")) {
+                    String n = readName();
+                    options.indexName = n;
+                } else {
+                    break;
+                }
+                readIf(",");
             }
             read(")");
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Fri Jul 28 13:15:43 2017
@@ -40,12 +40,14 @@ import org.apache.jackrabbit.oak.api.Typ
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
 import org.apache.jackrabbit.oak.query.QueryImpl;
+import org.apache.jackrabbit.oak.query.QueryOptions;
 import org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.query.plan.ExecutionPlan;
 import org.apache.jackrabbit.oak.query.plan.SelectorExecutionPlan;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.plugins.index.Cursors;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
 import org.apache.jackrabbit.oak.spi.query.IndexRow;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyValues;
 import org.apache.jackrabbit.oak.spi.query.QueryConstants;
@@ -412,7 +414,11 @@ public class SelectorImpl extends Source
         for (ConstraintImpl constraint : selectorConstraints) {
             constraint.restrict(f);
         }
-
+        QueryOptions options = query.getQueryOptions();
+        if (options != null && options.indexName != null) {
+            f.restrictProperty(IndexConstants.INDEX_NAME_OPTION, 
+                    Operator.EQUAL, PropertyValues.newString(options.indexName));
+        }
         return f;
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java Fri Jul 28 13:15:43 2017
@@ -56,7 +56,7 @@ public class Statement {
     
     String xpathQuery;
     
-    QueryOptions queryOptions = new QueryOptions();
+    QueryOptions queryOptions;
     
     public Statement optimize() {
         ignoreOrderByScoreDesc();
@@ -226,9 +226,7 @@ public class Statement {
                 buff.append(orderList.get(i));
             }
         }
-        if (queryOptions.traversal != Traversal.DEFAULT) {
-            buff.append(" option(traversal " + queryOptions.traversal +")");
-        }
+        appendQueryOptions(buff, queryOptions);
         // leave original xpath string as a comment
         appendXPathAsComment(buff, xpathQuery);
         return buff.toString();        
@@ -327,9 +325,7 @@ public class Statement {
                     buff.append(orderList.get(i));
                 }
             }
-            if (queryOptions.traversal != Traversal.DEFAULT) {
-                buff.append(" option(traversal " + queryOptions.traversal +")");
-            }
+            appendQueryOptions(buff, queryOptions);
             // leave original xpath string as a comment
             appendXPathAsComment(buff, xpathQuery);
             return buff.toString();
@@ -337,6 +333,27 @@ public class Statement {
         
     }
     
+    private static void appendQueryOptions(StringBuilder buff, QueryOptions queryOptions) {
+        if (queryOptions == null) {
+            return;
+        }
+        buff.append(" option(");
+        int optionCount = 0;
+        if (queryOptions.traversal != Traversal.DEFAULT) {
+            buff.append("traversal " + queryOptions.traversal);
+            optionCount++;
+        }
+        if (queryOptions.indexName != null) {
+            if (optionCount > 0) {
+                buff.append(", ");
+            }
+            buff.append("index [");
+            buff.append(queryOptions.indexName);
+            buff.append("]");
+        }
+        buff.append(")");
+    }
+    
     private static void appendXPathAsComment(StringBuilder buff, String xpath) {
         if (xpath == null) {
             return;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java Fri Jul 28 13:15:43 2017
@@ -329,12 +329,21 @@ public class XPathToSQL2Converter {
                 statement.addOrderBy(order);
             } while (readIf(","));
         }
-        QueryOptions options = new QueryOptions();
+        QueryOptions options = null;
         if (readIf("option")) {
             read("(");
-            if (readIf("traversal")) {
-                String type = readIdentifier().toUpperCase(Locale.ENGLISH);
-                options.traversal = Traversal.valueOf(type);
+            options = new QueryOptions();
+            while (true) {
+                if (readIf("traversal")) {
+                    String type = readIdentifier().toUpperCase(Locale.ENGLISH);
+                    options.traversal = Traversal.valueOf(type);
+                } else if (readIf("index")) {
+                    String n = readIdentifier();
+                    options.indexName = n;
+                } else {
+                    break;
+                }
+                readIf(",");
             }
             read(")");
         }
@@ -1126,7 +1135,7 @@ public class XPathToSQL2Converter {
             // but no longer in the individual statements
             // (can not use clear, because it is shared)
             stat.orderList = new ArrayList<Order>();
-            stat.queryOptions = new QueryOptions();
+            stat.queryOptions = null;
             if (result == null) {
                 result = stat;
             } else {

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java?rev=1803272&r1=1803271&r2=1803272&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java Fri Jul 28 13:15:43 2017
@@ -33,6 +33,7 @@ import org.apache.jackrabbit.JcrConstant
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
 import org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.IndexingRule;
 import org.apache.jackrabbit.oak.plugins.index.lucene.util.FacetHelper;
 import org.apache.jackrabbit.oak.spi.query.fulltext.FullTextContains;
@@ -123,6 +124,20 @@ class IndexPlanner {
 
     private IndexPlan.Builder getPlanBuilder() {
         log.trace("Evaluating plan with index definition {}", definition);
+
+        // skip index if "option(index <name>)" doesn't match
+        PropertyRestriction indexName = filter.getPropertyRestriction(IndexConstants.INDEX_NAME_OPTION);
+        if (indexName != null && indexName.first != null) {
+            String name = indexName.first.getValue(Type.STRING);
+            String thisName = definition.getIndexName();
+            if (thisName != null) {
+                thisName = PathUtils.getName(thisName);
+                if (!thisName.equals(name)) {
+                    return null;
+                }
+            }
+        }
+
         FullTextExpression ft = filter.getFullTextConstraint();
 
         if (!definition.getVersion().isAtLeast(IndexFormatVersion.V2)){
@@ -358,7 +373,7 @@ class IndexPlanner {
                 visitTerm(term.getPropertyName());
                 return true;
             }
-                
+
             private void visitTerm(String propertyName) {
                 String p = propertyName;
                 String propertyPath = null;
@@ -603,7 +618,7 @@ class IndexPlanner {
     private boolean notSupportedFeature() {
         if(filter.getPathRestriction() == Filter.PathRestriction.NO_RESTRICTION
                 && filter.matchesAllTypes()
-                && filter.getPropertyRestrictions().isEmpty()) { 
+                && filter.getPropertyRestrictions().isEmpty()) {
             //This mode includes name(), localname() queries
             //OrImpl [a/name] = 'Hello' or [b/name] = 'World'
             //Relative parent properties where [../foo1] is not null
@@ -612,7 +627,7 @@ class IndexPlanner {
         boolean failTestOnMissingFunctionIndex = true;
         if (failTestOnMissingFunctionIndex) {
             // this means even just function restrictions fail the test
-            // (for example "where upper(name) = 'X'", 
+            // (for example "where upper(name) = 'X'",
             // if a matching function-based index is missing
             return false;
         }