我有两个单独的类 - MyIndexer
和MySearcher
。索引器类工作正常并生成一个可与Luke一起浏览的索引。我看到了文档。我正在使用Lucene 4.0.0,以便我可以查看使用Luke的数据。
我有一个带有两个测试方法的JUnit测试类。第一个调用索引器并创建索引。然后它关闭了索引器的读者。然后第二个测试方法执行并尝试搜索结果。
我收到以下错误:
org.apache.lucene.store.AlreadyClosedException: this IndexReader is closed
at org.apache.lucene.index.IndexReader.ensureOpen(IndexReader.java:252)
at org.apache.lucene.index.SegmentReader.fields(SegmentReader.java:147)
at org.apache.lucene.index.TermContext.build(TermContext.java:90)
at org.apache.lucene.search.TermQuery.createWeight(TermQuery.java:167)
at org.apache.lucene.search.IndexSearcher.createNormalizedWeight(IndexSearcher.java:647)
at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:292)
at com.foo.MySearcher.findArtifacts(MySearcher.java:76) // Line pointer shown in comments below
... (more irrelevant stacks)
MyIndexer
相关摘录:
public class MyIndexer
{
private IndexWriter writer;
private IndexConfiguration indexConfiguration;
public MyIndexer()
{
}
public void initialize()
throws IOException
{
StandardAnalyzer analyzer = new StandardAnalyzer(indexConfiguration.getLuceneVersion());
final File indexDir = new File(indexConfiguration.getIndexDirectory()).getCanonicalFile();
final FSDirectory index = FSDirectory.open(indexDir);
IndexWriterConfig config = new IndexWriterConfig(indexConfiguration.getLuceneVersion(), analyzer);
writer = new IndexWriter(index, config);
}
public void addData()
throws IOException
{
// ...
// Add some data here
// ...
writer.addDocument(doc);
}
public void close()
throws IOException
{
if (writer != null)
{
writer.commit();
writer.close();
}
}
public IndexWriter getWriter()
{
return writer;
}
public void setWriter(IndexWriter writer)
{
this.writer = writer;
}
public IndexConfiguration getIndexConfiguration()
{
return indexConfiguration;
}
public void setIndexConfiguration(IndexConfiguration indexConfiguration)
{
this.indexConfiguration = indexConfiguration;
}
}
MySearcher
:
public class MySearcher
{
private IndexReader reader;
private IndexSearcher searcher;
private IndexConfiguration indexConfiguration;
public MySearcher()
{
}
public void initialize()
throws IOException
{
final File indexDir = new File(indexConfiguration.getIndexDirectory()).getCanonicalFile();
final FSDirectory index = FSDirectory.open(indexDir);
reader = DirectoryReader.open(index);
searcher = new IndexSearcher(reader);
}
// This method is currently void for the sake of testing:
public void findData(...)
throws IOException
{
int hitsPerPage = 10;
BooleanQuery query = new BooleanQuery();
// ...
// Does some irrelevant query-related stuff
// ...
TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage, true);
searcher.search(query, collector); // Place where the exception occurs.
ScoreDoc[] hits = collector.topDocs().scoreDocs;
System.out.println("Found " + hits.length + " hits.");
for (int i = 0; i < hits.length; ++i)
{
int docId = hits[i].doc;
Document document = searcher.doc(docId);
System.out.println(/*... Should print out some data from each matching document's fields */);
}
reader.close();
}
public IndexReader getReader()
{
return reader;
}
public void setReader(IndexReader reader)
{
this.reader = reader;
}
public IndexSearcher getSearcher()
{
return searcher;
}
public void setSearcher(IndexSearcher searcher)
{
this.searcher = searcher;
}
public IndexConfiguration getIndexConfiguration()
{
return indexConfiguration;
}
public void setIndexConfiguration(IndexConfiguration indexConfiguration)
{
this.indexConfiguration = indexConfiguration;
}
}
MyLuceneTest:
public class MyLuceneTest
{
public static final String INDEX_DIR = "target/test-indexes/index-001";
private static IndexConfiguration configuration;
@Before
public void setUp()
throws Exception
{
configuration = new IndexConfiguration();
configuration.setIndexDirectory(INDEX_DIR);
}
@Test
public void testVerboseIndexing()
throws IOException
{
MyIndexer indexer = new MyIndexer();
indexer.setIndexConfiguration(configuration);
indexer.initialize();
// Adding some data here
...
indexer.addData(...);
...
indexer.close();
// Obviously, we're not doing any assertions right now.
}
@Test
public void testSearch()
throws IOException
{
MySearcher searcher = new MySearcher();
searcher.setIndexConfiguration(configuration);
searcher.initialize();
searcher.findData(...);
searcher.findData(...);
searcher.findData(...);
// Obviously, we're not doing any assertions right now.
}
}
那么......这里有什么交易......?一旦索引器停止执行并且应用程序完成,通常如何打开索引?我显然做了一些愚蠢的事情,因为我相信你以后可以重新打开索引。
答案 0 :(得分:2)
你的问题在这里:
searcher.initialize();
searcher.findData(...);
searcher.findData(...);
searcher.findData(...);
结合您在方法reader.close()
末尾调用findData
的事实。我猜第一次调用findData
不会导致问题,但第二次调用会发生问题。
MySearcher
似乎旨在让同一位读者和搜索者在多次搜索中保持开放状态(这很好)。在搜索之后关闭读者对我来说真的没有意义。您只需删除对reader.close()
的调用。
答案 1 :(得分:1)
您正在使用findData方法关闭阅读器。
Lucene的最佳做法是在完成搜索后关闭IndexSearcher,并在关闭应用程序时关闭IndexWriter。对于IndexReader,它实际上取决于您需要刷新索引的频率。您可以搜索近实时搜索或使用IndexReader.openIfChanged。