You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2008/02/12 17:47:27 UTC
svn commit: r620859 - in
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene:
ChildAxisQuery.java DescendantSelfAxisQuery.java LuceneQueryBuilder.java
Author: mreutegg
Date: Tue Feb 12 08:47:25 2008
New Revision: 620859
URL: http://svn.apache.org/viewvc?rev=620859&view=rev
Log:
JCR-1365: Query path constraints like foo//*/bar do not scale
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java?rev=620859&r1=620858&r2=620859&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java Tue Feb 12 08:47:25 2008
@@ -20,12 +20,12 @@
import org.apache.jackrabbit.core.query.LocationStepQueryNode;
import org.apache.jackrabbit.core.query.lucene.hits.AdaptingHits;
import org.apache.jackrabbit.core.query.lucene.hits.Hits;
-import org.apache.jackrabbit.core.query.lucene.hits.HitsIntersection;
import org.apache.jackrabbit.core.query.lucene.hits.ScorerHits;
import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.core.state.ItemStateManager;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.uuid.UUID;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
@@ -38,12 +38,14 @@
import org.apache.lucene.search.Similarity;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.Weight;
+import org.apache.lucene.search.MatchAllDocsQuery;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.util.HashMap;
+import java.util.Map;
/**
* Implements a lucene <code>Query</code> which returns the child nodes of the
@@ -116,6 +118,21 @@
}
/**
+ * @return the name test or <code>null</code> if none was specified.
+ */
+ String getNameTest() {
+ return nameTest;
+ }
+
+ /**
+ * @return the position check or {@link LocationStepQueryNode#NONE} is none
+ * was specified.
+ */
+ int getPosition() {
+ return position;
+ }
+
+ /**
* Creates a <code>Weight</code> instance for this query.
*
* @param searcher the <code>Searcher</code> instance to use.
@@ -137,6 +154,24 @@
*/
public Query rewrite(IndexReader reader) throws IOException {
Query cQuery = contextQuery.rewrite(reader);
+ // only try to compact if no position is specified
+ if (position == LocationStepQueryNode.NONE) {
+ if (cQuery instanceof DescendantSelfAxisQuery) {
+ DescendantSelfAxisQuery dsaq = (DescendantSelfAxisQuery) cQuery;
+ if (dsaq.subQueryMatchesAll()) {
+ Query sub;
+ if (nameTest == null) {
+ sub = new MatchAllDocsQuery();
+ } else {
+ sub = new TermQuery(new Term(FieldNames.LABEL, nameTest));
+ }
+ return new DescendantSelfAxisQuery(dsaq.getContextQuery(),
+ sub, dsaq.getMinLevels() + 1).rewrite(reader);
+ }
+ }
+ }
+
+ // if we get here we could not compact the query
if (cQuery == contextQuery) {
return this;
} else {
@@ -217,7 +252,8 @@
if (nameTest != null) {
nameTestScorer = new TermQuery(new Term(FieldNames.LABEL, nameTest)).weight(searcher).scorer(reader);
}
- return new ChildAxisScorer(searcher.getSimilarity(), reader);
+ return new ChildAxisScorer(searcher.getSimilarity(),
+ reader, (HierarchyResolver) reader);
}
/**
@@ -241,6 +277,11 @@
private final IndexReader reader;
/**
+ * The <code>HierarchyResolver</code> of the index.
+ */
+ private final HierarchyResolver hResolver;
+
+ /**
* The next document id to return
*/
private int nextDoc = -1;
@@ -255,10 +296,14 @@
*
* @param similarity the <code>Similarity</code> instance to use.
* @param reader for index access.
+ * @param hResolver the hierarchy resolver of <code>reader</code>.
*/
- protected ChildAxisScorer(Similarity similarity, IndexReader reader) {
+ protected ChildAxisScorer(Similarity similarity,
+ IndexReader reader,
+ HierarchyResolver hResolver) {
super(similarity);
this.reader = reader;
+ this.hResolver = hResolver;
}
/**
@@ -313,7 +358,7 @@
if (hits == null) {
// collect all context nodes
- List uuids = new ArrayList();
+ Map uuids = new HashMap();
final Hits contextHits = new AdaptingHits();
contextScorer.score(new HitCollector() {
public void collect(int doc, float score) {
@@ -322,39 +367,53 @@
});
// read the uuids of the context nodes
- int i = contextHits.next();
- while (i > -1) {
- String uuid = reader.document(i).get(FieldNames.UUID);
- uuids.add(uuid);
- i = contextHits.next();
+ for (int i = contextHits.next(); i > -1; i = contextHits.next()) {
+ String uuid = reader.document(i, FieldSelectors.UUID).get(FieldNames.UUID);
+ uuids.put(new Integer(i), uuid);
}
// collect all children of the context nodes
Hits childrenHits = new AdaptingHits();
-
- TermDocs docs = reader.termDocs();
- try {
- for (Iterator it = uuids.iterator(); it.hasNext();) {
- docs.seek(new Term(FieldNames.PARENT, (String) it.next()));
- while (docs.next()) {
- childrenHits.set(docs.doc());
+ if (nameTestScorer != null) {
+ Hits nameHits = new ScorerHits(nameTestScorer);
+ for (int h = nameHits.next(); h > -1; h = nameHits.next()) {
+ if (uuids.containsKey(new Integer(hResolver.getParent(h)))) {
+ childrenHits.set(h);
}
}
- } finally {
- docs.close();
- }
-
- if (nameTestScorer != null) {
- hits = new HitsIntersection(childrenHits, new ScorerHits(nameTestScorer));
} else {
- hits = childrenHits;
+ // get child node entries for each hit
+ for (Iterator it = uuids.values().iterator(); it.hasNext(); ) {
+ String uuid = (String) it.next();
+ NodeId id = new NodeId(UUID.fromString(uuid));
+ try {
+ NodeState state = (NodeState) itemMgr.getItemState(id);
+ Iterator entries = state.getChildNodeEntries().iterator();
+ while (entries.hasNext()) {
+ NodeId childId = ((NodeState.ChildNodeEntry) entries.next()).getId();
+ Term uuidTerm = new Term(FieldNames.UUID, childId.getUUID().toString());
+ TermDocs docs = reader.termDocs(uuidTerm);
+ try {
+ if (docs.next()) {
+ childrenHits.set(docs.doc());
+ }
+ } finally {
+ docs.close();
+ }
+ }
+ } catch (ItemStateException e) {
+ // does not exist anymore -> ignore
+ }
+ }
}
+
+ hits = childrenHits;
}
}
private boolean indexIsValid(int i) throws IOException {
if (position != LocationStepQueryNode.NONE) {
- Document node = reader.document(i);
+ Document node = reader.document(i, FieldSelectors.UUID_AND_PARENT);
NodeId parentId = NodeId.valueOf(node.get(FieldNames.PARENT));
NodeId id = NodeId.valueOf(node.get(FieldNames.UUID));
try {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java?rev=620859&r1=620858&r2=620859&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java Tue Feb 12 08:47:25 2008
@@ -24,6 +24,7 @@
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.Similarity;
import org.apache.lucene.search.Weight;
+import org.apache.lucene.search.MatchAllDocsQuery;
import java.io.IOException;
import java.util.BitSet;
@@ -52,10 +53,10 @@
private final Query subQuery;
/**
- * If <code>true</code> this query acts on the descendant-or-self axis.
- * If <code>false</code> this query acts on the descendant axis.
+ * The minimal levels required between context and sub nodes for a sub node
+ * to match.
*/
- private final boolean includeSelf;
+ private final int minLevels;
/**
* The scorer of the sub query to filter
@@ -64,6 +65,21 @@
/**
* Creates a new <code>DescendantSelfAxisQuery</code> based on a
+ * <code>context</code> and matches all descendants of the context nodes.
+ * Whether the context nodes match as well is controlled by
+ * <code>includeSelf</code>.
+ *
+ * @param context the context for this query.
+ * @param includeSelf if <code>true</code> this query acts like a
+ * descendant-or-self axis. If <code>false</code> this
+ * query acts like a descendant axis.
+ */
+ public DescendantSelfAxisQuery(Query context, boolean includeSelf) {
+ this(context, new MatchAllDocsQuery(), includeSelf);
+ }
+
+ /**
+ * Creates a new <code>DescendantSelfAxisQuery</code> based on a
* <code>context</code> query and filtering the <code>sub</code> query.
*
* @param context the context for this query.
@@ -84,9 +100,45 @@
* a descendant axis.
*/
public DescendantSelfAxisQuery(Query context, Query sub, boolean includeSelf) {
+ this(context, sub, includeSelf ? 0 : 1);
+ }
+
+ /**
+ * Creates a new <code>DescendantSelfAxisQuery</code> based on a
+ * <code>context</code> query and filtering the <code>sub</code> query.
+ *
+ * @param context the context for this query.
+ * @param sub the sub query.
+ * @param minLevels the minimal levels required between context and sub
+ * nodes for a sub node to match.
+ */
+ public DescendantSelfAxisQuery(Query context, Query sub, int minLevels) {
this.contextQuery = context;
this.subQuery = sub;
- this.includeSelf = includeSelf;
+ this.minLevels = minLevels;
+ }
+
+ /**
+ * @return the context query of this <code>DescendantSelfAxisQuery</code>.
+ */
+ Query getContextQuery() {
+ return contextQuery;
+ }
+
+ /**
+ * @return <code>true</code> if the sub query of this <code>DescendantSelfAxisQuery</code>
+ * matches all nodes.
+ */
+ boolean subQueryMatchesAll() {
+ return subQuery instanceof MatchAllDocsQuery;
+ }
+
+ /**
+ * @return the minimal levels required between context and sub nodes for a
+ * sub node to match.
+ */
+ int getMinLevels() {
+ return minLevels;
}
/**
@@ -123,10 +175,17 @@
public Query rewrite(IndexReader reader) throws IOException {
Query cQuery = contextQuery.rewrite(reader);
Query sQuery = subQuery.rewrite(reader);
+ if (contextQuery instanceof DescendantSelfAxisQuery) {
+ DescendantSelfAxisQuery dsaq = (DescendantSelfAxisQuery) contextQuery;
+ if (dsaq.subQueryMatchesAll()) {
+ return new DescendantSelfAxisQuery(dsaq.getContextQuery(),
+ sQuery, dsaq.getMinLevels() + getMinLevels()).rewrite(reader);
+ }
+ }
if (cQuery == contextQuery && sQuery == subQuery) {
return this;
} else {
- return new DescendantSelfAxisQuery(cQuery, sQuery, includeSelf);
+ return new DescendantSelfAxisQuery(cQuery, sQuery, minLevels);
}
}
@@ -153,6 +212,8 @@
this.searcher = searcher;
}
+ //-----------------------------< Weight >-------------------------------
+
/**
* Returns this <code>DescendantSelfAxisQuery</code>.
*
@@ -330,10 +391,8 @@
*/
private boolean isValid(int doc) throws IOException {
// check self if necessary
- if (includeSelf) {
- if (contextHits.get(doc)) {
- return true;
- }
+ if (minLevels == 0 && contextHits.get(doc)) {
+ return true;
}
// check if doc is a descendant of one of the context nodes
@@ -343,7 +402,7 @@
ancestorDocs[ancestorCount++] = parentDoc;
// traverse
- while (parentDoc != -1 && !contextHits.get(parentDoc)) {
+ while (parentDoc != -1 && (!contextHits.get(parentDoc) || ancestorCount < minLevels)) {
parentDoc = hResolver.getParent(parentDoc);
// resize array if needed
if (ancestorCount == ancestorDocs.length) {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java?rev=620859&r1=620858&r2=620859&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java Tue Feb 12 08:47:25 2008
@@ -59,6 +59,7 @@
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.MatchAllDocsQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -556,19 +557,18 @@
}
} else {
// todo this will traverse the whole index, optimize!
- Query subQuery = null;
- try {
- subQuery = createMatchAllQuery(resolver.getJCRName(NameConstants.JCR_PRIMARYTYPE));
- } catch (NamespaceException e) {
- // will never happen, prefixes are created when unknown
- }
// only use descendant axis if path is not //*
PathQueryNode pathNode = (PathQueryNode) node.getParent();
if (pathNode.getPathSteps()[0] != node) {
- context = new DescendantSelfAxisQuery(context, subQuery);
- andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex()), Occur.MUST);
+ if (node.getIndex() == LocationStepQueryNode.NONE) {
+ context = new DescendantSelfAxisQuery(context, false);
+ andQuery.add(context, Occur.MUST);
+ } else {
+ context = new DescendantSelfAxisQuery(context, true);
+ andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex()), Occur.MUST);
+ }
} else {
- andQuery.add(subQuery, Occur.MUST);
+ andQuery.add(new MatchAllDocsQuery(), Occur.MUST);
}
}
}