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/19 17:25:31 UTC

svn commit: r629145 - /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/

Author: mreutegg
Date: Tue Feb 19 08:25:26 2008
New Revision: 629145

URL: http://svn.apache.org/viewvc?rev=629145&view=rev
Log:
JCR-1397: Allow query results with unknown size

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryHits.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeTraversingQueryHits.java   (with props)
Removed:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/WorkspaceTraversalResult.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PreparedQueryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryHits.java?rev=629145&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryHits.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryHits.java Tue Feb 19 08:25:26 2008
@@ -0,0 +1,69 @@
+/*
+ * 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 java.io.IOException;
+
+/**
+ * <code>AbstractQueryHits</code> serves as a base class for {@link QueryHits}
+ * implementations.
+ */
+public abstract class AbstractQueryHits implements QueryHits {
+
+    /**
+     * Calls {@link #doClose()} and disposes the {@link PerQueryCache}.
+     *
+     * @throws IOException if an error occurs while releasing resources.
+     */
+    public final void close() throws IOException {
+        try {
+            doClose();
+        } finally {
+            PerQueryCache.getInstance().dispose();
+        }
+    }
+
+    /**
+     * Provides a default implementation:
+     * <pre>
+     * while (n-- > 0) {
+     *     if (nextScoreNode() == null) {
+     *         return;
+     *     }
+     * }
+     * </pre>
+     * Sub classes may overwrite this method and implement are more efficient
+     * way to skip hits.
+     *
+     * @param n the number of hits to skip.
+     * @throws IOException if an error occurs while skipping.
+     */
+    public void skip(int n) throws IOException {
+        while (n-- > 0) {
+            if (nextScoreNode() == null) {
+                return;
+            }
+        }
+    }
+
+    /**
+     * Releases resources held by this hits instance.
+     *
+     * @throws IOException if an error occurs while releasing resources.
+     */
+    protected abstract void doClose() throws IOException;
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryHits.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java?rev=629145&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java Tue Feb 19 08:25:26 2008
@@ -0,0 +1,82 @@
+/*
+ * 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.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.index.IndexReader;
+import org.apache.jackrabbit.core.SessionImpl;
+
+import javax.jcr.RepositoryException;
+import java.io.IOException;
+
+/**
+ * <code>JackrabbitIndexSearcher</code> implements an index searcher with
+ * jackrabbit specific optimizations.
+ */
+public class JackrabbitIndexSearcher extends IndexSearcher {
+
+    /**
+     * The session that executes the query.
+     */
+    private final SessionImpl session;
+
+    /**
+     * The underlying index reader.
+     */
+    private final IndexReader reader;
+
+    /**
+     * Creates a new jackrabbit index searcher.
+     *
+     * @param s the session that executes the query.
+     * @param r the index reader.
+     */
+    public JackrabbitIndexSearcher(SessionImpl s, IndexReader r) {
+        super(r);
+        this.session = s;
+        this.reader = r;
+    }
+
+    /**
+     * Executes the query and returns the hits that match the query.
+     *
+     * @param query the query to execute.
+     * @param sort  the sort criteria.
+     * @return the query hits.
+     * @throws IOException if an error occurs while executing the query.
+     */
+    public QueryHits execute(Query query, Sort sort) throws IOException {
+        // optimize certain queries
+        if (sort.getSort().length == 0) {
+            query = query.rewrite(reader);
+            if (query instanceof MatchAllDocsQuery) {
+                try {
+                    return new NodeTraversingQueryHits(
+                            session.getRootNode(), true);
+                } catch (RepositoryException e) {
+                    IOException ex = new IOException(e.getMessage());
+                    ex.initCause(e);
+                    throw ex;
+                }
+            }
+        }
+        return new LuceneQueryHits(search(query, sort), reader);
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java?rev=629145&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java Tue Feb 19 08:25:26 2008
@@ -0,0 +1,106 @@
+/*
+ * 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.Hits;
+import org.apache.lucene.index.IndexReader;
+import org.apache.jackrabbit.core.NodeId;
+
+import java.io.IOException;
+
+/**
+ * Wraps the lucene <code>Hits</code> object and adds a close method that allows
+ * to release resources after a query has been executed and the results have
+ * been read completely.
+ */
+public class LuceneQueryHits extends AbstractQueryHits {
+
+    /**
+     * The lucene hits we wrap.
+     */
+    private final Hits hits;
+
+    /**
+     * The IndexReader in use by the lucene hits.
+     */
+    private final IndexReader reader;
+
+    /**
+     * The index of the current hit. Initially invalid.
+     */
+    private int hitIndex = -1;
+
+    /**
+     * Creates a new <code>QueryHits</code> instance wrapping <code>hits</code>.
+     * @param hits the lucene hits.
+     * @param reader the IndexReader in use by <code>hits</code>.
+     */
+    public LuceneQueryHits(Hits hits, IndexReader reader) {
+        this.hits = hits;
+        this.reader = reader;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected final void doClose() throws IOException {
+        reader.close();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public final int getSize() {
+      return hits.length();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public final ScoreNode nextScoreNode() throws IOException {
+        if (++hitIndex >= hits.length()) {
+            return null;
+        }
+        String uuid = reader.document(id(hitIndex), FieldSelectors.UUID).get(FieldNames.UUID);
+        return new ScoreNode(NodeId.valueOf(uuid), hits.score(hitIndex));
+    }
+
+    /**
+     * Skips <code>n</code> hits.
+     *
+     * @param n the number of hits to skip.
+     * @throws IOException if an error occurs while skipping.
+     */
+    public void skip(int n) throws IOException {
+        hitIndex += n;
+    }
+
+    //-------------------------------< internal >-------------------------------
+
+    /**
+     * Returns the document number for the <code>n</code><sup>th</sup> document
+     * in this QueryHits.
+     *
+     * @param n index.
+     * @return the document number for the <code>n</code><sup>th</sup>
+     *         document.
+     * @throws IOException if an error occurs.
+     */
+    private final int id(int n) throws IOException {
+        return hits.id(n);
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeTraversingQueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeTraversingQueryHits.java?rev=629145&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeTraversingQueryHits.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeTraversingQueryHits.java Tue Feb 19 08:25:26 2008
@@ -0,0 +1,159 @@
+/*
+ * 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.commons.collections.iterators.IteratorChain;
+import org.apache.jackrabbit.core.NodeImpl;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * <code>NodeTraversingQueryHits</code> implements query hits that traverse
+ * a node hierarchy.
+ */
+public class NodeTraversingQueryHits extends AbstractQueryHits {
+
+    /**
+     * The nodes to traverse.
+     */
+    private final Iterator nodes;
+
+    /**
+     * Creates query hits that consist of the nodes that are traversed from
+     * a given <code>start</code> node.
+     *
+     * @param start the start node of the traversal.
+     * @param includeStart whether to include the start node in the result.
+     */
+    public NodeTraversingQueryHits(Node start, boolean includeStart) {
+        this.nodes = new TraversingNodeIterator(start);
+        if (!includeStart) {
+            nodes.next();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * Does nothing.
+     */
+    protected void doClose() throws IOException {
+        // nothing to do
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * This implementation always returns <code>-1</code>.
+     */
+    public int getSize() {
+        // don't know
+        return -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ScoreNode nextScoreNode() throws IOException {
+        if (nodes.hasNext()) {
+            NodeImpl n = (NodeImpl) nodes.next();
+            return new ScoreNode(n.getNodeId(), 1.0f);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Implements a node iterator that traverses a node tree in document
+     * order.
+     */
+    private class TraversingNodeIterator implements Iterator {
+
+        /**
+         * The current <code>Node</code>, which acts as the starting point for
+         * the traversal.
+         */
+        private final Node currentNode;
+
+        /**
+         * The chain of iterators which includes the iterators of the children
+         * of the current node.
+         */
+        private IteratorChain selfAndChildren;
+
+        /**
+         * Creates a <code>TraversingNodeIterator</code>.
+         * @param start the node from where to start the traversal.
+         */
+        TraversingNodeIterator(Node start) {
+            currentNode = start;
+        }
+
+        /**
+         * @exception UnsupportedOperationException always.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException("remove");
+        }
+
+        /**
+         * @inheritDoc
+         */
+        public boolean hasNext() {
+            init();
+            return selfAndChildren.hasNext();
+        }
+
+        /**
+         * @inheritDoc
+         */
+        public Object next() {
+            init();
+            NodeImpl n = (NodeImpl) selfAndChildren.next();
+            return n;
+        }
+
+        /**
+         * Initializes the iterator chain once.
+         */
+        private void init() {
+            if (selfAndChildren == null) {
+                Iterator current = Arrays.asList(new Node[]{currentNode}).iterator();
+                List allIterators = new ArrayList();
+                allIterators.add(current);
+
+                // create new TraversingNodeIterator for each child
+                try {
+                    NodeIterator children = currentNode.getNodes();
+                    while (children.hasNext()) {
+                        allIterators.add(new TraversingNodeIterator(children.nextNode()));
+                    }
+                } catch (RepositoryException e) {
+                    // currentNode is probably stale
+                }
+                selfAndChildren = new IteratorChain(allIterators);
+            }
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeTraversingQueryHits.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PreparedQueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PreparedQueryImpl.java?rev=629145&r1=629144&r2=629145&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PreparedQueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PreparedQueryImpl.java Tue Feb 19 08:25:26 2008
@@ -120,7 +120,7 @@
             orderSpecs[i] = orderings[i].getOrder() == QueryObjectModelConstants.ORDER_ASCENDING;
         }
         return new QueryResultImpl(index, itemMgr,
-                session.getNamePathResolver(), session.getAccessManager(),
+                session, session.getAccessManager(),
                 // TODO: spell suggestion missing
                 this, query, null, selectProps, orderProps, orderSpecs,
                 getRespectDocumentOrder(), offset, limit);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java?rev=629145&r1=629144&r2=629145&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java Tue Feb 19 08:25:26 2008
@@ -16,94 +16,43 @@
  */
 package org.apache.jackrabbit.core.query.lucene;
 
-import org.apache.lucene.search.Hits;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.document.Document;
 
 import java.io.IOException;
 
 /**
- * Wraps the lucene <code>Hits</code> object and adds a close method that allows
- * to release resources after a query has been executed and the results have
- * been read completely.
+ * Defines an interface for reading query hits. A client will call {@link
+ * #close()} to release resources after a query has been executed and the
+ * results have been read.
  */
-public class QueryHits {
-
-    /**
-     * The lucene hits we wrap.
-     */
-    private final Hits hits;
-
-    /**
-     * The IndexReader in use by the lucene hits.
-     */
-    private final IndexReader reader;
-
-    /**
-     * Number of results.
-     */
-    private final int length;
-
-    /**
-     * Creates a new <code>QueryHits</code> instance wrapping <code>hits</code>.
-     * @param hits the lucene hits.
-     * @param reader the IndexReader in use by <code>hits</code>.
-     */
-    public QueryHits(Hits hits, IndexReader reader) {
-        this.hits = hits;
-        this.reader = reader;
-        this.length = hits.length();
-    }
+public interface QueryHits {
 
     /**
      * Releases resources held by this hits instance.
      *
      * @throws IOException if an error occurs while releasing resources.
      */
-    public final void close() throws IOException {
-        reader.close();
-        PerQueryCache.getInstance().dispose();
-    }
+    void close() throws IOException;
 
     /**
-     * Returns the number of results.
-     * @return the number of results.
+     * @return the number of results or <code>-1</code> if the size is unknown.
      */
-    public final int length() {
-      return length;
-    }
+    int getSize();
 
     /**
-     * Returns the <code>n</code><sup>th</sup> document in this QueryHits.
+     * Returns the next score node in this QueryHits or <code>null</code> if
+     * there are no more score nodes.
      *
-     * @param n index.
-     * @return the <code>n</code><sup>th</sup> document in this QueryHits.
+     * @return the next score node in this QueryHits.
      * @throws IOException if an error occurs while reading from the index.
      */
-    public final Document doc(int n) throws IOException {
-        return hits.doc(n);
-    }
-
-    /**
-     * Returns the score for the <code>n</code><sup>th</sup> document in this
-     * QueryHits.
-     * @param n index.
-     * @return the score for the <code>n</code><sup>th</sup> document.
-     */
-    public final float score(int n) throws IOException {
-      return hits.score(n);
-    }
+    ScoreNode nextScoreNode() throws IOException;
 
     /**
-     * Returns the document number for the <code>n</code><sup>th</sup> document
-     * in this QueryHits.
+     * Skips a <code>n</code> score nodes.
      *
-     * @param n index.
-     * @return the document number for the <code>n</code><sup>th</sup>
-     *         document.
-     * @throws IOException if an error occurs.
+     * @param n the number of score nodes to skip.
+     * @throws IOException if an error occurs while skipping.
      */
-    public final int id(int n) throws IOException {
-        return hits.id(n);
-    }
+    void skip(int n) throws IOException;
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java?rev=629145&r1=629144&r2=629145&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java Tue Feb 19 08:25:26 2008
@@ -45,7 +45,8 @@
 import java.util.List;
 
 /**
- * Implements the {@link ExecutableQuery} interface.
+ * Implements the {@link org.apache.jackrabbit.core.query.ExecutableQuery}
+ * interface.
  */
 public class QueryImpl extends AbstractQueryImpl {
 
@@ -105,13 +106,6 @@
             log.debug("Executing query: \n" + root.dump());
         }
 
-        // check for special query
-        if (allNodesQueryNode.equals(root)) {
-            return new WorkspaceTraversalResult(session,
-                    new Name[] { NameConstants.JCR_PRIMARYTYPE, NameConstants.JCR_PATH, NameConstants.JCR_SCORE },
-                    session.getNamePathResolver());
-        }
-
         // build lucene query
         Query query = LuceneQueryBuilder.createQuery(root, session,
                 index.getContext().getItemStateManager(),
@@ -135,7 +129,7 @@
         }
 
         return new QueryResultImpl(index, itemMgr,
-                session.getNamePathResolver(), session.getAccessManager(),
+                session, session.getAccessManager(),
                 this, query, new SpellSuggestion(index.getSpellChecker(), root),
                 getSelectProperties(), orderProperties, ascSpecs,
                 getRespectDocumentOrder(), offset, limit);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java?rev=629145&r1=629144&r2=629145&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java Tue Feb 19 08:25:26 2008
@@ -17,11 +17,10 @@
 package org.apache.jackrabbit.core.query.lucene;
 
 import org.apache.jackrabbit.core.ItemManager;
-import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.security.AccessManager;
 import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
 import org.apache.lucene.search.Query;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,9 +58,9 @@
     private final ItemManager itemMgr;
 
     /**
-     * The name and path resolver of the session executing the query
+     * The session executing the query
      */
-    protected final NamePathResolver resolver;
+    protected final SessionImpl session;
 
     /**
      * The access manager of the session that executes the query.
@@ -107,8 +106,7 @@
     /**
      * This is the raw number of results that matched the query. This number
      * also includes matches which will not be returned due to access
-     * restrictions. This value is set when the query is executed the first
-     * time.
+     * restrictions. This value is set whenever hits are obtained.
      */
     private int numResults = -1;
 
@@ -144,8 +142,7 @@
      * @param index           the search index where the query is executed.
      * @param itemMgr         the item manager of the session executing the
      *                        query.
-     * @param resolver        the namespace resolver of the session executing
-     *                        the query.
+     * @param session         the session executing the query.
      * @param accessMgr       the access manager of the session executiong the
      *                        query.
      * @param queryImpl       the query instance which created this query
@@ -164,7 +161,7 @@
      */
     public QueryResultImpl(SearchIndex index,
                            ItemManager itemMgr,
-                           NamePathResolver resolver,
+                           SessionImpl session,
                            AccessManager accessMgr,
                            AbstractQueryImpl queryImpl,
                            Query query,
@@ -177,7 +174,7 @@
                            long limit) throws RepositoryException {
         this.index = index;
         this.itemMgr = itemMgr;
-        this.resolver = resolver;
+        this.session = session;
         this.accessMgr = accessMgr;
         this.queryImpl = queryImpl;
         this.query = query;
@@ -199,7 +196,7 @@
         try {
             String[] propNames = new String[selectProps.length];
             for (int i = 0; i < selectProps.length; i++) {
-                propNames[i] = resolver.getJCRName(selectProps[i]);
+                propNames[i] = session.getJCRName(selectProps[i]);
             }
             return propNames;
         } catch (NamespaceException npde) {
@@ -228,7 +225,7 @@
             }
         }
         return new RowIteratorImpl(getNodeIterator(), selectProps,
-                resolver, excerptProvider, spellSuggestion);
+                session, excerptProvider, spellSuggestion);
     }
 
     /**
@@ -239,7 +236,8 @@
      * @throws IOException if an error occurs while executing the query.
      */
     protected QueryHits executeQuery() throws IOException {
-        return index.executeQuery(queryImpl, query, orderProps, orderSpecs);
+        return index.executeQuery(session, queryImpl,
+                query, orderProps, orderSpecs);
     }
 
     //--------------------------------< internal >------------------------------
@@ -269,7 +267,7 @@
      */
     private void getResults(long size) throws RepositoryException {
         if (log.isDebugEnabled()) {
-            log.debug("getResults(" + size + ")");
+            log.debug("getResults({}) limit={}", new Long(size), new Long(limit));
         }
 
         long maxResultSize = size;
@@ -287,21 +285,21 @@
         // execute it
         QueryHits result = null;
         try {
+            long time = System.currentTimeMillis();
             result = executeQuery();
-
-            // set num results with the first query execution
-            if (numResults == -1) {
-                numResults = result.length();
-            }
+            log.debug("query executed in {} ms",
+                    new Long(System.currentTimeMillis() - time));
 
             int start = resultNodes.size() + invalid + (int) offset;
-            int max = Math.min(result.length(), numResults);
-            for (int i = start; i < max && resultNodes.size() < maxResultSize; i++) {
-                NodeId id = NodeId.valueOf(result.doc(i).get(FieldNames.UUID));
+            time = System.currentTimeMillis();
+            result.skip(start);
+            for (ScoreNode sn = result.nextScoreNode();
+                 sn != null && resultNodes.size() < maxResultSize;
+                 sn = result.nextScoreNode()) {
                 // check access
                 try {
-                    if (accessMgr.isGranted(id, AccessManager.READ)) {
-                        resultNodes.add(new ScoreNode(id, result.score(i)));
+                    if (accessMgr.isGranted(sn.getNodeId(), AccessManager.READ)) {
+                        resultNodes.add(sn);
                     } else {
                         invalid++;
                     }
@@ -310,6 +308,11 @@
                     invalid++;
                 }
             }
+            log.debug("retrieved ScoreNodes in {} ms",
+                    new Long(System.currentTimeMillis() - time));
+
+            // update numResults
+            numResults = result.getSize();
         } catch (IOException e) {
             log.error("Exception while executing query: ", e);
             // todo throw?
@@ -328,10 +331,15 @@
      * Returns the total number of hits. This is the number of results you
      * will get get if you don't set any limit or offset. Keep in mind that this
      * number may get smaller if nodes are found in the result set which the
-     * current session has no permission to access.
+     * current session has no permission to access. This method may return
+     * <code>-1</code> if the total size is unknown.
      */
     public int getTotalSize() {
-        return numResults - invalid;
+        if (numResults == -1) {
+            return -1;
+        } else {
+            return numResults - invalid;
+        }
     }
 
     private final class LazyScoreNodeIterator implements ScoreNodeIterator {
@@ -381,9 +389,6 @@
             if (skipNum < 0) {
                 throw new IllegalArgumentException("skipNum must not be negative");
             }
-            if ((position + invalid + skipNum) > numResults) {
-                throw new NoSuchElementException();
-            }
             if (skipNum == 0) {
                 // do nothing
             } else {
@@ -411,7 +416,11 @@
          * nodes or the session does not have access to a node.
          */
         public long getSize() {
-            long size = getTotalSize() - offset;
+            int total = getTotalSize();
+            if (total == -1) {
+                return -1;
+            }
+            long size = total - offset;
             if (limit > 0 && size > limit) {
                 return limit;
             } else {
@@ -467,8 +476,14 @@
         private void fetchNext() {
             next = null;
             int nextPos = position + 1;
-            while (next == null && (nextPos + invalid) < numResults) {
+            while (next == null) {
                 if (nextPos >= resultNodes.size()) {
+                    // quick check if there are more results at all
+                    // this check is only possible if we have numResults
+                    if (numResults != -1 && (nextPos + invalid) >= numResults) {
+                        break;
+                    }
+
                     // fetch more results
                     try {
                         int num;
@@ -484,7 +499,7 @@
                     // check again
                     if (nextPos >= resultNodes.size()) {
                         // no more valid results
-                        return;
+                        break;
                     }
                 }
                 ScoreNode sn = (ScoreNode) resultNodes.get(nextPos);

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java?rev=629145&r1=629144&r2=629145&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java Tue Feb 19 08:25:26 2008
@@ -47,8 +47,6 @@
 import org.apache.lucene.index.MultiReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermDocs;
-import org.apache.lucene.search.Hits;
-import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.Sort;
 import org.apache.lucene.search.SortField;
@@ -638,6 +636,7 @@
 
     /**
      * Executes the query on the search index.
+     * @param session the session that executes the query.
      * @param queryImpl the query impl.
      * @param query the lucene query.
      * @param orderProps name of the properties for sort order.
@@ -647,22 +646,17 @@
      * @return the lucene Hits object.
      * @throws IOException if an error occurs while searching the index.
      */
-    public QueryHits executeQuery(AbstractQueryImpl queryImpl,
+    public QueryHits executeQuery(SessionImpl session,
+                                  AbstractQueryImpl queryImpl,
                                   Query query,
                                   Name[] orderProps,
                                   boolean[] orderSpecs) throws IOException {
         checkOpen();
-        SortField[] sortFields = createSortFields(orderProps, orderSpecs);
+
+        Sort sort = new Sort(createSortFields(orderProps, orderSpecs));
 
         IndexReader reader = getIndexReader(queryImpl.needsSystemTree());
-        IndexSearcher searcher = new IndexSearcher(reader);
-        Hits hits;
-        if (sortFields.length > 0) {
-            hits = searcher.search(query, new Sort(sortFields));
-        } else {
-            hits = searcher.search(query);
-        }
-        return new QueryHits(hits, reader);
+        return new JackrabbitIndexSearcher(session, reader).execute(query, sort);
     }
 
     /**