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 ch...@apache.org on 2014/10/28 16:41:41 UTC

svn commit: r1634896 - in /jackrabbit/oak/trunk/oak-lucene/src: main/java/org/apache/jackrabbit/oak/plugins/index/lucene/ test/java/org/apache/jackrabbit/oak/plugins/index/lucene/

Author: chetanm
Date: Tue Oct 28 15:41:41 2014
New Revision: 1634896

URL: http://svn.apache.org/r1634896
Log:
OAK-2236 - Support queries with only order by specified

Added:
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java

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=1634896&r1=1634895&r2=1634896&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 Tue Oct 28 15:41:41 2014
@@ -23,7 +23,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
-import javax.annotation.CheckForNull;
 
 import com.google.common.collect.Sets;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -58,6 +57,15 @@ public class IndexPlanner {
         return builder != null ? builder.build() : null;
     }
 
+    @Override
+    public String toString() {
+        return "IndexPlanner{" +
+                "indexPath='" + indexPath + '\'' +
+                ", filter=" + filter +
+                ", sortOrder=" + sortOrder +
+                '}';
+    }
+
     private IndexPlan.Builder getPlanBuilder() {
         FullTextExpression ft = filter.getFullTextConstraint();
 
@@ -84,11 +92,13 @@ public class IndexPlanner {
             }
         }
 
