Author: thomasm
Date: Fri Mar 28 09:57:03 2014
New Revision: 1582666

URL: http://svn.apache.org/r1582666
Log:
OAK-262 Query: support pseudo properties like jcr:score() and rep:excerpt() 
(jcr:score for Lucene so far)

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/aggregate/AggregateIndex.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
    
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
    
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryFulltextTest.java
    
jackrabbit/oak/trunk/oak-solr-core/src/test/resources/org/apache/jackrabbit/oak/query/native_solr.txt

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/aggregate/AggregateIndex.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/aggregate/AggregateIndex.java?rev=1582666&r1=1582665&r2=1582666&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/aggregate/AggregateIndex.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/aggregate/AggregateIndex.java
 Fri Mar 28 09:57:03 2014
@@ -23,6 +23,7 @@ import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.query.fulltext.FullTextAnd;
 import org.apache.jackrabbit.oak.query.fulltext.FullTextExpression;
@@ -30,7 +31,6 @@ import org.apache.jackrabbit.oak.query.f
 import org.apache.jackrabbit.oak.query.fulltext.FullTextTerm;
 import org.apache.jackrabbit.oak.query.fulltext.FullTextVisitor;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
-import org.apache.jackrabbit.oak.query.index.IndexRowImpl;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Cursors.AbstractCursor;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -165,9 +165,14 @@ public class AggregateIndex implements F
         private boolean closed;
 
         /**
-         * current item of the cursor
+         * the current row
          */
-        private String item;
+        private IndexRow currentRow;
+
+        /**
+         * the path of the current item of the cursor
+         */
+        private String currentPath;
 
         /**
          * all of the item's known aggregates
@@ -197,14 +202,14 @@ public class AggregateIndex implements F
 
         private void fetchNext() {
             if (aggregates != null && aggregates.hasNext()) {
-                item = aggregates.next();
+                currentPath = aggregates.next();
                 init = true;
                 return;
             }
             aggregates = null;
             if (cursor.hasNext()) {
-                IndexRow row = cursor.next();
-                String path = row.getPath();
+                currentRow = cursor.next();
+                String path = currentRow.getPath();
                 aggregates = Iterators.filter(Iterators.concat(
                         Iterators.singletonIterator(path),
                         aggregator.getParents(rootState, path)), Predicates
@@ -220,9 +225,27 @@ public class AggregateIndex implements F
             if (!hasNext()) {
                 throw new NoSuchElementException();
             }
-            seenPaths.add(item);
+            seenPaths.add(currentPath);
             init = false;
-            return new IndexRowImpl(item);
+            if (currentRow.getPath().equals(currentPath)) {
+                return currentRow;
+            }
+            // create a new overlayed index row,
+            // where the path is different but all other
+            // properties are kept
+            return new IndexRow() {
+
+                @Override
+                public String getPath() {
+                    return currentPath;
+                }
+
+                @Override
+                public PropertyValue getValue(String columnName) {
+                    return currentRow.getValue(columnName);
+                }
+                
+            };
         }
     }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java?rev=1582666&r1=1582665&r2=1582666&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
 Fri Mar 28 09:57:03 2014
@@ -153,7 +153,7 @@ public class Cursors {
      * <code>PathCursor</code> implements a simple {@link Cursor} that iterates
      * over a {@link String} based path {@link Iterable}.
      */
-    private static class PathCursor extends AbstractCursor {
+    public static class PathCursor extends AbstractCursor {
 
         private final Iterator<String> iterator;
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java?rev=1582666&r1=1582665&r2=1582666&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
 Fri Mar 28 09:57:03 2014
@@ -223,7 +223,11 @@ public abstract class AbstractQueryTest 
     }
 
     protected List<String> executeQuery(String query, String language) {
-        return executeQuery(query, language, false);
+        boolean pathsOnly = false;
+        if (language.equals(QueryEngineImpl.XPATH)) {
+            pathsOnly = true;
+        }
+        return executeQuery(query, language, pathsOnly);
     }
 
     protected List<String> executeQuery(String query, String language, boolean 
pathsOnly) {

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt?rev=1582666&r1=1582665&r2=1582666&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
 Fri Mar 28 09:57:03 2014
@@ -72,15 +72,15 @@ commit / - "test"
 commit / + "test": { "a": { "x": "1", "yes": { } }, "b": { "yes" : { } }, "c": 
{ "x": "1", "no" : { } }}
 
 xpath test//yes/..[@x]
-/test/a, null, null
+/test/a
 
-select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score]
+select b.[jcr:path] as [jcr:path]
   from [nt:base] as a
   inner join [nt:base] as b on ischildnode(a, b)
   where name(a) = 'yes'
   and isdescendantnode(a, '/test')
   and b.[x] is not null
-/test/a, null
+/test/a
 
 commit / - "test"
 

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java?rev=1582666&r1=1582665&r2=1582666&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
 Fri Mar 28 09:57:03 2014
@@ -51,12 +51,16 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
 import org.apache.jackrabbit.oak.plugins.index.lucene.util.MoreLikeThisHelper;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.query.QueryImpl;
 import org.apache.jackrabbit.oak.query.fulltext.FullTextAnd;
 import org.apache.jackrabbit.oak.query.fulltext.FullTextExpression;
 import org.apache.jackrabbit.oak.query.fulltext.FullTextOr;
@@ -64,7 +68,10 @@ import org.apache.jackrabbit.oak.query.f
 import org.apache.jackrabbit.oak.query.fulltext.FullTextVisitor;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Filter;
+import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.query.Cursors.PathCursor;
 import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction;
+import org.apache.jackrabbit.oak.spi.query.IndexRow;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex.FulltextQueryIndex;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
@@ -354,7 +361,7 @@ public class LuceneIndex implements Full
                 IndexReader reader = DirectoryReader.open(directory);
                 try {
                     IndexSearcher searcher = new IndexSearcher(reader);
-                    Collection<String> paths = new ArrayList<String>();
+                    List<LuceneResultRow> rows = new 
ArrayList<LuceneResultRow>();
                     Query query = getQuery(filter, reader,
                             nonFullTextConstraints, analyzer);
 
@@ -390,13 +397,16 @@ public class LuceneIndex implements Full
                                     seenPaths.add(path);
                                 }
 
-                                paths.add(path);
+                                LuceneResultRow r = new LuceneResultRow();
+                                r.path = path;
+                                r.score = doc.score;
+                                rows.add(r);
                             }
                         }
                     }
                     LOG.debug("query via {} took {} ms.", this,
                             System.currentTimeMillis() - s);
