2017-01-03 3 views
0

나는 Lucene을 처음 사용하므로 나와 함께하시기 바랍니다.Lucene - AlreadyClosedException :이 IndexReader가 닫혀있다

내 응용 프로그램이 indexInstxSearcher()를 호출하여 indexSearcher 객체를 가져 와서 모든 검색을 수행하는 데 사용하는 클래스 LuceneUtility가 있습니다. return 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

스택 트레이스가 다 말합니다. Dispose'd _searcher는 IndexSearcher에서 반환 한 참조를 통해 소비자에게 발송됩니다.

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