Index: src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (revision 1002043)
+++ src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (working copy)
@@ -69,6 +69,7 @@
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.BooleanClause.Occur;
@@ -265,7 +266,28 @@
Object[] result = node.acceptOperands(this, null);
for (Object aResult : result) {
Query operand = (Query) aResult;
- orQuery.add(operand, Occur.SHOULD);
+ if (operand instanceof BooleanQuery) {
+ // check if the clauses are all optional, then
+ // we can collapse into the the enclosing orQuery
+ boolean hasNonOptional = false;
+ for (BooleanClause clause : ((BooleanQuery) operand).getClauses()) {
+ if (clause.isProhibited() || clause.isRequired()) {
+ hasNonOptional = true;
+ break;
+ }
+ }
+ if (hasNonOptional) {
+ // cannot collapse
+ orQuery.add(operand, Occur.SHOULD);
+ } else {
+ // collapse
+ for (BooleanClause clause : ((BooleanQuery) operand).getClauses()) {
+ orQuery.add(clause);
+ }
+ }
+ } else {
+ orQuery.add(operand, Occur.SHOULD);
+ }
}
return orQuery;
}
Index: src/test/java/org/apache/jackrabbit/core/query/FulltextQueryTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/core/query/FulltextQueryTest.java (revision 1002043)
+++ src/test/java/org/apache/jackrabbit/core/query/FulltextQueryTest.java (working copy)
@@ -17,6 +17,9 @@
package org.apache.jackrabbit.core.query;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -24,7 +27,10 @@
import javax.jcr.query.InvalidQueryException;
import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;
+import javax.jcr.query.Row;
+import org.apache.jackrabbit.commons.iterator.RowIterable;
+
/**
* Performs tests with the CONTAINS function.
*/
@@ -267,6 +273,46 @@
executeContainsQuery("foo:bar", "foo:bar", true);
}
+ public void testMultipleOrExpressions() throws RepositoryException {
+ Node n = testRootNode.addNode("node1");
+ n.setProperty("prop1", "foo");
+ n.setProperty("prop2", "bar");
+ n.setProperty("prop3", "baz");
+
+ n = testRootNode.addNode("node2");
+ n.setProperty("prop1", "bar");
+ n.setProperty("prop2", "foo");
+ n.setProperty("prop3", "baz");
+
+ n = testRootNode.addNode("node3");
+ n.setProperty("prop1", "bar");
+ n.setProperty("prop2", "baz");
+ n.setProperty("prop3", "foo");
+
+ superuser.save();
+
+ List r1 = new ArrayList();
+ QueryResult result = qm.createQuery(testPath + "/*[jcr:contains(@prop1, 'foo') or jcr:contains(@prop2, 'foo') or jcr:contains(@prop3, 'foo')] order by @jcr:score descending", Query.XPATH).execute();
+ for (Row r : new RowIterable(result.getRows())) {
+ r1.add(r.getPath() + ":" + (int) (r.getScore() * 1000));
+ }
+
+ List r2 = new ArrayList();
+ result = qm.createQuery(testPath + "/*[jcr:contains(@prop3, 'foo') or jcr:contains(@prop1, 'foo') or jcr:contains(@prop2, 'foo')] order by @jcr:score descending", Query.XPATH).execute();
+ for (Row r : new RowIterable(result.getRows())) {
+ r2.add(r.getPath() + ":" + (int) (r.getScore() * 1000));
+ }
+
+ List r3 = new ArrayList();
+ result = qm.createQuery(testPath + "/*[jcr:contains(@prop2, 'foo') or jcr:contains(@prop3, 'foo') or jcr:contains(@prop1, 'foo')] order by @jcr:score descending", Query.XPATH).execute();
+ for (Row r : new RowIterable(result.getRows())) {
+ r3.add(r.getPath() + ":" + (int) (r.getScore() * 1000));
+ }
+
+ assertEquals(r1, r2);
+ assertEquals(r1, r3);
+ }
+
/**
* Executes a query and checks if the query matched the test node.
*