Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 87857 invoked from network); 30 Nov 2006 13:34:16 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 30 Nov 2006 13:34:16 -0000 Received: (qmail 19303 invoked by uid 500); 30 Nov 2006 13:34:25 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 19281 invoked by uid 500); 30 Nov 2006 13:34:24 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 19272 invoked by uid 99); 30 Nov 2006 13:34:24 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 30 Nov 2006 05:34:24 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 30 Nov 2006 05:34:14 -0800 Received: by eris.apache.org (Postfix, from userid 65534) id 100011A984D; Thu, 30 Nov 2006 05:33:36 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r480917 - in /jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene: LazyQueryResultImpl.java QueryImpl.java QueryResultImpl.java Date: Thu, 30 Nov 2006 13:33:35 -0000 To: commits@jackrabbit.apache.org From: mreutegg@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20061130133336.100011A984D@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: mreutegg Date: Thu Nov 30 05:33:34 2006 New Revision: 480917 URL: http://svn.apache.org/viewvc?view=rev&rev=480917 Log: JCR-651: Improve performance for queries with large result sets - reverted changes on QueryResultImpl to provide a backward compatible constructor - the newly introduces lazy access right check is now implemented in LazyQueryResultImpl. Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/LazyQueryResultImpl.java (with props) Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/LazyQueryResultImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/LazyQueryResultImpl.java?view=auto&rev=480917 ============================================================================== --- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/LazyQueryResultImpl.java (added) +++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/LazyQueryResultImpl.java Thu Nov 30 05:33:34 2006 @@ -0,0 +1,441 @@ +/* + * 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.jackrabbit.core.ItemManager; +import org.apache.jackrabbit.core.NodeId; +import org.apache.jackrabbit.core.NodeImpl; +import org.apache.jackrabbit.core.security.AccessManager; +import org.apache.jackrabbit.name.NamespaceResolver; +import org.apache.jackrabbit.name.NoPrefixDeclaredException; +import org.apache.jackrabbit.name.QName; +import org.apache.jackrabbit.name.NameFormat; +import org.apache.lucene.search.Query; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.ItemNotFoundException; +import javax.jcr.Node; +import javax.jcr.query.QueryResult; +import javax.jcr.query.RowIterator; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * Implements the javax.jcr.query.QueryResult interface. + */ +public class LazyQueryResultImpl implements QueryResult { + + /** + * The logger instance for this class + */ + private static final Logger log = LoggerFactory.getLogger(QueryResultImpl.class); + + /** + * The search index to execute the query. + */ + private final SearchIndex index; + + /** + * The item manager of the session executing the query + */ + private final ItemManager itemMgr; + + /** + * The namespace resolver of the session executing the query + */ + protected final NamespaceResolver resolver; + + /** + * The access manager of the session that executes the query. + */ + private final AccessManager accessMgr; + + /** + * The query instance which created this query result. + */ + protected final QueryImpl queryImpl; + + /** + * The lucene query to execute. + */ + protected final Query query; + + /** + * The select properties + */ + protected final QName[] selectProps; + + /** + * The names of properties to use for ordering the result set. + */ + protected final QName[] orderProps; + + /** + * The order specifier for each of the order properties. + */ + protected final boolean[] orderSpecs; + + /** + * The result nodes including their score. This list is populated on a lazy + * basis while a client iterates through the results. + */ + private final List resultNodes = new ArrayList(); + + /** + * 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. + */ + private int numResults = -1; + + /** + * The number of results that are invalid, either because a node does not + * exist anymore or because the session does not have access to the node. + */ + private int invalid = 0; + + /** + * If true nodes are returned in document order. + */ + private final boolean docOrder; + + /** + * Creates a new query result. + * + * @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 accessMgr the access manager of the session executiong the + * query. + * @param queryImpl the query instance which created this query result. + * @param query the lucene query to execute on the index. + * @param selectProps the select properties of the query. + * @param orderProps the names of the order properties. + * @param orderSpecs the order specs, one for each order property name. + * @param documentOrder if true the result is returned in + * document order. + */ + public LazyQueryResultImpl(SearchIndex index, + ItemManager itemMgr, + NamespaceResolver resolver, + AccessManager accessMgr, + QueryImpl queryImpl, + Query query, + QName[] selectProps, + QName[] orderProps, + boolean[] orderSpecs, + boolean documentOrder) throws RepositoryException { + this.index = index; + this.itemMgr = itemMgr; + this.resolver = resolver; + this.accessMgr = accessMgr; + this.queryImpl = queryImpl; + this.query = query; + this.selectProps = selectProps; + this.orderProps = orderProps; + this.orderSpecs = orderSpecs; + this.docOrder = orderProps.length == 0 && documentOrder; + // if document order is requested get all results right away + getResults(docOrder ? Integer.MAX_VALUE : index.getResultFetchSize()); + } + + /** + * {@inheritDoc} + */ + public String[] getColumnNames() throws RepositoryException { + try { + String[] propNames = new String[selectProps.length]; + for (int i = 0; i < selectProps.length; i++) { + propNames[i] = NameFormat.format(selectProps[i], resolver); + } + return propNames; + } catch (NoPrefixDeclaredException npde) { + String msg = "encountered invalid property name"; + log.debug(msg); + throw new RepositoryException(msg, npde); + + } + } + + /** + * {@inheritDoc} + */ + public NodeIterator getNodes() throws RepositoryException { + return getNodeIterator(); + } + + /** + * {@inheritDoc} + */ + public RowIterator getRows() throws RepositoryException { + return new RowIteratorImpl(getNodeIterator(), selectProps, resolver); + } + + /** + * Executes the query for this result and returns hits. The caller must + * close the query hits when he is done using it. + * + * @return hits for this query result. + * @throws IOException if an error occurs while executing the query. + */ + protected QueryHits executeQuery() throws IOException { + return index.executeQuery(queryImpl, query, orderProps, orderSpecs); + } + + //--------------------------------< internal >------------------------------ + + /** + * Creates a node iterator over the result nodes. + * + * @return a node iterator over the result nodes. + */ + private ScoreNodeIterator getNodeIterator() { + if (docOrder) { + return new DocOrderNodeIteratorImpl(itemMgr, resultNodes); + } else { + return new LazyScoreNodeIterator(); + } + } + + /** + * Attempts to get size results and puts them into {@link + * #resultNodes}. If the size of {@link #resultNodes} is less than + * size then there are no more than resultNodes.size() + * results for this query. + * + * @param size the number of results to fetch for the query. + * @throws RepositoryException if an error occurs while executing the + * query. + */ + private void getResults(int size) throws RepositoryException { + if (log.isDebugEnabled()) { + log.debug("getResults(" + size + ")"); + } + if (resultNodes.size() >= size) { + // we already have them all + return; + } + + // execute it + QueryHits result = null; + try { + result = executeQuery(); + + // set num results with the first query execution + if (numResults == -1) { + numResults = result.length(); + } + + int start = resultNodes.size() + invalid; + int max = Math.min(result.length(), numResults); + for (int i = start; i < max && resultNodes.size() < size; i++) { + NodeId id = NodeId.valueOf(result.doc(i).get(FieldNames.UUID)); + // check access + try { + if (accessMgr.isGranted(id, AccessManager.READ)) { + resultNodes.add(new ScoreNode(id, result.score(i))); + } + } catch (ItemNotFoundException e) { + // has been deleted meanwhile + invalid++; + } + } + } catch (IOException e) { + log.error("Exception while executing query: ", e); + // todo throw? + } finally { + if (result != null) { + try { + result.close(); + } catch (IOException e) { + log.warn("Unable to close query result: " + e); + } + } + } + } + + private final class LazyScoreNodeIterator implements ScoreNodeIterator { + + private int position = -1; + + private boolean initialized = false; + + private NodeImpl next; + + /** + * {@inheritDoc} + */ + public float getScore() { + initialize(); + if (!hasNext()) { + throw new NoSuchElementException(); + } + return ((ScoreNode) resultNodes.get(position)).getScore(); + } + + /** + * {@inheritDoc} + */ + public NodeImpl nextNodeImpl() { + initialize(); + if (next == null) { + throw new NoSuchElementException(); + } + NodeImpl n = next; + fetchNext(); + return n; + } + + /** + * {@inheritDoc} + */ + public Node nextNode() { + return nextNodeImpl(); + } + + /** + * {@inheritDoc} + */ + public void skip(long skipNum) { + initialize(); + 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 { + // attempt to get enough results + try { + getResults(position + invalid + (int) skipNum); + if (resultNodes.size() >= position + skipNum) { + // skip within already fetched results + position += skipNum - 1; + fetchNext(); + } else { + // not enough results after getResults() + throw new NoSuchElementException(); + } + } catch (RepositoryException e) { + throw new NoSuchElementException(e.getMessage()); + } + } + } + + /** + * {@inheritDoc} + *

