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 am...@apache.org on 2014/12/15 08:27:11 UTC

svn commit: r1645585 - 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: amitj
Date: Mon Dec 15 07:27:10 2014
New Revision: 1645585

URL: http://svn.apache.org/r1645585
Log:
OAK-2353: Support for "order by jcr:score descending" in lucene property index

Modified:
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java
    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/IndexDefinition.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java?rev=1645585&r1=1645584&r2=1645585&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java Mon Dec 15 07:27:10 2014
@@ -49,6 +49,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.plugins.tree.ImmutableTree;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -64,6 +65,7 @@ import static com.google.common.collect.
 import static com.google.common.collect.Lists.newArrayListWithCapacity;
 import static com.google.common.collect.Maps.newHashMap;
 import static com.google.common.collect.Sets.newHashSet;
+import static org.apache.jackrabbit.JcrConstants.JCR_SCORE;
 import static org.apache.jackrabbit.JcrConstants.NT_BASE;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
 import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath;
@@ -115,6 +117,12 @@ class IndexDefinition implements Aggrega
 
     static final int TYPES_ALLOW_ALL = -1;
 
+    /**
+     * native sort order
+     */
+    static final OrderEntry NATIVE_SORT_ORDER = new OrderEntry(JCR_SCORE, Type.UNDEFINED,
+        OrderEntry.Order.DESCENDING);
+
     private final boolean fullTextEnabled;
 
     private final NodeState definition;

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=1645585&r1=1645584&r2=1645585&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 Mon Dec 15 07:27:10 2014
@@ -323,8 +323,12 @@ class IndexPlanner {
                     && !o.getPropertyType().isArray()) {
                 orderEntries.add(o); //Lucene can manage any order desc/asc
                 result.sortedProperties.add(pd);
+            } else if (o.getPropertyName().equals(IndexDefinition.NATIVE_SORT_ORDER.getPropertyName())) {
+                // Supports jcr:score descending natively
+                orderEntries.add(IndexDefinition.NATIVE_SORT_ORDER);
             }
         }
+
         //TODO Should we return order entries only when all order clauses are satisfied
         return orderEntries;
     }

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=1645585&r1=1645584&r2=1645585&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 Mon Dec 15 07:27:10 2014
@@ -95,6 +95,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Lists.newArrayListWithCapacity;
 import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 import static org.apache.jackrabbit.oak.api.Type.LONG;
@@ -103,6 +104,7 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.commons.PathUtils.getName;
 import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath;
 import static org.apache.jackrabbit.oak.plugins.index.lucene.FieldNames.PATH;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.NATIVE_SORT_ORDER;
 import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.VERSION;
 import static org.apache.jackrabbit.oak.plugins.index.lucene.TermFactory.newAncestorTerm;
 import static org.apache.jackrabbit.oak.plugins.index.lucene.TermFactory.newFulltextTerm;
@@ -368,17 +370,35 @@ public class LucenePropertyIndex impleme
         if (sortOrder == null || sortOrder.isEmpty()) {
             return null;
         }
-        SortField[] fields = new SortField[sortOrder.size()];
+
+        List<SortField> fieldsList = newArrayListWithCapacity(sortOrder.size());
         PlanResult planResult = pr(plan);
         for (int i = 0; i < sortOrder.size(); i++) {
-            PropertyDefinition pd = planResult.getOrderedProperty(i);
             OrderEntry oe = sortOrder.get(i);
-            boolean reverse = oe.getOrder() != OrderEntry.Order.ASCENDING;
-            String propName = oe.getPropertyName();
-            propName = FieldNames.createDocValFieldName(propName);
-            fields[i] = new SortField(propName, toLuceneSortType(oe, pd), reverse);
+            if (!isNativeSort(oe)) {
+                PropertyDefinition pd = planResult.getOrderedProperty(i);
+                boolean reverse = oe.getOrder() != OrderEntry.Order.ASCENDING;
+                String propName = oe.getPropertyName();
+                propName = FieldNames.createDocValFieldName(propName);
+                fieldsList.add(new SortField(propName, toLuceneSortType(oe, pd), reverse));
+            }
+        }
+
+        if (fieldsList.isEmpty()) {
+            return null;
+        } else {
+            return new Sort(fieldsList.toArray(new SortField[0]));
         }
