Revision: 14589
http://gate.svn.sourceforge.net/gate/?rev=14589&view=rev
Author: valyt
Date: 2011-11-22 17:57:48 +0000 (Tue, 22 Nov 2011)
Log Message:
-----------
- new QueryRunner API,
- RankingQueryRunnerImpl(*) now works,
- old QueryRunner interface renamed to QueryRunnerMk1 for now.
(*) this is a working name; it will probably revert to being called simply
QueryRunnerImpl.
Modified Paths:
--------------
mimir/trunk/mimir-core/src/gate/mimir/search/FederatedQueryRunner.java
mimir/trunk/mimir-core/src/gate/mimir/search/QueryEngine.java
mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunner.java
mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunnerImpl.java
mimir/trunk/mimir-core/src/gate/mimir/search/RankingQueryRunnerImpl.java
Added Paths:
-----------
mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunnerMk1.java
Modified: mimir/trunk/mimir-core/src/gate/mimir/search/FederatedQueryRunner.java
===================================================================
--- mimir/trunk/mimir-core/src/gate/mimir/search/FederatedQueryRunner.java
2011-11-22 13:54:51 UTC (rev 14588)
+++ mimir/trunk/mimir-core/src/gate/mimir/search/FederatedQueryRunner.java
2011-11-22 17:57:48 UTC (rev 14589)
@@ -31,14 +31,14 @@
/**
* QueryRunner implementation for querying federated indexes.
*/
-public class FederatedQueryRunner implements QueryRunner {
+public class FederatedQueryRunner implements QueryRunnerMk1 {
/**
* The QueryRunners running the sub-queries of this federated
* query. Typically this would be one runner for each sub-index,
* all running the same query string.
*/
- protected QueryRunner[] subRunners;
+ protected QueryRunnerMk1[] subRunners;
/**
* A pointer to the most recent DocumentData object in the
@@ -124,7 +124,7 @@
* Create a federated query runner that delegates to the specified
* sub-query runners.
*/
- public FederatedQueryRunner(QueryRunner[] subRunners) {
+ public FederatedQueryRunner(QueryRunnerMk1[] subRunners) {
super();
this.subRunners = subRunners;
// Java doesn't allow you to create an array of generic elements
@@ -453,7 +453,7 @@
* Tell all the sub-query runners to getMoreHits.
*/
public void getMoreHits() throws IOException {
- for(QueryRunner r : subRunners) {
+ for(QueryRunnerMk1 r : subRunners) {
r.getMoreHits();
}
}
@@ -495,7 +495,7 @@
* Pass on the stage timeout to all the sub-runners.
*/
public void setStageTimeout(int timeout) throws IOException {
- for(QueryRunner r : subRunners) {
+ for(QueryRunnerMk1 r : subRunners) {
r.setStageTimeout(timeout);
}
}
@@ -504,7 +504,7 @@
* Close all the sub-query runners.
*/
public void close() throws IOException {
- for(QueryRunner r : subRunners) {
+ for(QueryRunnerMk1 r : subRunners) {
r.close();
}
}
Modified: mimir/trunk/mimir-core/src/gate/mimir/search/QueryEngine.java
===================================================================
--- mimir/trunk/mimir-core/src/gate/mimir/search/QueryEngine.java
2011-11-22 13:54:51 UTC (rev 14588)
+++ mimir/trunk/mimir-core/src/gate/mimir/search/QueryEngine.java
2011-11-22 17:57:48 UTC (rev 14589)
@@ -182,7 +182,7 @@
* runners when the query engine itself is closed (thus releasing all open
* files).
*/
- private List<QueryRunner> activeQueryRunners;
+ private List<QueryRunnerMk1> activeQueryRunners;
/**
* @return the indexDir
@@ -363,7 +363,7 @@
readDeletedDocs();
activeQueryRunners = Collections.synchronizedList(
- new ArrayList<QueryRunner>());
+ new ArrayList<QueryRunnerMk1>());
} catch(FileNotFoundException e) {
throw new IndexException("File not found!", e);
} catch(IOException e) {
@@ -383,10 +383,10 @@
* @throws IOException
* if the index files cannot be accessed.
*/
- public QueryRunner getQueryRunner(QueryNode query) throws IOException {
+ public QueryRunnerMk1 getQueryRunner(QueryNode query) throws IOException {
logger.info("Executing query: " + query.toString());
QueryExecutor qExecutor = query.getQueryExecutor(this);
- QueryRunner qRunner = new QueryRunnerImpl(qExecutor);
+ QueryRunnerMk1 qRunner = new QueryRunnerImpl(qExecutor);
activeQueryRunners.add(qRunner);
return qRunner;
}
@@ -395,7 +395,7 @@
* Notifies the QueryEngine that the given QueryRunner has been closed.
* @param qRunner
*/
- public void releaseQueryRunner(QueryRunner qRunner) {
+ public void releaseQueryRunner(QueryRunnerMk1 qRunner) {
activeQueryRunners.remove(qRunner);
}
@@ -411,7 +411,7 @@
* @throws ParseException
* if the string provided for the query cannot be parsed.
*/
- public QueryRunner getQueryRunner(String query) throws IOException,
+ public QueryRunnerMk1 getQueryRunner(String query) throws IOException,
ParseException {
logger.info("Executing query: " + query.toString());
QueryNode qNode =
@@ -643,8 +643,8 @@
*/
public void close() {
// close all active query runners
- List<QueryRunner> runnersCopy = new
ArrayList<QueryRunner>(activeQueryRunners);
- for(QueryRunner aRunner : runnersCopy) {
+ List<QueryRunnerMk1> runnersCopy = new
ArrayList<QueryRunnerMk1>(activeQueryRunners);
+ for(QueryRunnerMk1 aRunner : runnersCopy) {
try {
logger.debug("Closing query runner: " + aRunner.toString());
aRunner.close();
Modified: mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunner.java
===================================================================
--- mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunner.java
2011-11-22 13:54:51 UTC (rev 14588)
+++ mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunner.java
2011-11-22 17:57:48 UTC (rev 14589)
@@ -8,7 +8,7 @@
* Version 3, June 2007 (also included with this distribution as file
* LICENCE-LGPL3.html).
*
- * Valentin tablan, 16 Dec 2009
+ * Valentin Tablan, 22 Nov 2011
*
* $Id$
*/
@@ -25,241 +25,157 @@
import java.util.Map;
import java.util.Set;
+
/**
- * A QueryRunner object can be used to execute a query in a separate thread.
The
- * query execution will be performed in stages, each being limited to a given
- * number of maximum hits or a set timeout. During the query execution
- * statistics are made available about the number of hits currently obtained
for
- * each document. The hits already collected can be accessed in a random
- * fashion.
+ * A QueryRunner is used to manage the execution of the query (supplied as a
+ * {@link QueryExecutor}). Implementations may use a background thread to
+ * pre-fetch data which they then make available through the public API.
*
- * N.B. Documents are referred to in two different manners:
- * <ul>
- * <li>by documentId: the ID associated with the document at indexing time,
- * which never changes</li>
- * <li>by index: the index in the list of documents found to contain
hits.</li>
- * </ul>
- * You can tell which addressing scheme is used based on the of the parameter.
+ * All references to documents are made by rank, i.e. the position of the
+ * document in the list of results.
*
- * Implementations of this interface must be thread-safe!
+ * Unless there is a good reason not to (e.g. results ranking), the documents
+ * will be returned in increasing documentID order.
+ *
+ * QueryRunners that perform ranking will re-order the result list so that
+ * documents are returned in decreasing score order.
*/
public interface QueryRunner {
-
/**
- * The default number of hits obtained in one search stage.
+ * Gets the number of result documents.
+ * @return <code>-1</code> if the search has not yet completed, the total
+ * number of result document otherwise.
*/
- public static final int DEFAULT_MAX_HITS = 1000000;
-
-
+ public int getDocumentsCount();
+
/**
- * The default maximum amount of time (in milliseconds) used for one search
- * stage.
+ * Gets the number of result documents found so far. After the search
+ * completes, the result returned by this call is identical to that of
+ * {@link #getDocumentsCount()}.
+ * @return the number of result documents known so far.
*/
- public static final int DEFAULT_TIMEOUT = 30000;
-
+ public int getCurrentDocumentsCount();
+
/**
- * Starts a new search stage, obtaining more results. Executes the query
- * asynchronously until a set number of hits are obtained, or a given
- * period is elapsed.
- *
- * If the query execution is currently in progress (i.e. a previous search
- * stage has not yet finished), this call will have no effect. If a previous
- * query execution stage has ended, this call will cause the search to
- * restart, accumulating more hits. If the search had finished, this call
- * will have no effect.
- *
- * @see #setMaxHits(int)
- * @see #setTimeout(int)
- * @see #isActive()
- * @see #isComplete()
- *
- * @throws IOException
- */
- public void getMoreHits() throws IOException;
-
- /**
- * Sets the maximum number of hits to be obtain in one search stage. If not
- * set, the {@link #DEFAULT_MAX_HITS default value} is used.
- * If the value provided is negative, then no limit is imposed on the number
- * of hits obtained.
- *
- * @param the maximum number of hits to be obtained by the next call to
- * {@link #getMoreHits()}.
- * @throws IOException if the communication with the query runner
- * implementation fails.
- */
- public void setStageMaxHits(int maxHits) throws IOException;
-
- /**
- * Sets the maximum amount of time to be used for one search stage. If not
- * set, the {@link #DEFAULT_TIMEOUT default value} is used. If the value
- * provided is negative, then no limit is imposed on the amount of time
spent.
- *
- * @param timeout the maximum amount of time (in milliseconds) to be used by
- * the next call to {@link #getMoreHits()}.
- * @throws IOException if the communication with the query runner
- * implementation fails.
- */
- public void setStageTimeout(int timeout) throws IOException;
-
- /**
- * Gets the number of hits obtained so far.
- * This number may increase at any time if the query is currently
- * {@link #isActive() active}.
- * @return an int value, representing the number of hits.
- */
- public int getHitsCount();
-
- /**
- * Gets the number of distinct documents found to contain hits so far.
- * This number may increase at any time if the query is currently
- * {@link #isActive() active}.
- * @return an int value, representing the number of distinct documents.
- */
- public int getDocumentsCount();
-
- /**
- * Gets the ID of a document found to contain hits.
- * @param index the index of the desired document in the list of documents.
+ * Gets the ID of a result document.
+ * @param rank the index of the desired document in the list of documents.
* This should be a value between 0 and {@link #getDocumentsCount()} -1.
*
+ * If the requested document position has not yet been ranked (i.e. we know
+ * there is a document at that position, but we don't yet know which one)
then
+ * the necessary ranking is performed before this method returns.
+ *
* @return an int value, representing the ID of the requested document.
* @throws IndexOutOfBoundsException is the index provided is less than
zero,
* or greater than {@link #getDocumentsCount()} -1.
+ * @throws IOException
*/
- public int getDocumentID(int index) throws IndexOutOfBoundsException;
-
+ public int getDocumentID(int rank) throws IndexOutOfBoundsException,
+ IOException;
+
/**
- * Gets the number of hits for one of the documents found to contain hits.
- * Note that for the <i>last</i> document this number is a lower bound -
there
- * may still be more hits to be found in this document (unless
- * {@link #isComplete()} returns true).
- *
- * @param index the index of the desired document in the list of documents.
+ * Retrieves the hits within a given result document.
+ * @param rank the index of the desired document in the list of documents.
* This should be a value between 0 and {@link #getDocumentsCount()} -1.
- *
- * @return an int value, representing the number of hits on the requested
- * document.
- * @throws IndexOutOfBoundsException is the index provided is less than
zero,
- * or greater than {@link #getDocumentsCount()} -1.
+ *
+ * This method call waits until the requested data is available before
+ * returning (document hits are being collected by a background thread).
+ *
+ * @return
+ * @throws IOException
+ * @throws IndexOutOfBoundsException
*/
- public int getDocumentHitsCount(int index) throws IndexOutOfBoundsException;
-
+ public List<Binding> getDocumentHits(int rank)
+ throws IndexOutOfBoundsException, IOException;
+
/**
- * Gets a subset of the hits obtained so far. If the set of hits requested
- * does not exist (e.g. if the startIndex is too large) then an empty
- * list will be returned.
+ * Gets a segment of the document text for a given document.
+ * @param rank the rank of the requested document.
+ * @param termPosition the first term requested.
+ * @param length the number of terms requested.
+ * @return two parallel String arrays, one containing term text, the other
+ * containing the spaces in between. The first term is results[0][0], the
+ * space following it is results[1][0], etc.
*
- * @param startIndex the index of the first requested hit.
- * @param hitCount the maximum number of hits to be returned (fewer hits
will
- * be returned if there aren't enough available).
- * @return a list of maximum hitCount hits.
- * @throws IndexOutOfBoundsException if startIndex is negative.
+ * @throws IndexException
+ * @throws IndexOutOfBoundsException
+ * @throws IOException
*/
- public List<Binding> getHits(int startIndex, int hitCount)
- throws IndexOutOfBoundsException;
-
+ public String[][] getDocumentText(int rank, int termPosition, int length)
+ throws IndexException, IndexOutOfBoundsException, IOException;
+
/**
- * Gets all the hits for a given document.
- * @param documentId the ID of the document for which the hits are being
- * requested.
- * @return a list of hits
+ * Obtains the URI for a given document.
+ * @param rank the rank for the requested document.
+ * @return the URI provided at indexing time for the document.
+ * @throws IndexException
* @throws IndexOutOfBoundsException
+ * @throws IOException
*/
- public List<Binding> getHitsForDocument(int documentId)
- throws IndexOutOfBoundsException;
-
+ public String getDocumentURI(int rank) throws IndexException,
+ IndexOutOfBoundsException, IOException;
+
/**
- * Render the content of the given document, with the hits for this query
- * highlighted.
- * @param documentId
- * @param out
- * @throws IOException if the output cannot be written to.
- * @throws IndexException if no document renderer is available.
+ * Obtains the title for a given document.
+ * @param rank the rank of the requested document.
+ * @return the document title (provided at indexing time).
+ * @throws IndexException
+ * @throws IndexOutOfBoundsException
+ * @throws IOException
*/
- public void renderDocument(int documentId, Appendable out) throws
IOException,
- IndexException;
-
-
+ public String getDocumentTitle(int rank) throws IndexException,
+ IndexOutOfBoundsException, IOException;
+
/**
- * Obtains the URI for a given document (specified by its ID).
- * @param documentID
- * @return
- * @throws IndexException if the document URI cannot be retrieved from the
- * index.
- */
- public String getDocumentURI(int documentID) throws IndexException;
-
- /**
- * Obtains the title for a given document (specified by its ID).
- * @param documentID
- * @return
- * @throws IndexException if the document title cannot be retrieved from the
- * index.
- */
- public String getDocumentTitle(int documentID) throws IndexException;
-
- /**
* Obtains an arbitrary document metadata field from the stored document
data.
* {@link DocumentMetadataHelper}s used at indexing time can add arbitrary
* {@link Serializable} values as metadata fields for the documents being
- * indexed. This method is used at search time to retrieve those values.
- *
- * @param docID the ID of document for which the metadata is sought.
- * @param fieldName the name of the metadata fields to be obtained
- * @return the de-serialised value stored at indexing time for the given
- * field name and document.
+ * indexed. This method is used at search time to retrieve those values.
+ *
+ * @param rank the rank for the requested document.
+ * @param fieldName the field name for which the value is sought.
+ * @return
* @throws IndexException
- */
- public Serializable getDocumentMetadataField(int docID, String fieldName)
- throws IndexException;
-
+ * @throws IndexOutOfBoundsException
+ * @throws IOException
+ */
+ public Serializable getDocumentMetadataField(int rank, String fieldName)
+ throws IndexException, IndexOutOfBoundsException, IOException;
+
/**
* Obtains a set of arbitrary document metadata fields from the stored
* document data.
* {@link DocumentMetadataHelper}s used at indexing time can add arbitrary
* {@link Serializable} values as metadata fields for the documents being
- * indexed. This method is used at search time to retrieve those values.
- *
- * @param docID the ID of document for which the metadata is sought.
- * @param fieldNames the names of the metadata fields to be obtained
- * @return the de-serialised values stored at indexing time for the given
- * field names and document (as a Map from field name to filed value).
+ * indexed. This method is used at search time to retrieve those values.
+ *
+ * @param rank the rank for the requested document.
+ * @param fieldNames the names of the metadata fields for which the values
are
+ * requested.
+ * @return a {@link Map} linking field names with their values.
* @throws IndexException
- */
- public Map<String, Serializable> getDocumentMetadataFields(int docID,
- Set<String> fieldNames) throws IndexException;
-
- /**
- * Gets a segment of the document text for a given document.
- * @param documentID
- * @param startToken
- * @param length
- * @return
- * @throws IndexException if the document text cannot be retrieved from the
- * index.
+ * @throws IndexOutOfBoundsException
+ * @throws IOException
*/
- public String[][] getDocumentText(int documentID, int termPosition,
- int length) throws IndexException;
-
+ public Map<String, Serializable> getDocumentMetadataFields(int rank,
+ Set<String> fieldNames) throws IndexException,
+ IndexOutOfBoundsException, IOException;
+
/**
- * Checks whether a search stage is currently active.
- * @return <code>true</code> iff more hits are currently being sought (a
- * search stage has started and not finished yet)
+ * Render the content of the given document, with the hits for this query
+ * highlighted.
+ *
+ * @param rank the rank for the requested document.
+ * @param out an {@link Appendable} to which the output is written.
+ * @throws IOException
+ * @throws IndexException
*/
- public boolean isActive();
-
+ public void renderDocument(int rank, Appendable out) throws IOException,
+ IndexException;
+
/**
- * Checks whether all the available hits have been obtained. When this
returns
- * <code>true</code>, further calls to {@link #getMoreHits()} will have no
- * effect.
- * @return <code>true</code> after all the possible hits have been obtained.
- */
- public boolean isComplete();
-
- /**
* Closes this {@link QueryExecutor} and releases all resources used.
- * @throws IOException if the index files cannot be accessed.
+ * @throws IOException
*/
public void close() throws IOException;
-}
+}
\ No newline at end of file
Modified: mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunnerImpl.java
===================================================================
--- mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunnerImpl.java
2011-11-22 13:54:51 UTC (rev 14588)
+++ mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunnerImpl.java
2011-11-22 17:57:48 UTC (rev 14589)
@@ -41,7 +41,7 @@
* @author valyt
*
*/
-public class QueryRunnerImpl implements QueryRunner {
+public class QueryRunnerImpl implements QueryRunnerMk1 {
private class SearchStageRunner implements Runnable{
Copied: mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunnerMk1.java (from
rev 14588, mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunner.java)
===================================================================
--- mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunnerMk1.java
(rev 0)
+++ mimir/trunk/mimir-core/src/gate/mimir/search/QueryRunnerMk1.java
2011-11-22 17:57:48 UTC (rev 14589)
@@ -0,0 +1,265 @@
+/*
+ * QueryRunner.java
+ *
+ * Copyright (c) 2007-2011, The University of Sheffield.
+ *
+ * This file is part of GATE MÃmir (see http://gate.ac.uk/family/mimir.html),
+ * and is free software, licenced under the GNU Lesser General Public License,
+ * Version 3, June 2007 (also included with this distribution as file
+ * LICENCE-LGPL3.html).
+ *
+ * Valentin tablan, 16 Dec 2009
+ *
+ * $Id$
+ */
+package gate.mimir.search;
+
+import gate.mimir.DocumentMetadataHelper;
+import gate.mimir.index.IndexException;
+import gate.mimir.search.query.Binding;
+import gate.mimir.search.query.QueryExecutor;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A QueryRunner object can be used to execute a query in a separate thread.
The
+ * query execution will be performed in stages, each being limited to a given
+ * number of maximum hits or a set timeout. During the query execution
+ * statistics are made available about the number of hits currently obtained
for
+ * each document. The hits already collected can be accessed in a random
+ * fashion.
+ *
+ * N.B. Documents are referred to in two different manners:
+ * <ul>
+ * <li>by documentId: the ID associated with the document at indexing time,
+ * which never changes</li>
+ * <li>by index: the index in the list of documents found to contain
hits.</li>
+ * </ul>
+ * You can tell which addressing scheme is used based on the of the parameter.
+ *
+ * Implementations of this interface must be thread-safe!
+ */
+public interface QueryRunnerMk1 {
+
+ /**
+ * The default number of hits obtained in one search stage.
+ */
+ public static final int DEFAULT_MAX_HITS = 1000000;
+
+
+ /**
+ * The default maximum amount of time (in milliseconds) used for one search
+ * stage.
+ */
+ public static final int DEFAULT_TIMEOUT = 30000;
+
+ /**
+ * Starts a new search stage, obtaining more results. Executes the query
+ * asynchronously until a set number of hits are obtained, or a given
+ * period is elapsed.
+ *
+ * If the query execution is currently in progress (i.e. a previous search
+ * stage has not yet finished), this call will have no effect. If a previous
+ * query execution stage has ended, this call will cause the search to
+ * restart, accumulating more hits. If the search had finished, this call
+ * will have no effect.
+ *
+ * @see #setMaxHits(int)
+ * @see #setTimeout(int)
+ * @see #isActive()
+ * @see #isComplete()
+ *
+ * @throws IOException
+ */
+ public void getMoreHits() throws IOException;
+
+ /**
+ * Sets the maximum number of hits to be obtain in one search stage. If not
+ * set, the {@link #DEFAULT_MAX_HITS default value} is used.
+ * If the value provided is negative, then no limit is imposed on the number
+ * of hits obtained.
+ *
+ * @param the maximum number of hits to be obtained by the next call to
+ * {@link #getMoreHits()}.
+ * @throws IOException if the communication with the query runner
+ * implementation fails.
+ */
+ public void setStageMaxHits(int maxHits) throws IOException;
+
+ /**
+ * Sets the maximum amount of time to be used for one search stage. If not
+ * set, the {@link #DEFAULT_TIMEOUT default value} is used. If the value
+ * provided is negative, then no limit is imposed on the amount of time
spent.
+ *
+ * @param timeout the maximum amount of time (in milliseconds) to be used by
+ * the next call to {@link #getMoreHits()}.
+ * @throws IOException if the communication with the query runner
+ * implementation fails.
+ */
+ public void setStageTimeout(int timeout) throws IOException;
+
+ /**
+ * Gets the number of hits obtained so far.
+ * This number may increase at any time if the query is currently
+ * {@link #isActive() active}.
+ * @return an int value, representing the number of hits.
+ */
+ public int getHitsCount();
+
+ /**
+ * Gets the number of distinct documents found to contain hits so far.
+ * This number may increase at any time if the query is currently
+ * {@link #isActive() active}.
+ * @return an int value, representing the number of distinct documents.
+ */
+ public int getDocumentsCount();
+
+ /**
+ * Gets the ID of a document found to contain hits.
+ * @param index the index of the desired document in the list of documents.
+ * This should be a value between 0 and {@link #getDocumentsCount()} -1.
+ *
+ * @return an int value, representing the ID of the requested document.
+ * @throws IndexOutOfBoundsException is the index provided is less than
zero,
+ * or greater than {@link #getDocumentsCount()} -1.
+ */
+ public int getDocumentID(int index) throws IndexOutOfBoundsException;
+
+ /**
+ * Gets the number of hits for one of the documents found to contain hits.
+ * Note that for the <i>last</i> document this number is a lower bound -
there
+ * may still be more hits to be found in this document (unless
+ * {@link #isComplete()} returns true).
+ *
+ * @param index the index of the desired document in the list of documents.
+ * This should be a value between 0 and {@link #getDocumentsCount()} -1.
+ *
+ * @return an int value, representing the number of hits on the requested
+ * document.
+ * @throws IndexOutOfBoundsException is the index provided is less than
zero,
+ * or greater than {@link #getDocumentsCount()} -1.
+ */
+ public int getDocumentHitsCount(int index) throws IndexOutOfBoundsException;
+
+ /**
+ * Gets a subset of the hits obtained so far. If the set of hits requested
+ * does not exist (e.g. if the startIndex is too large) then an empty
+ * list will be returned.
+ *
+ * @param startIndex the index of the first requested hit.
+ * @param hitCount the maximum number of hits to be returned (fewer hits
will
+ * be returned if there aren't enough available).
+ * @return a list of maximum hitCount hits.
+ * @throws IndexOutOfBoundsException if startIndex is negative.
+ */
+ public List<Binding> getHits(int startIndex, int hitCount)
+ throws IndexOutOfBoundsException;
+
+ /**
+ * Gets all the hits for a given document.
+ * @param documentId the ID of the document for which the hits are being
+ * requested.
+ * @return a list of hits
+ * @throws IndexOutOfBoundsException
+ */
+ public List<Binding> getHitsForDocument(int documentId)
+ throws IndexOutOfBoundsException;
+
+ /**
+ * Render the content of the given document, with the hits for this query
+ * highlighted.
+ * @param documentId
+ * @param out
+ * @throws IOException if the output cannot be written to.
+ * @throws IndexException if no document renderer is available.
+ */
+ public void renderDocument(int documentId, Appendable out) throws
IOException,
+ IndexException;
+
+
+ /**
+ * Obtains the URI for a given document (specified by its ID).
+ * @param documentID
+ * @return
+ * @throws IndexException if the document URI cannot be retrieved from the
+ * index.
+ */
+ public String getDocumentURI(int documentID) throws IndexException;
+
+ /**
+ * Obtains the title for a given document (specified by its ID).
+ * @param documentID
+ * @return
+ * @throws IndexException if the document title cannot be retrieved from the
+ * index.
+ */
+ public String getDocumentTitle(int documentID) throws IndexException;
+
+ /**
+ * Obtains an arbitrary document metadata field from the stored document
data.
+ * {@link DocumentMetadataHelper}s used at indexing time can add arbitrary
+ * {@link Serializable} values as metadata fields for the documents being
+ * indexed. This method is used at search time to retrieve those values.
+ *
+ * @param docID the ID of document for which the metadata is sought.
+ * @param fieldName the name of the metadata fields to be obtained
+ * @return the de-serialised value stored at indexing time for the given
+ * field name and document.
+ * @throws IndexException
+ */
+ public Serializable getDocumentMetadataField(int docID, String fieldName)
+ throws IndexException;
+
+ /**
+ * Obtains a set of arbitrary document metadata fields from the stored
+ * document data.
+ * {@link DocumentMetadataHelper}s used at indexing time can add arbitrary
+ * {@link Serializable} values as metadata fields for the documents being
+ * indexed. This method is used at search time to retrieve those values.
+ *
+ * @param docID the ID of document for which the metadata is sought.
+ * @param fieldNames the names of the metadata fields to be obtained
+ * @return the de-serialised values stored at indexing time for the given
+ * field names and document (as a Map from field name to filed value).
+ * @throws IndexException
+ */
+ public Map<String, Serializable> getDocumentMetadataFields(int docID,
+ Set<String> fieldNames) throws IndexException;
+
+ /**
+ * Gets a segment of the document text for a given document.
+ * @param documentID
+ * @param startToken
+ * @param length
+ * @return
+ * @throws IndexException if the document text cannot be retrieved from the
+ * index.
+ */
+ public String[][] getDocumentText(int documentID, int termPosition,
+ int length) throws IndexException;
+
+ /**
+ * Checks whether a search stage is currently active.
+ * @return <code>true</code> iff more hits are currently being sought (a
+ * search stage has started and not finished yet)
+ */
+ public boolean isActive();
+
+ /**
+ * Checks whether all the available hits have been obtained. When this
returns
+ * <code>true</code>, further calls to {@link #getMoreHits()} will have no
+ * effect.
+ * @return <code>true</code> after all the possible hits have been obtained.
+ */
+ public boolean isComplete();
+
+ /**
+ * Closes this {@link QueryExecutor} and releases all resources used.
+ * @throws IOException if the index files cannot be accessed.
+ */
+ public void close() throws IOException;
+}
Modified:
mimir/trunk/mimir-core/src/gate/mimir/search/RankingQueryRunnerImpl.java
===================================================================
--- mimir/trunk/mimir-core/src/gate/mimir/search/RankingQueryRunnerImpl.java
2011-11-22 13:54:51 UTC (rev 14588)
+++ mimir/trunk/mimir-core/src/gate/mimir/search/RankingQueryRunnerImpl.java
2011-11-22 17:57:48 UTC (rev 14589)
@@ -15,6 +15,8 @@
*/
package gate.mimir.search;
+import gate.mimir.DocumentMetadataHelper;
+import gate.mimir.index.IndexException;
import gate.mimir.search.query.Binding;
import gate.mimir.search.query.QueryExecutor;
import gate.mimir.search.query.QueryNode;
@@ -27,9 +29,13 @@
import it.unimi.dsi.fastutil.objects.ObjectList;
import java.io.IOException;
+import java.io.Serializable;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.SortedMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
@@ -43,21 +49,32 @@
* A QueryRunner implementation that can perform ranking.
* This query runner has two modes of functioning: ranking and non-ranking,
* depending on whether a {@link MimirScorer} is provided during construction
- * or not.
+ * or not.
+ * All documents are referred to using their rank (i.e. position in the list
of
+ * results). When working in non-ranking mode, ranking order is the same as
+ * document ID order.
*/
-public class RankingQueryRunnerImpl {
+public class RankingQueryRunnerImpl implements QueryRunner {
- private static final Runnable NO_MORE_JOBS = new Runnable(){
+
+ /**
+ * Constant used as a flag to mark then of a list of tasks.
+ */
+ private static final Runnable NO_MORE_TASKS = new Runnable(){
public void run() {}
};
+ /**
+ * The background thread implementation: simply collects {@link Runnable}s
+ * from the {@link RankingQueryRunnerImpl#backgroundTasks} queue and runs
them.
+ */
protected class BackgroundRunner implements Runnable {
@Override
public void run() {
try {
while(true) {
Runnable job = backgroundTasks.take();
- if(job == NO_MORE_JOBS) break;
+ if(job == NO_MORE_TASKS) break;
else job.run();
}
} catch(InterruptedException e) {
@@ -107,7 +124,7 @@
// we need to 'scroll back' the executor: get a new executor
QueryExecutor oldExecutor = queryExecutor;
queryExecutor = queryExecutor.getQueryNode().getQueryExecutor(
- queryExecutor.getQueryEngine());
+ queryEngine);
oldExecutor.close();
}
for(int i = start; i < end; i++) {
@@ -217,7 +234,10 @@
}
}
- protected Logger logger = Logger.getLogger(RankingQueryRunnerImpl.class);
+ /**
+ * Shared logger instance.
+ */
+ protected static Logger logger =
Logger.getLogger(RankingQueryRunnerImpl.class);
/**
* The {@link QueryExecutor} for the query being run.
@@ -225,6 +245,11 @@
protected QueryExecutor queryExecutor;
/**
+ * The QueryEngine we run inside.
+ */
+ protected QueryEngine queryEngine;
+
+ /**
* The {@link MimirScorer} to be used for ranking documents.
*/
protected MimirScorer scorer;
@@ -277,6 +302,9 @@
*/
protected BlockingQueue<Runnable> backgroundTasks;
+ /**
+ * Flag used to mark that all results documents have been counted.
+ */
protected volatile boolean allDocIdsCollected = false;
/**
@@ -289,7 +317,8 @@
public RankingQueryRunnerImpl(QueryExecutor executor, MimirScorer scorer)
throws IOException {
this.queryExecutor = executor;
this.scorer = scorer;
- docBlockSize = queryExecutor.getQueryEngine().getRankingDocCount();
+ queryEngine = queryExecutor.getQueryEngine();
+ docBlockSize = queryEngine.getRankingDocCount();
documentIds = new IntArrayList();
documentHits = new ObjectArrayList<List<Binding>>();
if(scorer != null) {
@@ -305,9 +334,9 @@
backgroundTasks = new LinkedBlockingQueue<Runnable>();
Runnable backgroundRunner = new BackgroundRunner();
//get a thread from the executor, if one exists
- if(queryExecutor.getQueryEngine().getExecutor() != null){
+ if(queryEngine.getExecutor() != null){
try {
- queryExecutor.getQueryEngine().getExecutor().execute(backgroundRunner);
+ queryEngine.getExecutor().execute(backgroundRunner);
} catch(RejectedExecutionException e) {
logger.warn("Could not allocate a new background thread", e);
throw new RejectedExecutionException(
@@ -328,56 +357,35 @@
}
}
- /**
- * Gets the number of result documents. If the search has not yet completed,
- * then -1 is returned.
- * @return
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getDocumentsCount()
*/
+ @Override
public int getDocumentsCount() {
if(allDocIdsCollected) return documentIds.size();
else return -1;
}
- /**
- * Gets the number of documents found to contain hits so far. After the
search
- * completes, the result returned by this call is identical to that of
- * {@link #getDocumentsCount()}.
- * @return
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getCurrentDocumentsCount()
*/
+ @Override
public int getCurrentDocumentsCount() {
return documentIds.size();
}
- /**
- * Gets the ID of a result document.
- * @param rank the index of the desired document in the list of documents.
- * This should be a value between 0 and {@link #getDocumentsCount()} -1.
- *
- * If the requested document position has not yet been ranked (i.e. we know
- * there is a document at that position, but we don't yet know which one)
then
- * the necessary ranking is performed before this method returns.
- *
- * @return an int value, representing the ID of the requested document.
- * @throws IndexOutOfBoundsException is the index provided is less than
zero,
- * or greater than {@link #getDocumentsCount()} -1.
- * @throws IOException
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getDocumentID(int)
*/
+ @Override
public int getDocumentID(int rank) throws IndexOutOfBoundsException,
IOException {
return documentIds.getInt(getDocumentIndex(rank));
}
- /**
- * Retrieves the hits withing a given result document.
- * @param rank the index of the desired document in the list of documents.
- * This should be a value between 0 and {@link #getDocumentsCount()} -1.
- *
- * This method call waits until the requested data is available before
- * returning (document hits are being collected by a background thread).
- *
- * @return
- * @throws IOException
- * @throws IndexOutOfBoundsException
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getDocumentHits(int)
*/
+ @Override
public List<Binding> getDocumentHits(int rank) throws
IndexOutOfBoundsException, IOException {
int documentIndex = getDocumentIndex(rank);
List<Binding> hits = documentHits.get(documentIndex);
@@ -442,8 +450,7 @@
int rankRangeEnd = index;
if((rankRangeEnd - rankRangeStart) < (docBlockSize -1)) {
// extend the size of the chunk of documents to be ranked
- rankRangeEnd = rankRangeStart +
- queryExecutor.getQueryEngine().getRankingDocCount();
+ rankRangeEnd = rankRangeStart + docBlockSize;
}
// the document with the minimum score already ranked.
int smallestOldScoreDocId = rankRangeStart > 0 ?
@@ -520,7 +527,8 @@
else if (midVal < documentScore) end = mid - 1;
else {
// we found a doc with exactly the same score: scan to the right
- while(documentScores.getDouble(documentsOrder.getInt(mid)) ==
+ while(documentsOrder.size() < mid &&
+ documentScores.getDouble(documentsOrder.getInt(mid)) ==
documentScore){
mid++;
}
@@ -574,12 +582,79 @@
}
}
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getDocumentText(int, int, int)
+ */
+ @Override
+ public String[][] getDocumentText(int rank, int termPosition, int length)
+ throws IndexException, IndexOutOfBoundsException, IOException {
+ return queryEngine.getText(getDocumentID(rank), termPosition, length);
+ }
+
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getDocumentURI(int)
+ */
+ @Override
+ public String getDocumentURI(int rank) throws IndexException,
+ IndexOutOfBoundsException, IOException {
+ return queryEngine.getDocumentURI(getDocumentID(rank));
+ }
+
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getDocumentTitle(int)
+ */
+ @Override
+ public String getDocumentTitle(int rank) throws IndexException,
+ IndexOutOfBoundsException, IOException {
+ return queryEngine.getDocumentTitle(getDocumentID(rank));
+ }
+
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getDocumentMetadataField(int,
java.lang.String)
+ */
+ @Override
+ public Serializable getDocumentMetadataField(int rank, String fieldName)
+ throws IndexException, IndexOutOfBoundsException, IOException {
+ return queryEngine.getDocumentMetadataField(getDocumentID(rank),
fieldName);
+ }
+
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#getDocumentMetadataFields(int,
java.util.Set)
+ */
+ @Override
+ public Map<String, Serializable> getDocumentMetadataFields(int rank,
+ Set<String> fieldNames) throws IndexException,
IndexOutOfBoundsException,
+ IOException {
+ Map<String, Serializable> res = new HashMap<String, Serializable>();
+ int docId = getDocumentID(rank);
+ for(String fieldName : fieldNames) {
+ Serializable value = getDocumentMetadataField(docId, fieldName);
+ if(value != null) res.put(fieldName, value);
+ }
+ return res;
+ }
+
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#renderDocument(int,
java.lang.Appendable)
+ */
+ @Override
+ public void renderDocument(int rank, Appendable out) throws IOException,
+ IndexException {
+ queryEngine.renderDocument(getDocumentID(rank),
+ getDocumentHits(rank), out);
+ }
+
+ /* (non-Javadoc)
+ * @see gate.mimir.search.QueryRunner#close()
+ */
+ @Override
public void close() throws IOException {
- // TODO give back the borrowed thread
queryExecutor.close();
scorer = null;
try {
- backgroundTasks.put(NO_MORE_JOBS);
+ // stop the background tasks runnable,
+ // which will return the thread to the pool
+ backgroundTasks.put(NO_MORE_TASKS);
} catch(InterruptedException e) {
// ignore
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure
contains a definitive record of customers, application performance,
security threats, fraudulent activity, and more. Splunk takes this
data and makes sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-novd2d
_______________________________________________
GATE-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gate-cvs