我是Lucene的新手,所以请耐心等待。
我有一个类LuceneUtility,我的应用程序使用它来调用RequestIndexSearcher()来获取indexSearcher对象并执行所有搜索。 每次返回indexSearcher对象时我都在更新索引(如果有什么需要更新)并重新创建IndexSearcher对象以反映新的更新(如果有任何新的更新)但有时我得到AlreadyClosedException:这个IndexReader已关闭。 / p>
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()
那么......这里有什么交易......?我做错了什么?
非常感谢提前! :)
答案 0 :(得分:2)
堆栈跟踪说明了一切。可能是消费者通过IndexSearcher返回的引用Dispose&#39; _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优惠,所以有经验的最新版本可能会提供更好的起点。