重新开启Lucene指数

时间:2013-07-12 15:05:00

标签: java lucene

我有两个单独的类 - MyIndexerMySearcher。索引器类工作正常并生成一个可与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.
    }

}

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

2 个答案:

答案 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。