2013-03-22 17 views
2

有人可以幫助我找到一種方法來處理Lucene中抽象收集器類的自定義實現嗎?Lucene索引自定義收集器的工作方式

我已經實現了一些測試文本查詢索引的方法有兩種:

1.Total命中被eq至2兩個文件名相同,因此導致大小EQ爲1,因爲我讓他們在一套。

TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE); 
LOG.info("Total hits " + topDocs.totalHits); 
ScoreDoc[] scoreDosArray = topDocs.scoreDocs; 
for (ScoreDoc scoreDoc : scoreDosArray) { 
    Document doc = searcher.doc(scoreDoc.doc); 
    String fileName = doc.get(FILENAME_FIELD); 
    results.add(fileName); 
} 

2.CountCollect是EQ 2。從我得到的文件名中收集的收集方法,這兩個文件都是獨一無二的,因此最終結果大小也情商爲2 CountNextReader變量在的結束邏輯是eq至10

private Set<String> doStreamingSearch(final IndexSearcher searcher, Query query) throws IOException { 
    final Set<String> results = new HashSet<String>(); 
    Collector collector = new Collector() { 
     private int base; 
     private Scorer scorer; 
     private int countCollect; 
     private int countNextReader; 

     @Override 
     public void collect(int doc) throws IOException { 
      Document document = searcher.doc(doc); 
      String filename = document.get(FILENAME_FIELD); 
      results.add(filename); 
      countCollect++; 
     } 

     @Override 
     public boolean acceptsDocsOutOfOrder() { 
      return true; 
     } 

     @Override 
     public void setScorer(Scorer scorer) throws IOException { 
      this.scorer = scorer; 
     } 

     @Override 
     public void setNextReader(AtomicReaderContext ctx) throws IOException { 
      this.base = ctx.docBase; 
      countNextReader++; 
     } 

     @Override 
     public String toString() { 
      LOG.info("CountCollect: " + countCollect); 
      LOG.info("CountNextReader: " + countNextReader); 
      return null; 
     } 
    }; 
    searcher.search(query, collector); 
    collector.toString(); 
    return results; 
} 

我不明白的收集方法中,爲什麼我在以前的實現比較得到不同的文件和不同的文件名?我希望得到相同的結果,或?

回答

7

Collector#collect方法是搜索請求的熱點。它要求與查詢相匹配的每個文檔,而不僅僅是返回的那些文檔。事實上,您通常只會收回頂級文檔,這些文檔實際上是您向用戶展示的文檔。

我建議不要做這樣的事情:

TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE); 

這將迫使Lucene來恢復文件太多。

無論如何,如果您只有兩個匹配的文檔(或者您要求所有匹配的文檔),則您返回的文檔數量和收集方法的調用數量應該相同。

setNextReader方法是完全不同的,你不應該關心那麼多。看看this article如果你想了解更多關於AtomicReader的信息等等。爲了保持簡短,Lucene將數據存儲爲段,它們是最小的可搜索倒排索引。每個查詢都按順序在每個段上執行。每次搜索切換到下一個段時,將調用setNextReader方法以允許在Collector中的段級別執行操作。例如,內部lucene文檔ID僅在段內是唯一的,因此您需要添加docBase以使其在整個索引內唯一。這就是爲什麼當細分市場發生變化並將其考慮在內時,您需要將其存儲起來。您的countNextReader變量僅包含爲您的查詢分析的段數,它與您的文檔沒有任何關係。

深入瞭解您的Collector代碼我還注意到,在通過id檢索文檔時,您沒有考慮docBase。這應該可以解決它:

Document document = searcher.doc(doc + docBase); 

保持也記住,Collector內加載存儲領域是不是真的做一個明智的做法。這會讓你的搜索真的很慢,因爲存儲的字段是從磁盤加載的。通常只會爲要返回的文檔的子集加載存儲的字段。在Collector內,您通常會加載用於對有效載荷或類似事物等文檔進行評分所需的信息,通常也會使用lucene字段緩存。

+0

這個也是我注意到的,調用Collector#collect的次數與第一次執行返回的次數相同......我的疑惑是爲什麼我在通過scoreDosArray迭代時得到不同的文檔或在收集器方法中檢索文檔......這最終會影響不同的結果,這些結果實際上是文件名,作爲集合返回。 – damax 2013-03-22 13:15:42

+0

明白了,我沒有得到這部分的問題。你忘了考慮'docBase'。看看我更新的答案。 – javanna 2013-03-22 14:05:02

+0

是的,添加doc + docBase解決了問題!我會考慮與收藏家有關的其他評論和建議。感謝您提供寶貴意見。 – damax 2013-03-22 14:18:36