2017-01-03 83 views
0

我是Lucene的新手,請耐心等待。Lucene - AlreadyClosedException:此IndexReader已關閉

我有一個LuceneUtility類,我的應用程序使用它來調用RequestIndexSearcher()來獲取indexSearcher對象並執行所有搜索。 每當我返回indexSearcher對象時,我正在更新索引(如果需要更新任何東西)並重新創建IndexSearcher對象以反映新更新(如果有任何新更新),但有時會出現AlreadyClosedException:此IndexReader已關閉。

public class LuceneUtility 
{ 
    private static IndexSearcher _searcher; 
    private static Directory _directory; 
    private static Lazy<IndexWriter> _writer = new Lazy<IndexWriter>(() => new IndexWriter(_directory, new KeywordLowerCaseAnalyser(), IndexWriter.MaxFieldLength.UNLIMITED)); 

    private static Object lock_Lucene = new object(); 

    //this private constructor makes it a singleton now. 
    private LuceneUtility() { } 

    //Static constructor, opening the directory once for all. 
    static LuceneUtility() 
    { 
     string s ="Path of lucene Index"; 
     _directory = FSDirectory.Open(s); 
    } 

    public static IndexSearcher IndexSearcher 
    { 
     get 
     { 
      if (_searcher == null) 
      { 
       InitializeSearcher(); 
      } 
      else if (!_searcher.IndexReader.IsCurrent()) 
      { 

       _searcher.Dispose(); 
       InitializeSearcher(); 
      } 

      return _searcher; 
     } 
    } 

    public static IndexWriter IndexWriter 
    { 
     get 
     {    
      return _writer.Value; 
     } 
    } 

    private static void InitializeSearcher() 
    { 
     _searcher = new IndexSearcher(_directory, false); 

    } 

    public static IndexSearcher RequestIndexSearcher() 
    { 

     lock (lock_Lucene) 
     { 
      PerformIndexUpdation(); 
     } 

     return IndexSearcher; 
    } 
    /// <summary> 
    /// Performs Lucene Index Updation 
    /// </summary> 
    private static void PerformIndexUpdation() 
    { 

    // Performs Index Updation 
    } 

堆棧跟蹤:

 AlreadyClosedException: this IndexReader is closed 
    Lucene.Net.Index.IndexReader.EnsureOpen() 
    at Lucene.Net.Index.DirectoryReader.IsCurrent() 
    at LuceneOperation.LuceneUtility.get_IndexSearcher() 
    at LuceneOperation.LuceneUtility.RequestIndexSearcher() 

所以...什麼這裏的交易...?我究竟做錯了什麼 ?

非常感謝提前! :)

回答

2

堆棧跟蹤說明了一切。消費者可能通過IndexSearcher返回的引用處理了_searcher。下面的代碼重新產生此問題(至少單程):

Lucene.Net.Index.IndexWriter sw = LuceneUtility.IndexWriter; 
Lucene.Net.Search.IndexSearcher ref1 = LuceneUtility.IndexSearcher; 
ref1.Dispose(); 
// this next call throws at _searcher.IndexReader.IsCurrent() 
// because _searcher has been Dispose'd 
Lucene.Net.Search.IndexSearcher ref2 = LuceneUtility.IndexSearcher; 

更糟的是,IndexSearcher的可配置實例of_searcher由消費者參考,這可能會導致其他地方相同的異常:

Lucene.Net.Search.IndexSearcher ref1 = LuceneUtility.IndexSearcher; 
// index some documents with the writer 
Lucene.Net.Search.IndexSearcher ref2 = LuceneUtility.IndexSearcher; 
// acquiring ref2 Dispose'd ref1 because index changed so AlreadyClosedException is thrown 
int freq = ref1.DocFreq(new Lucene.Net.Index.Term("text", "RamblinRose")); 

這裏的一個皮膚和骨骼類,避免Dispose問題和經常實例化IndexSearcher的性能陷阱。

public static class MySingletonIndex 
{ 
    private static IndexWriter writer; 

    public static void Open(string path) 
    { 
     if (writer != null) 
      throw new Exception("MySingletonIndex is already open"); 
     // ram directory is a nice option for early stages and experimentation. 
     Directory d = path == null ? new RAMDirectory() : (Directory)FSDirectory.Open(path); 
     writer = new IndexWriter(d, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); 
    } 

    public static void Close() 
    { 
     if (writer == null) return; 
     writer.Dispose(); 
     writer = null; 
    } 
    /// <summary> 
    /// Caller must Dispose the IndexSearcher returned. 
    /// </summary> 
    /// <returns>IndexSearcher</returns> 
    public static IndexSearcher GetSearcher() 
    { 
     if (writer == null) 
      throw new Exception("MySingletonIndex is closed"); 
     return new IndexSearcher(writer.GetReader());   
    } 
} 

writer.GetReader()充滿了勝利。

我走出了最新的Lucene.Net提供的循環,所以有經驗的最新版本的人可能會提供一個更好的起點。

+0

爲了這個目的,Lucene.net 4.8的新版本有一個'SearcherManager' – AndyPook