Revision: 14560
          http://gate.svn.sourceforge.net/gate/?rev=14560&view=rev
Author:   valyt
Date:     2011-11-17 10:07:57 +0000 (Thu, 17 Nov 2011)
Log Message:
-----------
Possible solution for doing ranked and non-ranked query running sharing the 
same code.

Modified Paths:
--------------
    mimir/trunk/mimir-core/src/gate/mimir/search/QueryEngine.java
    mimir/trunk/mimir-core/src/gate/mimir/search/RankingQueryRunnerImpl.java

Modified: mimir/trunk/mimir-core/src/gate/mimir/search/QueryEngine.java
===================================================================
--- mimir/trunk/mimir-core/src/gate/mimir/search/QueryEngine.java       
2011-11-17 02:18:02 UTC (rev 14559)
+++ mimir/trunk/mimir-core/src/gate/mimir/search/QueryEngine.java       
2011-11-17 10:07:57 UTC (rev 14560)
@@ -173,9 +173,9 @@
   protected Executor executor;
 
   /**
-   * How many documents get ranked in the first instance.
+   * How many documents get ranked in one ranking stage.
    */
-  private int rankedDocumentsCount = 1000;
+  private int rankingDocCount = 1000;
   
   /**
    * A list of currently active QueryRunners. This is used to close all active 
@@ -213,16 +213,22 @@
 
   /**
    * Gets the configuration parameter specifying the number of documents that 
-   * get ranked in the first instance. This is used to optimise the search 
-   * process by limiting the nuber of results that get calculated by default.
+   * get ranked in one ranking stage. This is used to optimise the search 
+   * process by limiting the number of results that get calculated by default.
    * @return
    */
