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)')