+ * This value may shrink when the query result encounters non-existing + * nodes or the session does not have access to a node. + */ + public long getSize() { + return numResults - invalid; + } + + /** + * {@inheritDoc} + */ + public long getPosition() { + initialize(); + return position; + } + + /** + * @throws UnsupportedOperationException always. + */ + public void remove() { + throw new UnsupportedOperationException("remove"); + } + + /** + * {@inheritDoc} + */ + public boolean hasNext() { + initialize(); + return next != null; + } + + /** + * {@inheritDoc} + */ + public Object next() { + return nextNodeImpl(); + } + + /** + * Initializes this iterator but only if it is not yet initialized. + */ + private void initialize() { + if (!initialized) { + fetchNext(); + initialized = true; + } + } + + /** + * Fetches the next node to return by this iterator. If this method + * returns and {@link #next} is null then there is no next + * node. + */ + private void fetchNext() { + next = null; + int nextPos = position + 1; + while (next == null && (nextPos + invalid) < numResults) { + if (nextPos >= resultNodes.size()) { + // fetch more results + try { + int num; + if (resultNodes.size() == 0) { + num = index.getResultFetchSize(); + } else { + num = resultNodes.size() * 2; + } + getResults(num); + } catch (RepositoryException e) { + log.warn("Exception getting more results: " + e); + } + // check again + if (nextPos >= resultNodes.size()) { + // no more valid results + return; + } + } + ScoreNode sn = (ScoreNode) resultNodes.get(nextPos); + try { + next = (NodeImpl) itemMgr.getItem(sn.getNodeId()); + } catch (RepositoryException e) { + log.warn("Exception retrieving Node with UUID: " + + sn.getNodeId() + ": " + e.toString()); + // remove score node and try next + resultNodes.remove(nextPos); + invalid++; + } + } + position++; + } + } +} Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/LazyQueryResultImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java?view=diff&rev=480917&r1=480916&r2=480917 ============================================================================== --- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java (original) +++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java Thu Nov 30 05:33:34 2006 @@ -160,7 +160,7 @@ ascSpecs[i] = orderSpecs[i].isAscending(); } - return new QueryResultImpl(index, itemMgr, session.getNamespaceResolver(), + return new LazyQueryResultImpl(index, itemMgr, session.getNamespaceResolver(), session.getAccessManager(), this, query, getSelectProperties(), orderProperties, ascSpecs, documentOrder); } Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java?view=diff&rev=480917&r1=480916&r2=480917 ============================================================================== --- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java (original) +++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java Thu Nov 30 05:33:34 2006 @@ -18,26 +18,18 @@ import org.apache.jackrabbit.core.ItemManager; import org.apache.jackrabbit.core.NodeId; -import org.apache.jackrabbit.core.NodeImpl; -import org.apache.jackrabbit.core.security.AccessManager; import org.apache.jackrabbit.name.NamespaceResolver; import org.apache.jackrabbit.name.NoPrefixDeclaredException; import org.apache.jackrabbit.name.QName; import org.apache.jackrabbit.name.NameFormat; -import org.apache.lucene.search.Query; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; -import javax.jcr.ItemNotFoundException; -import javax.jcr.Node; import javax.jcr.query.QueryResult; import javax.jcr.query.RowIterator; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; +import java.util.Arrays; /** * Implements the javax.jcr.query.QueryResult interface. @@ -50,69 +42,24 @@ private static final Logger log = LoggerFactory.getLogger(QueryResultImpl.class); /** - * The search index to execute the query. - */ - private final SearchIndex index; - - /** * The item manager of the session executing the query */ private final ItemManager itemMgr; /** - * The namespace resolver of the session executing the query - */ - protected final NamespaceResolver resolver; - - /** - * The access manager of the session that executes the query. - */ - private final AccessManager accessMgr; - - /** - * The query instance which created this query result. - */ - protected final QueryImpl queryImpl; - - /** - * The lucene query to execute. + * The result nodes and their scores */ - protected final Query query; + private final ScoreNode[] scoreNodes; /** * The select properties */ - protected final QName[] selectProps; - - /** - * The names of properties to use for ordering the result set. - */ - protected final QName[] orderProps; - - /** - * The order specifier for each of the order properties. - */ - protected final boolean[] orderSpecs; - - /** - * The result nodes including their score. This list is populated on a lazy - * basis while a client iterates through the results. - */ - private final List resultNodes = new ArrayList(); + private final QName[] selectProps; /** - * 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. - */ - private int numResults = -1; - - /** - * The number of results that are invalid, either because a node does not - * exist anymore or because the session does not have access to the node. + * The namespace resolver of the session executing the query */ - private int invalid = 0; + private final NamespaceResolver resolver; /** * If true nodes are returned in document order. @@ -122,43 +69,28 @@ /** * Creates a new query result. * - * @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 accessMgr the access manager of the session executiong the - * query. - * @param queryImpl the query instance which created this query result. - * @param query the lucene query to execute on the index. - * @param selectProps the select properties of the query. - * @param orderProps the names of the order properties. - * @param orderSpecs the order specs, one for each order property name. - * @param documentOrder if true the result is returned in - * document order. - */ - public QueryResultImpl(SearchIndex index, - ItemManager itemMgr, - NamespaceResolver resolver, - AccessManager accessMgr, - QueryImpl queryImpl, - Query query, + * @param itemMgr the item manager of the session executing the query. + * @param ids the Ids of the result nodes. + * @param scores the score values of the result nodes. + * @param selectProps the select properties of the query. + * @param resolver the namespace resolver of the session executing the query. + * @param docOrder if true the result is returned in document + * order. + */ + public QueryResultImpl(ItemManager itemMgr, + NodeId[] ids, + Float[] scores, QName[] selectProps, - QName[] orderProps, - boolean[] orderSpecs, - boolean documentOrder) throws RepositoryException { - this.index = index; + NamespaceResolver resolver, + boolean docOrder) { + this.scoreNodes = new ScoreNode[ids.length]; this.itemMgr = itemMgr; - this.resolver = resolver; - this.accessMgr = accessMgr; - this.queryImpl = queryImpl; - this.query = query; this.selectProps = selectProps; - this.orderProps = orderProps; - this.orderSpecs = orderSpecs; - this.docOrder = orderProps.length == 0 && documentOrder; - // if document order is requested get all results right away - getResults(docOrder ? Integer.MAX_VALUE : index.getResultFetchSize()); + this.resolver = resolver; + this.docOrder = docOrder; + for (int i = 0; i < ids.length; i++) { + scoreNodes[i] = new ScoreNode(ids[i], scores[i].floatValue()); + } } /** @@ -194,248 +126,14 @@ } /** - * Executes the query for this result and returns hits. The caller must - * close the query hits when he is done using it. - * - * @return hits for this query result. - * @throws IOException if an error occurs while executing the query. - */ - protected QueryHits executeQuery() throws IOException { - return index.executeQuery(queryImpl, query, orderProps, orderSpecs); - } - - //--------------------------------< internal >------------------------------ - - /** * Creates a node iterator over the result nodes. - * * @return a node iterator over the result nodes. */ private ScoreNodeIterator getNodeIterator() { if (docOrder) { - return new DocOrderNodeIteratorImpl(itemMgr, resultNodes); + return new DocOrderNodeIteratorImpl(itemMgr, Arrays.asList(scoreNodes)); } else { - return new LazyScoreNodeIterator(); - } - } - - /** - * Attempts to get size results and puts them into {@link - * #resultNodes}. If the size of {@link #resultNodes} is less than - * size then there are no more than resultNodes.size() - * results for this query. - * - * @param size the number of results to fetch for the query. - * @throws RepositoryException if an error occurs while executing the - * query. - */ - private void getResults(int size) throws RepositoryException { - if (log.isDebugEnabled()) { - log.debug("getResults(" + size + ")"); - } - if (resultNodes.size() >= size) { - // we already have them all - return; - } - - // execute it - QueryHits result = null; - try { - result = executeQuery(); - - // set num results with the first query execution - if (numResults == -1) { - numResults = result.length(); - } - - int start = resultNodes.size() + invalid; - int max = Math.min(result.length(), numResults); - for (int i = start; i < max && resultNodes.size() < size; i++) { - NodeId id = NodeId.valueOf(result.doc(i).get(FieldNames.UUID)); - // check access - try { - if (accessMgr.isGranted(id, AccessManager.READ)) { - resultNodes.add(new ScoreNode(id, result.score(i))); - } - } catch (ItemNotFoundException e) { - // has been deleted meanwhile - invalid++; - } - } - } catch (IOException e) { - log.error("Exception while executing query: ", e); - // todo throw? - } finally { - if (result != null) { - try { - result.close(); - } catch (IOException e) { - log.warn("Unable to close query result: " + e); - } - } - } - } - - private final class LazyScoreNodeIterator implements ScoreNodeIterator { - - private int position = -1; - - private boolean initialized = false; - - private NodeImpl next; - - /** - * {@inheritDoc} - */ - public float getScore() { - initialize(); - if (!hasNext()) { - throw new NoSuchElementException(); - } - return ((ScoreNode) resultNodes.get(position)).getScore(); - } - - /** - * {@inheritDoc} - */ - public NodeImpl nextNodeImpl() { - initialize(); - if (next == null) { - throw new NoSuchElementException(); - } - NodeImpl n = next; - fetchNext(); - return n; - } - - /** - * {@inheritDoc} - */ - public Node nextNode() { - return nextNodeImpl(); - } - - /** - * {@inheritDoc} - */ - public void skip(long skipNum) { - initialize(); - 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 { - // attempt to get enough results - try { - getResults(position + invalid + (int) skipNum); - if (resultNodes.size() >= position + skipNum) { - // skip within already fetched results - position += skipNum - 1; - fetchNext(); - } else { - // not enough results after getResults() - throw new NoSuchElementException(); - } - } catch (RepositoryException e) { - throw new NoSuchElementException(e.getMessage()); - } - } - } - - /** - * {@inheritDoc} - *

- * This value may shrink when the query result encounters non-existing - * nodes or the session does not have access to a node. - */ - public long getSize() { - return numResults - invalid; - } - - /** - * {@inheritDoc} - */ - public long getPosition() { - initialize(); - return position; - } - - /** - * @throws UnsupportedOperationException always. - */ - public void remove() { - throw new UnsupportedOperationException("remove"); - } - - /** - * {@inheritDoc} - */ - public boolean hasNext() { - initialize(); - return next != null; - } - - /** - * {@inheritDoc} - */ - public Object next() { - return nextNodeImpl(); - } - - /** - * Initializes this iterator but only if it is not yet initialized. - */ - private void initialize() { - if (!initialized) { - fetchNext(); - initialized = true; - } - } - - /** - * Fetches the next node to return by this iterator. If this method - * returns and {@link #next} is null then there is no next - * node. - */ - private void fetchNext() { - next = null; - int nextPos = position + 1; - while (next == null && (nextPos + invalid) < numResults) { - if (nextPos >= resultNodes.size()) { - // fetch more results - try { - int num; - if (resultNodes.size() == 0) { - num = index.getResultFetchSize(); - } else { - num = resultNodes.size() * 2; - } - getResults(num); - } catch (RepositoryException e) { - log.warn("Exception getting more results: " + e); - } - // check again - if (nextPos >= resultNodes.size()) { - // no more valid results - return; - } - } - ScoreNode sn = (ScoreNode) resultNodes.get(nextPos); - try { - next = (NodeImpl) itemMgr.getItem(sn.getNodeId()); - } catch (RepositoryException e) { - log.warn("Exception retrieving Node with UUID: " - + sn.getNodeId() + ": " + e.toString()); - // remove score node and try next - resultNodes.remove(nextPos); - invalid++; - } - } - position++; + return new NodeIteratorImpl(itemMgr, scoreNodes); } } }