-  public int getRankedDocumentsCount() {
-    return rankedDocumentsCount;
+  public int getRankingDocCount() {
+    return rankingDocCount;
   }
 
-  public void setRankedDocumentsCount(int rankedDocumentsCount) {
-    this.rankedDocumentsCount = rankedDocumentsCount;
+  /**
+   * Sets the configuration parameter specifying the number of documents that 
+   * get ranked in one ranking stage. This is used to optimise the search 
+   * process by limiting the number of results that get calculated by default.
+   * @param rankingDocCount
+   */
+  public void setRankingDocCount(int rankingDocCount) {
+    this.rankingDocCount = rankingDocCount;
   }
 
   /**

Modified: 
mimir/trunk/mimir-core/src/gate/mimir/search/RankingQueryRunnerImpl.java
===================================================================
--- mimir/trunk/mimir-core/src/gate/mimir/search/RankingQueryRunnerImpl.java    
2011-11-17 02:18:02 UTC (rev 14559)
+++ mimir/trunk/mimir-core/src/gate/mimir/search/RankingQueryRunnerImpl.java    
2011-11-17 10:07:57 UTC (rev 14560)
@@ -24,8 +24,11 @@
 import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
 import it.unimi.dsi.fastutil.doubles.DoubleList;
 import it.unimi.dsi.fastutil.ints.Int2IntFunction;
+import it.unimi.dsi.fastutil.ints.IntAVLTreeSet;
 import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntIterator;
 import it.unimi.dsi.fastutil.ints.IntList;
+import it.unimi.dsi.fastutil.ints.IntSortedSet;
 import it.unimi.dsi.fastutil.objects.ObjectArrayList;
 import it.unimi.dsi.fastutil.objects.ObjectList;
 
@@ -42,20 +45,90 @@
  */
 public class RankingQueryRunnerImpl implements QueryRunner, Runnable {
   
+  /**
+   * When doing ranking, this class is used to delegate the iteration of 
+   * document IDs to an IntIterator that is limited to a finite set of 
documents
+   * that have just been ranked. When that iterator is emptied, the 
+   * {@link RankingQueryRunnerImpl#documentsById} field is nullified before 
+   * hasNext() returns false, to indicate that more documents may be available.
+   */
+  protected class RankedDocIdIterator implements IntIterator {
+    
+    public RankedDocIdIterator(IntIterator underlyingIterator) {
+      this.underlyingIterator = underlyingIterator;
+    }
+
+    protected IntIterator underlyingIterator;
+
+    public boolean hasNext() {
+      return underlyingIterator.hasNext();
+    }
+
+    public Integer next() {
+      return underlyingIterator.next();
+    }
+
+    public void remove() {
+      underlyingIterator.remove();
+    }
+
+    public int nextInt() {
+      return underlyingIterator.nextInt();
+    }
+
+    public int skip(int n) {
+      return underlyingIterator.skip(n);
+    }
+    
+  }
+  
   protected Logger logger =  Logger.getLogger(RankingQueryRunnerImpl.class);
   
+  /**
+   * The {@link QueryExecutor} for the query being run.
+   */
   protected QueryExecutor queryExecutor;
   
+  /**
+   * The {@link MimirScorer} to be used for ranking documents.
+   */
   protected MimirScorer scorer;
 
+  /**
+   * The document IDs for the documents found to contain hits. This list is
+   * sorted in ascending documentID order.
+   */
   protected IntList documentIds;
   
+  /**
+   * If scoring is enabled ({@link #scorer} is not <code>null</code>), this 
list
+   * contains the scores for the documents found to contain hits. This list is 
+   * aligned to {@link #documentIds}.   
+   */
   protected DoubleList documentScores;
   
+  /**
+   * The sets of hits for each returned document. This data structure is 
lazily 
+   * built, so some elements may be null. 
+   */
   protected ObjectList<Binding[]> documentHits;
 
-  protected IntList documentsByRank;
+  /**
+   * The order the documents should be returned in (elements in this list are 
+   * indexes in {@link #documentIds}).
+   */
+  protected IntList documentsOrder;
   
+  /**
+   * An iterator supplying documentIDs in ascending order. These are used when 
+   * collecting the hits.
+   */
+  protected IntIterator documentsById;
+  
+  /**
+   * The thread used for executing the query. This is a separate thread from 
one 
+   * that created the query runner.
+   */
   protected Thread runningThread;
   
   /**
@@ -68,6 +141,7 @@
   public RankingQueryRunnerImpl(QueryExecutor executor, MimirScorer scorer) 
throws IOException {
     this.queryExecutor = executor;
     this.scorer = scorer;
+    documentsById = null;
     // start the search
     getMoreHits();
   }
@@ -246,6 +320,103 @@
     // TODO Auto-generated method stub
   }
   
+  
+  /**
+   * Creates an {@link IntIterator} used for enumerating the documents in the
+   * correct order for returning to the user.
+   * If no more documents are available, this should return null
+   * @return
+   * @throws IOException 
+   */
+  protected IntIterator getDocumentIterator() throws IOException {
+    if(scorer != null) {
+      // we're doing ranking
+      if(documentIds == null) {
+        // first stage: collect all documents and their scores
+        documentIds = new IntArrayList();
+        documentScores = new DoubleArrayList();
+        documentHits = new ObjectArrayList<Binding[]>();
+        documentsOrder = new IntArrayList(
+          queryExecutor.getQueryEngine().getRankingDocCount());
+        
+        scorer.wrap(queryExecutor);
+        int docId = scorer.nextDocument(-1);
+        while(docId >= 0) {
+          documentIds.add(docId);
+          documentScores.add(scorer.score());
+          documentHits.add(null);
+          docId = scorer.nextDocument(-1);
+        }
+      }
+      // collect some more ranked documents
+      
+      int rankRangeStart = documentsOrder.size();
+      int rankRangeEnd = documentsOrder.size() + 
+          queryExecutor.getQueryEngine().getRankingDocCount();
+      int docsByRankWriteIndex = rankRangeStart;
+      
+      // the document with the minimum score already ranked.
+      int smallestOldScoreDocId = rankRangeStart > 0 ? 
+        documentIds.getInt(documentsOrder.getInt(rankRangeStart -1))
+        : -1;
+      // the score for the document above, which is a the upper limit for new 
scores
+      double smallestOldScore = rankRangeStart > 0 ? 
+          documentScores.getDouble(documentsOrder.getInt(rankRangeStart -1))
+          : -1;
+      // the documentIds for newly ranked documents
+      IntSortedSet newDocuments = new IntAVLTreeSet();
+      // now collect some more documents
+      for(int i = 0; i < documentIds.size(); i++) {
+        int documentId = documentIds.getInt(i);
+        double documentScore = documentScores.getDouble(i);
+        // the index for the document with the smallest score, 
+        // from the new ones being ranked 
+        int smallestDocIndex = rankRangeStart < documentsOrder.size() ?
+            documentsOrder.getInt(rankRangeStart) : -1;
+        // the smallest score that's been seen in this new round 
+        double smallestNewScore = smallestDocIndex == -1 ? 0.0 : 
+            documentScores.getDouble(smallestDocIndex);
+        // we care about this new document if:
+        // - we haven't collected enough documents yet, or
+        // - it has a better score than the smallest score so far, but a 
+        // smaller score than the maximum permitted score (i.e. it has not 
+        // already been ranked)., or
+        // - it's a new document with the same score as the largest permitted 
score
+        if(docsByRankWriteIndex < rankRangeEnd 
+           || 
+           (documentScore > smallestNewScore && 
+               (smallestOldScore < 0 || documentScore < smallestOldScore)) 
+           ||
+           documentScore == smallestOldScore && documentId != 
smallestOldScoreDocId) {
+          if(docsByRankWriteIndex == rankRangeEnd) {
+            // we need to remove the  newly ranked document 
+            // with the smallest score
+            docsByRankWriteIndex--;
+            int oldDocIndex = documentsOrder.removeInt(docsByRankWriteIndex);
+            newDocuments.remove(documentIds.getInt(oldDocIndex));
+          }
+          // find the rank for the new doc
+          int rank = rankRangeStart;
+          while(rank < documentsOrder.size() && 
+                documentScore < 
documentScores.getDouble(documentsOrder.getInt(rank))){
+            rank++;
+          }
+          documentsOrder.add(rank, i);
+          newDocuments.add(documentId);
+          docsByRankWriteIndex++;
+        }
+      }
+      if(newDocuments.isEmpty()){
+        return null;
+      } else {
+        return new RankedDocIdIterator(newDocuments.iterator());
+      }
+    } else {
+      // we're not doing scoring, simply use the queryExecutor as an 
intIterator
+      return queryExecutor;
+    }
+  }
+  
   public void run() {
     //store the running thread
     synchronized(this) {
@@ -256,85 +427,12 @@
       runningThread = Thread.currentThread();  
     }
     try {
-      if(scorer != null) {
-        // we're doing ranking
-        if(documentIds == null) {
-          // first stage: collect all documents and their scores
-          documentIds = new IntArrayList();
-          documentScores = new DoubleArrayList();
-          documentHits = new ObjectArrayList<Binding[]>();
-          documentsByRank = new IntArrayList(
-            queryExecutor.getQueryEngine().getRankedDocumentsCount());
-          
-          scorer.wrap(queryExecutor);
-          int docId = scorer.nextDocument(-1);
-          while(docId >= 0) {
-            documentIds.add(docId);
-            documentScores.add(scorer.score());
-            docId = scorer.nextDocument(-1);
-          }
-        }
-        // collect some more ranked documents
-        int rankRangeStart = documentsByRank.size();
-        int rankRangeEnd = documentsByRank.size() + 
-            queryExecutor.getQueryEngine().getRankedDocumentsCount();
-        int docsByRankWriteIndex = rankRangeStart;
+      if(documentsById == null) {
+        documentsById = getDocumentIterator();
+      }
+      // collect the hits
+      while(documentsById != null) {
         
-        // the document with the minimum score already ranked.
-        int smallestOldScoreDocId = rankRangeStart > 0 ? 
-          documentIds.getInt(documentsByRank.getInt(rankRangeStart -1))
-          : -1;
-        // the score for the document above, which is a the upper limit for 
new scores
-        double smallestOldScore = rankRangeStart > 0 ? 
-            documentScores.getDouble(documentsByRank.getInt(rankRangeStart -1))
-            : -1;
-        for(int i = 0; i < documentIds.size(); i++) {
-          int documentId = documentIds.getInt(i);
-          double documentScore = documentScores.getDouble(i);
-          // XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx
-          // !!! Note that the documentsByRank is sorted in DESCENDING order 
now
-          
-          // the index for the document with the smallest score, 
-          // from the new ones being ranked 
-          int smallestDocIndex = rankRangeStart < documentsByRank.size() ?
-              documentsByRank.getInt(rankRangeStart) : -1;
-          // the smallest score that's been seen in this new round 
-          double smallestNewScore = smallestDocIndex == -1 ? 0.0 : 
-              documentScores.getDouble(smallestDocIndex);
-          // we care about this new document if:
-          // - we haven't collected enough documents yet, or
-          // - it has a better score than the smallest score so far, but a 
-          // smaller score than the maximum permitted score (i.e. it has not 
-          // already been ranked)., or
-          // - it's a new document with the same score as the largest 
permitted score
-          if(docsByRankWriteIndex < rankRangeEnd 
-             || 
-             (documentScore > smallestNewScore && 
-                 (smallestOldScore < 0 || documentScore < smallestOldScore)) 
-             ||
-             documentScore == smallestOldScore && documentId != 
smallestOldScoreDocId) {
-            if(docsByRankWriteIndex == rankRangeEnd) {
-              // we need to remove the  newly ranked document 
-              // with the smallest score
-              docsByRankWriteIndex--;
-              documentsByRank.removeInt(docsByRankWriteIndex);
-            }
-            
-            // find the rank for the new doc
-            int rank = rankRangeStart;
-            while(rank < documentsByRank.size() && 
-                  documentScore < 
documentScores.getDouble(documentsByRank.getInt(rank))){
-              rank++;
-            }
-            documentsByRank.add(rank, i);
-            docsByRankWriteIndex++;
-            // XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx
-          }
-          // collect the hits for the newly ranked docs
-        }
-        
-      } else {
-        // TODO: non-ranking mode implementation
       }
     } catch(IOException e) {
       //something went bad!

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

Reply via email to