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 2009/02/26 14:24:08 UTC

svn commit: r748139 - in /jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene: ChildAxisQuery.java DescendantSelfAxisQuery.java LuceneQueryBuilder.java NameQuery.java

Author: mreutegg
Date: Thu Feb 26 13:24:08 2009
New Revision: 748139

URL: http://svn.apache.org/viewvc?rev=748139&view=rev
Log:
JCR-1872: Improve performance of simple path queries

Added:
    jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java   (with props)
Modified:
    jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java
    jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java
    jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java

Modified: jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java?rev=748139&r1=748138&r2=748139&view=diff
==============================================================================
--- jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java (original)
+++ jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ChildAxisQuery.java Thu Feb 26 13:24:08 2009
@@ -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;
@@ -36,14 +36,18 @@
 import org.apache.lucene.search.Scorer;
 import org.apache.lucene.search.Searcher;
 import org.apache.lucene.search.Similarity;
-import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.search.Weight;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.HashSet;
 
 /**
  * Implements a lucene <code>Query</code> which returns the child nodes of the
@@ -52,6 +56,17 @@
 class ChildAxisQuery extends Query {
 
     /**
+     * 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;
@@ -65,7 +80,7 @@
      * The nameTest to apply on the child axis, or <code>null</code> if all
      * child nodes should be selected.
      */
-    private final String nameTest;
+    private final Name nameTest;
 
     /**
      * The context position for the selected child node, or
@@ -74,6 +89,11 @@
     private final int position;
 
     /**
+     * The internal namespace mappings.
+     */
+    private final NamespaceMappings nsMappings;
+
+    /**
      * The scorer of the context query
      */
     private Scorer contextScorer;
@@ -91,9 +111,13 @@
      * @param context the context for this query.
      * @param nameTest a name test or <code>null</code> if any child node is
      * selected.
+     * @param nsMappings the internal namespace mappings.
      */
