如何解决大规模Lucene索引编写中的MergeException?

时间:2013-01-14 05:09:27

标签: python multithreading merge lucene indexing

我有一个python脚本来简单地将unicode句子索引到lucene索引中。它在100个句子和我的1000个句子试用中都能正常工作。然而,当我需要索引200,000个句子时,我在第4514句得到合并错误,问题是什么以及如何解决?

错误

Exception in thread "Thread-4543" org.apache.lucene.index.MergePolicy$MergeException: java.io.FileNotFoundException: /home/alvas/europarl/index/_70g.tii (Too many open files)
    at org.apache.lucene.index.ConcurrentMergeScheduler$MergeThread.run(ConcurrentMergeScheduler.java:271)
Traceback (most recent call last):
Caused by: java.io.FileNotFoundException: /home/alvas/europarl/index/_70g.tii (Too many open files)
    at java.io.RandomAccessFile.open(Native Method)  File "indexer.py", line 183, in <module>

    at java.io.RandomAccessFile.<init>(RandomAccessFile.java:216)
    at org.apache.lucene.store.FSDirectory$FSIndexOutput.<init>(FSDirectory.java:593)
    at org.apache.lucene.store.FSDirectory.createOutput(FSDirectory.java:435)
    at org.apache.lucene.index.TermInfosWriter.initialize(TermInfosWriter.java:91)
    at org.apache.lucene.index.TermInfosWriter.<init>(TermInfosWriter.java:83)
        at org.apache.lucene.index.TermInfosWriter.<init>(TermInfosWriter.java:77)
incrementalIndexing(sfile,tfile,indexDir)
    at org.apache.lucene.index.SegmentMerger.mergeTerms(SegmentMerger.java:381)
    at org.apache.lucene.index.SegmentMerger.merge(SegmentMerger.java:134)  File "indexer.py", line 141, in incrementalIndexing

    at org.apache.lucene.index.IndexWriter.mergeMiddle(IndexWriter.java:3109)
    at org.apache.lucene.index.IndexWriter.merge(IndexWriter.java:2834)
    at org.apache.lucene.index.ConcurrentMergeScheduler$MergeThread.run(ConcurrentMergeScheduler.java:240)
    writer.optimize(); writer.close()
lucene.JavaError: java.io.IOException: background merge hit exception: _70e:c4513 _70f:c1 into _70g [optimize]
    Java stacktrace:
java.io.IOException: background merge hit exception: _70e:c4513 _70f:c1 into _70g [optimize]
    at org.apache.lucene.index.IndexWriter.optimize(IndexWriter.java:1749)
    at org.apache.lucene.index.IndexWriter.optimize(IndexWriter.java:1689)
    at org.apache.lucene.index.IndexWriter.optimize(IndexWriter.java:1669)
Caused by: java.io.FileNotFoundException: /home/alvas/europarl/index/_70g.tii (Too many open files)
    at java.io.RandomAccessFile.open(Native Method)
    at java.io.RandomAccessFile.<init>(RandomAccessFile.java:216)
    at org.apache.lucene.store.FSDirectory$FSIndexOutput.<init>(FSDirectory.java:593)
    at org.apache.lucene.store.FSDirectory.createOutput(FSDirectory.java:435)
    at org.apache.lucene.index.TermInfosWriter.initialize(TermInfosWriter.java:91)
    at org.apache.lucene.index.TermInfosWriter.<init>(TermInfosWriter.java:83)
    at org.apache.lucene.index.TermInfosWriter.<init>(TermInfosWriter.java:77)
    at org.apache.lucene.index.SegmentMerger.mergeTerms(SegmentMerger.java:381)
    at org.apache.lucene.index.SegmentMerger.merge(SegmentMerger.java:134)
    at org.apache.lucene.index.IndexWriter.mergeMiddle(IndexWriter.java:3109)
    at org.apache.lucene.index.IndexWriter.merge(IndexWriter.java:2834)
    at org.apache.lucene.index.ConcurrentMergeScheduler$MergeThread.run(ConcurrentMergeScheduler.java:240)

我的代码:http://pastebin.com/Ep133W5f

示例输入文件: http://pastebin.com/r5qE4qpthttp://pastebin.com/wxCU277x

2 个答案:

答案 0 :(得分:2)

您有来自Java的“打开文件太多”错误。尝试批量添加文档然后提交&amp;在每批(例如)1000个文件之后进行优化。存在其他解决方案,但与搜索后端相关,而不是与Python脚本相关。

答案 1 :(得分:2)

你在第169行重新分配filedir,没有关闭你在第116行所做的那个。我认为这是一个错误,因为你不需要创建那个新的,你可以重用旧的一。另外,你会在每个循环左右创建它,它只会泄漏句柄,因为它们永远不会被关闭。

如果使用其他一些方法,您需要创建一个新的filedir而不关闭它,createEmptyIndex中的第106行和deleteFromIndex中的第97行。

retrieveUniqID中还有另一个不太明显的问题。您正在创建searcher,但只有在第87行的条件if cont == content:为真时才关闭它。在没有匹配的情况下,以及第91行的return None,你永远不会关闭那个搜索者。在这种情况下,由于您将字符串传递给IndexSearcher构造函数,因此它会在内部创建一个Directory,在某些情况下您不会关闭它。如果您愿意,可以使用try / finally块确保始终关闭它。

以上所有调用都来自incrementalIndexing中的主循环,因此泄漏句柄的数量会迅速增加。

另外,需要考虑的事项:所有这些类IndexSearcherIndexReaderIndexWriterDirectory都是线程安全的,创建新的类是很昂贵的每一次。通过小型重新设计可能会更好,以最大限度地减少打开和关闭它们所需的时间。它实际上可能只是你的代码,因为你可以传递已经创建的实例,这将清除不同方法中的大量初始化混乱。

由于您似乎也希望能够访问您已立即编入索引的文档,因此我会考虑通过IndexReader方法获取您的IndexWriter.GetReader()(以及您的IndexSearcher) ,或刷新读者,如:reader = reader.Refresh()