2017-01-03 15 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 
    } 

StackTrace:

 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's _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 может Dispose экземпляр 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")); 

Вот класс skin-and-bones, который позволяет избежать проблемы 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

В новой версии Lucent.net версии 4.8 есть «SearcherManager» для этой цели – AndyPook

 Смежные вопросы

  • Нет связанных вопросов^_^