-    ChildAxisQuery(ItemStateManager itemMgr, Query context, String nameTest) {
-        this(itemMgr, context, nameTest, LocationStepQueryNode.NONE);
+    ChildAxisQuery(ItemStateManager itemMgr,
+                   Query context,
+                   Name nameTest,
+                   NamespaceMappings nsMappings) {
+        this(itemMgr, context, nameTest, LocationStepQueryNode.NONE, nsMappings);
     }
 
     /**
@@ -107,12 +131,48 @@
      * @param position the context position of the child node to select. If
      * <code>position</code> is {@link LocationStepQueryNode#NONE}, the context
      * position of the child node is not checked.
+     * @param nsMapping the internal namespace mappings.
      */
-    ChildAxisQuery(ItemStateManager itemMgr, Query context, String nameTest, int position) {
+    ChildAxisQuery(ItemStateManager itemMgr,
+                   Query context,
+                   Name nameTest,
+                   int position,
+                   NamespaceMappings nsMapping) {
         this.itemMgr = itemMgr;
         this.contextQuery = context;
         this.nameTest = nameTest;
         this.position = position;
+        this.nsMappings = nsMapping;
+    }
+
+    /**
+     * @return the context query of this child axis query.
+     */
+    Query getContextQuery() {
+        return contextQuery;
+    }
+
+    /**
+     * @return <code>true</code> if this child axis query matches any child
+     *         node; <code>false</code> otherwise.
+     */
+    boolean matchesAnyChildNode() {
+        return nameTest == null && position == LocationStepQueryNode.NONE;
+    }
+
+    /**
+     * @return the name test or <code>null</code> if none was specified.
+     */
+    Name getNameTest() {
+        return nameTest;
+    }
+
+    /**
+     * @return the position check or {@link LocationStepQueryNode#NONE} is none
+     *         was specified.
+     */
+    int getPosition() {
+        return position;
     }
 
     /**
@@ -140,18 +200,26 @@
         if (cQuery == contextQuery) {
             return this;
         } else {
-            return new ChildAxisQuery(itemMgr, cQuery, nameTest, position);
+            return new ChildAxisQuery(itemMgr, cQuery, nameTest,
+                    position, nsMappings);
         }
     }
 
     /**
-     * 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();
     }
 
     //-------------------< ChildAxisWeight >------------------------------------
@@ -215,9 +283,10 @@
         public Scorer scorer(IndexReader reader) throws IOException {
             contextScorer = contextQuery.weight(searcher).scorer(reader);
             if (nameTest != null) {
-                nameTestScorer = new TermQuery(new Term(FieldNames.LABEL, nameTest)).weight(searcher).scorer(reader);
+                nameTestScorer = new NameQuery(nameTest, nsMappings).weight(searcher).scorer(reader);
             }
-            return new ChildAxisScorer(searcher.getSimilarity(), reader);
+            return new ChildAxisScorer(searcher.getSimilarity(),
+                    reader, (HierarchyResolver) reader);
         }
 
         /**
@@ -241,6 +310,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 +329,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;
         }
 
         /**
@@ -269,7 +347,7 @@
             do {
                 nextDoc = hits.next();
             } while (nextDoc > -1 && !indexIsValid(nextDoc));
-            
+
             return nextDoc > -1;
         }
 
@@ -293,9 +371,10 @@
         public boolean skipTo(int target) throws IOException {
             calculateChildren();
             nextDoc = hits.skipTo(target);
-            while (nextDoc > -1 && !indexIsValid(nextDoc))
+            while (nextDoc > -1 && !indexIsValid(nextDoc)) {
                 next();
-            return nextDoc > -1;            
+            }
+            return nextDoc > -1;
         }
 
         /**
@@ -310,50 +389,49 @@
 
         private void calculateChildren() throws IOException {
             if (hits == null) {
-                
-                // collect all context nodes
-                List uuids = new ArrayList();
-                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
-                int i = contextHits.next();
-                while (i > -1) {
-                    String uuid = reader.document(i).get(FieldNames.UUID);
-                    uuids.add(uuid);
-                    i = contextHits.next();
-                }
-                
-                // 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());
+                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);
                         }
-                    }
-                } finally {
-                    docs.close();
-                }
-                
-                if (nameTestScorer != null) {
-                    hits = new HitsIntersection(childrenHits, new ScorerHits(nameTestScorer));
+                    });
                 } else {
-                    hits = childrenHits;
+                    // 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());
+                                    }
+                                    // indicate that we switched
+                                    docIds = null;
+                                }
+                            }
+                        }
+                    });
                 }
+
+                hits = calc[0].getHits();
             }
         }
 
         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 {
@@ -418,4 +496,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 = ((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
+                }
+            }
+            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/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java?rev=748139&r1=748138&r2=748139&view=diff
==============================================================================
--- jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java (original)
+++ jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DescendantSelfAxisQuery.java Thu Feb 26 13:24:08 2009
@@ -24,6 +24,9 @@
 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.BitSet;
@@ -37,6 +40,11 @@
 class DescendantSelfAxisQuery extends Query {
 
     /**
+     * The logger instance for this class.
+     */
+    private static final Logger log = LoggerFactory.getLogger(DescendantSelfAxisQuery.class);
+
+    /**
      * The context query
      */
     private final Query contextQuery;
@@ -90,6 +98,14 @@
     }
 
     /**
+     * @return <code>true</code> if the sub query of this <code>DescendantSelfAxisQuery</code>
+     *         matches all nodes.
+     */
+    boolean subQueryMatchesAll() {
+        return subQuery instanceof MatchAllDocsQuery;
+    }
+
+    /**
      * Creates a <code>Weight</code> instance for this query.
      *
      * @param searcher the <code>Searcher</code> instance to use.
@@ -106,7 +122,13 @@
      * @return 'DescendantSelfAxisQuery'.
      */
     public String toString(String field) {
-        return "DescendantSelfAxisQuery";
+        StringBuffer sb = new StringBuffer();
+        sb.append("DescendantSelfAxisQuery(");
+        sb.append(contextQuery);
+        sb.append(", ");
+        sb.append(subQuery);
+        sb.append(")");
+        return sb.toString();
     }
 
     /**
@@ -256,14 +278,27 @@
                 return false;
             }
             int nextDoc = subScorer.doc();
+            int numInvalid = 0;
+            long time = System.currentTimeMillis();
             while (nextDoc > -1) {
 
                 if (isValid(nextDoc)) {
+                    if (numInvalid > 0) {
+                        time = System.currentTimeMillis() - time;
+                        log.debug("Skipped {} nodes in {} ms. Not matching hierarchy constraint.",
+                                new Integer(numInvalid), new Long(time));
+                    }
                     return true;
                 }
 
                 // try next
                 nextDoc = subScorer.next() ? subScorer.doc() : -1;
+                numInvalid++;
+            }
+            if (numInvalid > 0) {
+                time = System.currentTimeMillis() - time;
+                log.debug("Skipped {} nodes in {} ms. Not matching hierarchy constraint.",
+                        new Integer(numInvalid), new Long(time));
             }
             return false;
         }
@@ -302,12 +337,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
+                            });
+                }
             }
         }
 

Modified: jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java?rev=748139&r1=748138&r2=748139&view=diff
==============================================================================
--- jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (original)
+++ jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java Thu Feb 26 13:24:08 2009
@@ -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;
 
@@ -525,15 +526,9 @@
             }
         }
 
-        TermQuery nameTest = null;
+        NameQuery nameTest = null;
         if (node.getNameTest() != null) {
-            try {
-                String internalName = resolver.getJCRName(node.getNameTest());
-                nameTest = new TermQuery(new Term(FieldNames.LABEL, internalName));
-            } catch (NamespaceException e) {
-                // should never happen
-                exceptions.add(e);
-            }
+            nameTest = new NameQuery(node.getNameTest(), nsMappings);
         }
 
         if (node.getIncludeDescendants()) {
@@ -555,17 +550,12 @@
                     }
                 } 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
-                    }
+                    Query subQuery = new MatchAllDocsQuery();
                     // 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);
+                        andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex(), nsMappings), Occur.MUST);
                     } else {
                         andQuery.add(subQuery, Occur.MUST);
                     }
@@ -574,10 +564,10 @@
         } else {
             // name test
             if (nameTest != null) {
-                andQuery.add(new ChildAxisQuery(sharedItemMgr, context, nameTest.getTerm().text(), node.getIndex()), Occur.MUST);
+                andQuery.add(new ChildAxisQuery(sharedItemMgr, context, nameTest.getName(), node.getIndex(), nsMappings), Occur.MUST);
             } else {
                 // select child nodes
-                andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex()), Occur.MUST);
+                andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex(), nsMappings), Occur.MUST);
             }
         }
 

Added: jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java?rev=748139&view=auto
==============================================================================
--- jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java (added)
+++ jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java Thu Feb 26 13:24:08 2009
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.query.lucene;
+
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
+
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * <code>NameQuery</code> implements a query for the name of a node.
+ */
+public class NameQuery extends Query {
+
+    /**
+     * The node name.
+     */
+    private final Name nodeName;
+
+    /**
+     * The internal namespace mappings of the index.
+     */
+    private final NamespaceMappings nsMappings;
+
+    /**
+     * Creates a new <code>NameQuery</code>.
+     *
+     * @param nodeName   the name of the nodes to return.
+     * @param nsMappings the namespace mappings of the index.
+     */
+    public NameQuery(Name nodeName,
+                     NamespaceMappings nsMappings) {
+        this.nodeName = nodeName;
+        this.nsMappings = nsMappings;
+    }
+
+    /**
+     * @return the name of the nodes to return.
+     */
+    public Name getName() {
+        return nodeName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Query rewrite(IndexReader reader) throws IOException {
+        // use LABEL field
+        try {
+            return new TermQuery(new Term(FieldNames.LABEL,
+                    nsMappings.translatePropertyName(nodeName)));
+        } catch (IllegalNameException e) {
+            throw (IOException) new IOException().initCause(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void extractTerms(Set terms) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString(String field) {
+        return "name() = " + nodeName.toString();
+    }
+}

Propchange: jackrabbit/branches/1.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java
------------------------------------------------------------------------------
    svn:eol-style = native