-                    return newPathCursor(paths, settings);
+                    return new LucenePathCursor(rows, settings);
                 } finally {
                     reader.close();
                 }
@@ -868,5 +878,80 @@ public class LuceneIndex implements Full
     public NodeAggregator getNodeAggregator() {
         return aggregator;
     }
+    
+    static class LuceneResultRow {
+        String path;
+        double score;
+    }
+    
+    /**
+     * A cursor over Lucene results. The result includes the path,
+     * and the jcr:score pseudo-property as returned by Lucene.
+     */
+    static class LucenePathCursor implements Cursor {
+        
+        private final Cursor pathCursor;
+        LuceneResultRow currentRow;
+        
+        LucenePathCursor(List<LuceneResultRow> list, QueryEngineSettings 
settings) {
+            
+            final Iterator<LuceneResultRow> it = list.iterator();
+            
+            Iterator<String> pathIterator = new Iterator<String>() {
+
+                @Override
+                public boolean hasNext() {
+                    return it.hasNext();
+                }
+
+                @Override
+                public String next() {
+                    currentRow = it.next(); 
+                    return currentRow.path;
+                }
+
+                @Override
+                public void remove() {
+                    it.remove();
+                }
+                
+            };
+            pathCursor = new PathCursor(pathIterator, true, settings);
+        }
+        
+
+        @Override
+        public boolean hasNext() {
+            return pathCursor.hasNext();
+        }
+
+        @Override
+        public void remove() {
+            pathCursor.remove();
+        }
+
+        @Override
+        public IndexRow next() {
+            final IndexRow pathRow = pathCursor.next();
+            return new IndexRow() {
+
+                @Override
+                public String getPath() {
+                    return pathRow.getPath();
+                }
+
+                @Override
+                public PropertyValue getValue(String columnName) {
+                    // overlay the score
+                    if (QueryImpl.JCR_SCORE.equals(columnName)) {
+                        return PropertyValues.newDouble(currentRow.score);
+                    }
+                    return pathRow.getValue(columnName);
+                }
+                
+            };
+        }
+        
+    }
 
 }

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryFulltextTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryFulltextTest.java?rev=1582666&r1=1582665&r2=1582666&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryFulltextTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryFulltextTest.java
 Fri Mar 28 09:57:03 2014
@@ -33,6 +33,23 @@ import org.apache.jackrabbit.core.query.
  */
 public class QueryFulltextTest extends AbstractQueryTest {
 
+    public void testScore() throws Exception {
+        Session session = superuser;
+        QueryManager qm = session.getWorkspace().getQueryManager();
+        Node n1 = testRootNode.addNode("node1");
+        n1.setProperty("text", "hello hello hello");
+        Node n2 = testRootNode.addNode("node2");
+        n2.setProperty("text", "hello");
+        session.save();
+
+        String xpath = "/jcr:root//*[jcr:contains(@text, 'hello')] order by 
jcr:score()";
+        Query q = qm.createQuery(xpath, "xpath");
+        String result = getResult(q.execute(), "jcr:score");
+        // expect two numbers (any value)
+        result = result.replaceAll("[0-9\\.]+", "n");
+        assertEquals("n, n", result);
+    }
+
     public void testFulltext() throws Exception {
         Session session = superuser;
         QueryManager qm = session.getWorkspace().getQueryManager();

Modified: 
jackrabbit/oak/trunk/oak-solr-core/src/test/resources/org/apache/jackrabbit/oak/query/native_solr.txt
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/test/resources/org/apache/jackrabbit/oak/query/native_solr.txt?rev=1582666&r1=1582665&r2=1582666&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-solr-core/src/test/resources/org/apache/jackrabbit/oak/query/native_solr.txt
 (original)
+++ 
jackrabbit/oak/trunk/oak-solr-core/src/test/resources/org/apache/jackrabbit/oak/query/native_solr.txt
 Fri Mar 28 09:57:03 2014
@@ -27,11 +27,11 @@
 commit / + "test": { "a": { "name": "Hello" }, "b": { "name" : "World" }}
 
 xpath /jcr:root/test/a[rep:native('solr', 'name:(Hello OR World)')]
-/test/a, null, null
+/test/a
 
 xpath //*[rep:native('solr', 'name:(Hello OR World)')]
-/test/a, null, null
-/test/b, null, null
+/test/a
+/test/b
 
 select [jcr:path] from [nt:base]
   where native('solr', 'name:(Hello OR World)')


Reply via email to