-        return new Sort(fields);
+    }
+
+    /**
+     * Identifies the default sort order used by the index (@jcr:score descending)
+     *
+     * @param oe order entry
+     * @return
+     */
+    private static boolean isNativeSort(OrderEntry oe) {
+        return oe.getPropertyName().equals(NATIVE_SORT_ORDER.getPropertyName());
     }
 
     private static SortField.Type toLuceneSortType(OrderEntry oe, PropertyDefinition defn) {
@@ -468,12 +488,14 @@ public class LucenePropertyIndex impleme
             List<OrderEntry> orders = plan.getSortOrder();
             for (int i = 0; i < orders.size(); i++) {
                 OrderEntry oe = orders.get(i);
-                PropertyDefinition pd = planResult.getOrderedProperty(i);
-                PropertyRestriction orderRest = new PropertyRestriction();
-                orderRest.propertyName = oe.getPropertyName();
-                Query q = createQuery(orderRest, pd);
-                if (q != null) {
-                    qs.add(q);
+                if (!isNativeSort(oe)) {
+                    PropertyDefinition pd = planResult.getOrderedProperty(i);
+                    PropertyRestriction orderRest = new PropertyRestriction();
+                    orderRest.propertyName = oe.getPropertyName();
+                    Query q = createQuery(orderRest, pd);
+                    if (q != null) {
+                        qs.add(q);
+                    }
                 }
             }
         }

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=1645585&r1=1645584&r2=1645585&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 Mon Dec 15 07:27:10 2014
@@ -32,10 +32,13 @@ import com.google.common.collect.Compari
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.ResultRow;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
@@ -52,6 +55,7 @@ import org.junit.Test;
 
 import static com.google.common.collect.ImmutableSet.of;
 import static java.util.Arrays.asList;
+import static org.apache.jackrabbit.oak.api.QueryEngine.NO_MAPPINGS;
 import static org.apache.jackrabbit.oak.api.Type.STRINGS;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
@@ -773,6 +777,65 @@ public class LucenePropertyIndexTest ext
     }
 
     @Test
+    public void sortQueriesWithJcrScore() throws Exception {
+        Tree idx = createIndex("test1", of("propa", "n0", "n1", "n2"));
+        root.commit();
+
+        Tree test = root.getTree("/").addChild("test");
+        for(int i = 3; i > 0; i--){
+            Tree child = test.addChild("n" + i);
+            child.setProperty("propa", "foo");
+        }
+        root.commit();
+
+        // Descending matches with lucene native sort
+        String query =
+            "measure select [jcr:path] from [nt:base] where [propa] = 'foo' order by [jcr:score] desc";
+        assertThat(measureWithLimit(query, SQL2, 1), containsString("scanCount: 1"));
+
+        // Ascending needs to be sorted by query engine
+        query =
+            "measure select [jcr:path] from [nt:base] where [propa] = 'foo' order by [jcr:score]";
+        assertThat(measureWithLimit(query, SQL2, 1), containsString("scanCount: 3"));
+    }
+
+    @Test
+    public void sortFulltextQueriesWithJcrScore() throws Exception {
+        // Index Definition
+        Tree idx = createIndex("test1", of("propa"));
+        idx.setProperty(LuceneIndexConstants.FULL_TEXT_ENABLED, true);
+        useV2(idx);
+
+        // create test data
+        Tree test = root.getTree("/").addChild("test");
+        root.commit();
+        test.addChild("a").setProperty("propa", "foo");
+        test.addChild("b").setProperty("propa", "foo");
+        test.addChild("c").setProperty("propa", "foo");
+        root.commit();
+
+        // Descending matches with lucene native sort
+        String query = "measure //*[jcr:contains(., 'foo' )] order by @jcr:score descending";
+        assertThat(measureWithLimit(query, XPATH, 1), containsString("scanCount: 1"));
+
+        // Ascending needs to be sorted by query engine
+        query = "measure //*[jcr:contains(., 'foo' )] order by @jcr:score";
+        assertThat(measureWithLimit(query, XPATH, 1), containsString("scanCount: 3"));
+    }
+
+    private String measureWithLimit(String query, String lang, int limit) throws ParseException {
+        List<? extends ResultRow> result = Lists.newArrayList(
+            qe.executeQuery(query, lang, limit, 0, Maps.<String, PropertyValue>newHashMap(),
+                NO_MAPPINGS).getRows());
+
+        String measure = "";
+        if (result.size() > 0) {
+            measure = result.get(0).toString();
+        }
+        return measure;
+    }
+
+    @Test
     public void indexTimeFieldBoostAndRelativeProperty() throws Exception {
         // Index Definition
         Tree index = root.getTree("/");