-        if (!indexedProps.isEmpty()) {
+        List<OrderEntry> sortOrder = createSortOrder();
+        if (!indexedProps.isEmpty() || !sortOrder.isEmpty()) {
             //TODO Need a way to have better cost estimate to indicate that
             //this index can evaluate more propertyRestrictions natively (if more props are indexed)
             //For now we reduce cost per entry
             int costPerEntryFactor = indexedProps.size();
+            costPerEntryFactor += sortOrder.size();
             
             // Restrict matching index when declaringNodeTypes declared
             if (defn.hasDeclaredNodeTypes()) {
@@ -102,9 +112,10 @@ public class IndexPlanner {
             //this index can evaluate more propertyRestrictions natively (if more props are indexed)
             //For now we reduce cost per entry
             IndexPlan.Builder plan = defaultPlan();
-            if (plan != null) {
-                return plan.setCostPerEntry(1.0 / costPerEntryFactor);
+            if (!sortOrder.isEmpty()) {
+                plan.setSortOrder(sortOrder);
             }
+            return plan.setCostPerEntry(1.0 / costPerEntryFactor);
         }
 
         //TODO Support for property existence queries
@@ -128,7 +139,6 @@ public class IndexPlanner {
                 .setIncludesNodeData(false) // we should not include node data
                 .setFilter(filter)
                 .setPathPrefix(getPathPrefix())
-                .setSortOrder(createSortOrder())
                 .setDelayed(true) //Lucene is always async
                 .setAttribute(LuceneIndex.ATTR_INDEX_PATH, indexPath)
                 .setEstimatedEntryCount(Math.min(defn.getEntryCount(), getReader().numDocs()));
@@ -143,7 +153,6 @@ public class IndexPlanner {
         return indexNode.getSearcher().getIndexReader();
     }
 
-    @CheckForNull
     private List<OrderEntry> createSortOrder() {
         //TODO Refine later once we make mixed indexes having both
         //full text  and property index
@@ -152,7 +161,7 @@ public class IndexPlanner {
         }
 
         if (sortOrder == null) {
-            return null;
+            return Collections.emptyList();
         }
 
         List<OrderEntry> orderEntries = newArrayListWithCapacity(sortOrder.size());

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java?rev=1634896&r1=1634895&r2=1634896&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java Tue Oct 28 15:41:41 2014
@@ -535,6 +535,23 @@ public class LucenePropertyIndex impleme
             addNonFullTextConstraints(qs, filter, reader, analyzer,
                     defn);
         }
+
+        if (qs.size() == 0
+                && plan.getSortOrder() != null) {
+            //This case indicates that query just had order by and no
+            //property restriction defined. In this case property
+            //existence queries for each sort entry
+
+            for (OrderEntry oe : plan.getSortOrder()) {
+                PropertyRestriction orderRest = new PropertyRestriction();
+                orderRest.propertyName = oe.getPropertyName();
+                Query q = createQuery(orderRest, defn);
+                if (q != null) {
+                    qs.add(q);
+                }
+            }
+        }
+
         if (qs.size() == 0) {
             if (!defn.isFullTextEnabled()) {
                 throw new IllegalStateException("No query created for filter " + filter);

Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java?rev=1634896&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java Tue Oct 28 15:41:41 2014
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+package org.apache.jackrabbit.oak.plugins.index.lucene;
+
+import java.io.IOException;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.VERSION;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent.INITIAL_CONTENT;
+import static org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
+import static org.junit.Assert.assertNotNull;
+
+public class IndexPlannerTest {
+    private NodeState root = INITIAL_CONTENT;
+
+    private NodeBuilder builder = root.builder();
+
+    @Test
+    public void planForSortField() throws Exception{
+        NodeBuilder defn = LuceneIndexHelper.newLucenePropertyIndexDefinition(builder, "test", ImmutableSet.of("foo"), "async");
+        IndexNode node = createIndexNode(new IndexDefinition(defn));
+        IndexPlanner planner = new IndexPlanner(node, "/foo", createFilter("nt:base"),
+                ImmutableList.of(new OrderEntry("foo", Type.LONG, OrderEntry.Order.ASCENDING)));
+        assertNotNull(planner.getPlan());
+    }
+
+    private IndexNode createIndexNode(IndexDefinition defn) throws IOException {
+        return new IndexNode("foo", defn, createSampleDirectory());
+    }
+
+    private FilterImpl createFilter(String nodeTypeName) {
+        NodeState system = root.getChildNode(JCR_SYSTEM);
+        NodeState types = system.getChildNode(JCR_NODE_TYPES);
+        NodeState type = types.getChildNode(nodeTypeName);
+        SelectorImpl selector = new SelectorImpl(type, nodeTypeName);
+        return new FilterImpl(selector, "SELECT * FROM [" + nodeTypeName + "]", new QueryEngineSettings());
+    }
+
+    private static Directory createSampleDirectory() throws IOException {
+        Directory dir = new RAMDirectory();
+        IndexWriterConfig config = new IndexWriterConfig(VERSION, LuceneIndexConstants.ANALYZER);
+        IndexWriter writer = new  IndexWriter(dir, config);
+        Document doc = new Document();
+        doc.add(new StringField("foo", "bar", Field.Store.NO));
+        writer.addDocument(doc);
+        writer.close();
+        return dir;
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java?rev=1634896&r1=1634895&r2=1634896&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java Tue Oct 28 15:41:41 2014
@@ -412,7 +412,28 @@ public class LucenePropertyIndexTest ext
         assertSortedLong();
     }
 
+    @Test
+    public void sortQueriesWithLong_NotIndexed() throws Exception {
+        Tree idx = createIndex("test1", Collections.<String>emptySet());
+        idx.setProperty(createProperty(ORDERED_PROP_NAMES, of("foo"), STRINGS));
+        Tree propIdx = idx.addChild(PROP_NODE).addChild("foo");
+        propIdx.setProperty(LuceneIndexConstants.PROP_TYPE, PropertyType.TYPENAME_LONG);
+        root.commit();
+
+        assertThat(explain("select [jcr:path] from [nt:base] order by [foo]"), containsString("lucene:test1"));
+
+        List<Tuple> tuples = createDataForLongProp();
+        assertOrderedQuery("select [jcr:path] from [nt:base] order by [foo]", getSortedPaths(tuples, OrderDirection.ASC));
+        assertOrderedQuery("select [jcr:path] from [nt:base]  order by [foo] DESC", getSortedPaths(tuples, OrderDirection.DESC));
+    }
+
     void assertSortedLong() throws CommitFailedException {
+        List<Tuple> tuples = createDataForLongProp();
+        assertOrderedQuery("select [jcr:path] from [nt:base] where [bar] = 'baz' order by [foo]", getSortedPaths(tuples, OrderDirection.ASC));
+        assertOrderedQuery("select [jcr:path] from [nt:base] where [bar] = 'baz' order by [foo] DESC", getSortedPaths(tuples, OrderDirection.DESC));
+    }
+
+    private List<Tuple> createDataForLongProp() throws CommitFailedException {
         Tree test = root.getTree("/").addChild("test");
         List<Long> values = createLongs(NUMBER_OF_NODES);
         List<Tuple> tuples = Lists.newArrayListWithCapacity(values.size());
@@ -423,9 +444,7 @@ public class LucenePropertyIndexTest ext
             tuples.add(new Tuple(values.get(i), child.getPath()));
         }
         root.commit();
-
-        assertOrderedQuery("select [jcr:path] from [nt:base] where [bar] = 'baz' order by [foo]", getSortedPaths(tuples, OrderDirection.ASC));
-        assertOrderedQuery("select [jcr:path] from [nt:base] where [bar] = 'baz' order by [foo] DESC", getSortedPaths(tuples, OrderDirection.DESC));
+        return tuples;
     }
 
     @Test