1

我有两个单独的课程 -MyIndexerMySearcher. indexer 类工作正常,并生成一个可以用 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.
    }

}

所以...这里有什么交易...?一旦索引器停止执行并且应用程序完成后,如何正常打开索引?我显然在做一些愚蠢的事情,因为我相信你以后可以重新打开索引。

4

2 回答 2

2

你的问题在这里:

searcher.initialize();
searcher.findData(...);
searcher.findData(...);
searcher.findData(...);

结合您reader.close()在方法结束时调用的事实findData。我猜第一次调用findData不会导致问题,但第二次调用会。

MySearcher似乎旨在使相同的阅读器和搜索器在多个搜索中保持打开状态(这很好)。对我来说,在搜索后关闭阅读器真的没有意义。您应该简单地删除对reader.close().

于 2013-07-12T15:33:07.693 回答
1

您正在 findData 方法中关闭阅读器。

Lucene 的最佳实践是在完成搜索后关闭 IndexSearcher,在关闭应用程序时关闭 IndexWriter。对于 IndexReader,它实际上取决于您需要多久刷新一次索引。您可以搜索近实时搜索或使用 IndexReader.openIfChanged。

于 2013-07-12T15:40:48.980 回答