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/11/21 15:45:20 UTC
svn commit: r719592 - in
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene:
ChildAxisQuery.java DescendantSelfAxisQuery.java
Author: mreutegg
Date: Fri Nov 21 06:45:20 2008
New Revision: 719592
URL: http://svn.apache.org/viewvc?rev=719592&view=rev
Log:
JCR-1872: Improve performance of simple path queries
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
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=719592&r1=719591&r2=719592&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 Fri Nov 21 06:45:20 2008
@@ -40,6 +40,8 @@
import org.apache.lucene.search.Similarity;
import org.apache.lucene.search.Weight;
import org.apache.lucene.search.Sort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Iterator;
@@ -47,6 +49,8 @@
import java.util.Set;
import java.util.HashMap;
import java.util.Map;
+import java.util.HashSet;
+import java.util.ArrayList;
/**
* Implements a lucene <code>Query</code> which returns the child nodes of the
@@ -55,6 +59,17 @@
class ChildAxisQuery extends Query implements JackrabbitQuery {
/**
+ * The logger instance for this class.
+ */
+ private static final Logger log = LoggerFactory.getLogger(ChildAxisQuery.class);
+
+ /**
+ * Threshold when children calculation is switched to
+ * {@link HierarchyResolvingChildrenCalculator}.
+ */
+ private static int CONTEXT_SIZE_THRESHOLD = 10;
+
+ /**
* The item state manager containing persistent item states.
*/
private final ItemStateManager itemMgr;
@@ -222,13 +237,20 @@
}
/**
- * Always returns 'ChildAxisQuery'.
- *
- * @param field the name of a field.
- * @return 'ChildAxisQuery'.
+ * {@inheritDoc}
*/
public String toString(String field) {
- return "ChildAxisQuery";
+ StringBuffer sb = new StringBuffer();
+ sb.append("ChildAxisQuery(");
+ sb.append(contextQuery);
+ sb.append(", ");
+ sb.append(nameTest);
+ if (position != LocationStepQueryNode.NONE) {
+ sb.append(", ");
+ sb.append(position);
+ }
+ sb.append(")");
+ return sb.toString();
}
//-------------------< JackrabbitQuery >------------------------------------
@@ -416,57 +438,42 @@
private void calculateChildren() throws IOException {
if (hits == null) {
- // collect all context nodes
- Map uuids = new HashMap();
- final Hits contextHits = new AdaptingHits();
- contextScorer.score(new HitCollector() {
- public void collect(int doc, float score) {
- contextHits.set(doc);
- }
- });
-
- // read the uuids of the context nodes
- 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();
- 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);
+ final ChildrenCalculator[] calc = new ChildrenCalculator[1];
+ if (nameTestScorer == null) {
+ // always use simple in that case
+ calc[0] = new SimpleChildrenCalculator(reader, hResolver);
+ contextScorer.score(new HitCollector() {
+ public void collect(int doc, float score) {
+ calc[0].collectContextHit(doc);
}
- }
+ });
} else {
- // 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 = ((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());
+ // start simple but switch once threshold is reached
+ calc[0] = new SimpleChildrenCalculator(reader, hResolver);
+ contextScorer.score(new HitCollector() {
+
+ private List docIds = new ArrayList();
+
+ public void collect(int doc, float score) {
+ calc[0].collectContextHit(doc);
+ if (docIds != null) {
+ docIds.add(new Integer(doc));
+ if (docIds.size() > CONTEXT_SIZE_THRESHOLD) {
+ // switch
+ calc[0] = new HierarchyResolvingChildrenCalculator(
+ reader, hResolver);
+ for (Iterator it = docIds.iterator(); it.hasNext(); ) {
+ calc[0].collectContextHit(((Integer) it.next()).intValue());
}
- } finally {
- docs.close();
+ // indicate that we switched
+ docIds = null;
}
}
- } catch (ItemStateException e) {
- // does not exist anymore -> ignore
}
- }
+ });
}
- hits = childrenHits;
+ hits = calc[0].getHits();
}
}
@@ -537,4 +544,172 @@
return true;
}
}
+
+ /**
+ * Base class to calculate the children for a context query.
+ */
+ private abstract class ChildrenCalculator {
+
+ /**
+ * The current index reader.
+ */
+ protected final IndexReader reader;
+
+ /**
+ * The current hierarchy resolver.
+ */
+ protected final HierarchyResolver hResolver;
+
+ /**
+ * Creates a new children calculator with the given index reader and
+ * hierarchy resolver.
+ *
+ * @param reader the current index reader.
+ * @param hResolver the current hierarchy resolver.
+ */
+ public ChildrenCalculator(IndexReader reader,
+ HierarchyResolver hResolver) {
+ this.reader = reader;
+ this.hResolver = hResolver;
+ }
+
+ /**
+ * Collects a context hit.
+ *
+ * @param doc the lucene document number of the context hit.
+ */
+ protected abstract void collectContextHit(int doc);
+
+ /**
+ * @return the hits that contains the children.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public abstract Hits getHits() throws IOException;
+ }
+
+ /**
+ * An implementation of a children calculator using the item state manager.
+ */
+ private final class SimpleChildrenCalculator extends ChildrenCalculator {
+
+ /**
+ * The context hits.
+ */
+ private final Hits contextHits = new AdaptingHits();
+
+ /**
+ * Creates a new simple children calculator.
+ *
+ * @param reader the current index reader.
+ * @param hResolver the current hierarchy resolver.
+ */
+ public SimpleChildrenCalculator(IndexReader reader,
+ HierarchyResolver hResolver) {
+ super(reader, hResolver);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void collectContextHit(int doc) {
+ contextHits.set(doc);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Hits getHits() throws IOException {
+ // read the uuids of the context nodes
+ Map uuids = new HashMap();
+ 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);
+ }
+
+ // get child node entries for each hit
+ Hits childrenHits = new AdaptingHits();
+ for (Iterator it = uuids.values().iterator(); it.hasNext(); ) {
+ String uuid = (String) it.next();
+ NodeId id = new NodeId(UUID.fromString(uuid));
+ try {
+ long time = System.currentTimeMillis();
+ NodeState state = (NodeState) itemMgr.getItemState(id);
+ time = System.currentTimeMillis() - time;
+ log.debug("got NodeState with id {} in {} ms.", id, new Long(time));
+ Iterator entries;
+ if (nameTest != null) {
+ entries = state.getChildNodeEntries(nameTest).iterator();
+ } else {
+ // get all children
+ entries = state.getChildNodeEntries().iterator();
+ }
+ while (entries.hasNext()) {
+ NodeId childId = ((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
+ }
+ }
+ return childrenHits;
+ }
+ }
+
+ /**
+ * An implementation of a children calculator that uses the hierarchy
+ * resolver. This implementation requires that
+ * {@link ChildAxisQuery#nameTestScorer} is non null.
+ */
+ private final class HierarchyResolvingChildrenCalculator
+ extends ChildrenCalculator {
+
+ /**
+ * The document numbers of the context hits.
+ */
+ private final Set docIds = new HashSet();
+
+ /**
+ * Creates a new hierarchy resolving children calculator.
+ *
+ * @param reader the current index reader.
+ * @param hResolver the current hierarchy resolver.
+ */
+ public HierarchyResolvingChildrenCalculator(IndexReader reader,
+ HierarchyResolver hResolver) {
+ super(reader, hResolver);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void collectContextHit(int doc) {
+ docIds.add(new Integer(doc));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Hits getHits() throws IOException {
+ long time = System.currentTimeMillis();
+ Hits childrenHits = new AdaptingHits();
+ Hits nameHits = new ScorerHits(nameTestScorer);
+ for (int h = nameHits.next(); h > -1; h = nameHits.next()) {
+ if (docIds.contains(new Integer(hResolver.getParent(h)))) {
+ childrenHits.set(h);
+ }
+ }
+ time = System.currentTimeMillis() - time;
+
+ log.debug("Filtered hits in {} ms.", new Long(time));
+ return childrenHits;
+ }
+ }
}
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=719592&r1=719591&r2=719592&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 Fri Nov 21 06:45:20 2008
@@ -26,6 +26,8 @@
import org.apache.lucene.search.Weight;
import org.apache.lucene.search.Sort;
import org.apache.jackrabbit.core.SessionImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -44,6 +46,11 @@
class DescendantSelfAxisQuery extends Query implements JackrabbitQuery {
/**
+ * The logger instance for this class.
+ */
+ private static final Logger log = LoggerFactory.getLogger(DescendantSelfAxisQuery.class);
+
+ /**
* The context query
*/
private final Query contextQuery;
@@ -169,13 +176,18 @@
}
/**
- * Always returns 'DescendantSelfAxisQuery'.
- *
- * @param field the name of a field.
- * @return 'DescendantSelfAxisQuery'.
+ * {@inheritDoc}
*/
public String toString(String field) {
- return "DescendantSelfAxisQuery";
+ StringBuffer sb = new StringBuffer();
+ sb.append("DescendantSelfAxisQuery(");
+ sb.append(contextQuery);
+ sb.append(", ");
+ sb.append(subQuery);
+ sb.append(", ");
+ sb.append(minLevels);
+ sb.append(")");
+ return sb.toString();
}
/**
@@ -477,12 +489,22 @@
private void collectContextHits() throws IOException {
if (!contextHitsCalculated) {
+ long time = System.currentTimeMillis();
contextScorer.score(new HitCollector() {
public void collect(int doc, float score) {
contextHits.set(doc);
}
}); // find all
contextHitsCalculated = true;
+ time = System.currentTimeMillis() - time;
+ if (log.isDebugEnabled()) {
+ log.debug("Collected {} context hits in {} ms for {}",
+ new Object[]{
+ new Integer(contextHits.cardinality()),
+ new Long(time),
+ DescendantSelfAxisQuery.this
+ });
+ }
}
}