2017-01-03 23 views
0

私はLuceneを初めて使用しています。Lucene - AlreadyClosedException:このIndexReaderが閉じている

私はRequestIndexSearcher()を呼び出してindexSearcherオブジェクトを取得し、すべての検索を実行するために私のアプリケーションで使用するクラスLuceneUtilityを持っています。 返す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によって返された参照を介してDispose'd _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")); 

はここに次のコードは、問題(少なくとも1つの方法)を再生します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

関連する問題