我正在尝试以增量模式刷新Lucene索引,该模式正在更新已更改的文档并保留其他未更改的文档。
要更新已更改的文档,我将使用IndexWriter.deleteDocuments(Query)
删除这些文档,然后使用IndexWriter.addDocument()
添加更新的文档。
Query
中使用的IndexWriter.deleteDocuments
对象包含约12-15个术语。在刷新索引的过程中,我有时需要通过使用IndexWriter.deleteDocuments
删除所有文档然后添加新文档来进行全面刷新。
问题是,在我说删除大约100000个文档后调用IndexWriter.flush()
时,执行并抛出OutOfMemoryError
需要很长时间。如果我禁用刷新,则索引会快速上升到2000000个文档删除,然后它会抛出OutOfMemoryError
。我试图将IndexWriter.setRAMBufferSizeMB
设置为500以避免内存不足错误,但没有运气。索引大小为1.8 GB。
答案 0 :(得分:1)
<强>第一即可。增加RAM缓冲区不是您的解决方案。据我所知,它是一个缓存,我宁愿认为它正在增加你的问题。 OutOfMemoryError是一个JVM问题,而不是Lucene的问题。您可以将RAM缓冲区设置为1TB - 如果您的VM没有足够的内存,则无论如何都会出现问题。所以你可以做两件事:增加JVM内存或减少消耗。
<强>第二即可。您是否考虑过增加堆内存设置?刷新需要永远的原因是系统在内存耗尽之前不久就进行了大量的垃圾收集。这是典型的症状。您可以使用jvisualvm
之类的工具进行检查。您需要先安装GC详细信息插件,然后才能选择并监控疯狂的OutOfMemory应用程序。如果您已经了解了内存问题,可以像这样增加最大堆空间:
java -Xmx512M MyLuceneApp(或者你启动你的Lucene应用程序)
但是,我会再次使用工具来检查内存消耗配置文件和垃圾回收行为。你的目标应该是避免内存不足,因为这会导致垃圾收集导致应用程序速度降低,直至达不到性能。
<强>第三即可。现在,如果你增加堆,你必须确保你有足够的本机内存。因为如果你不这样做(在Linux上查看top
之类的工具),你的系统将开始交换到磁盘,这也会像疯了一样打击Lucene的性能。因为Lucene针对顺序磁盘读取进行了优化,并且如果您的系统开始交换,您的硬盘将执行大量磁盘搜索,这比顺序读取慢2个数量级。所以情况会更糟。
<强>四即可。如果您没有足够的内存,请考虑批量删除。在1,000或10,000个文档之后执行刷新,然后一次又一次。这个OutOfMemoryError的原因是Lucene必须将所有内容保存在内存中,直到你进行刷新。因此,无论如何不允许冲洗太大的批次可能是一个好主意,以避免将来出现问题。
答案 1 :(得分:0)
在我想要从Lucene索引中擦除所有文档的(罕见)场合,我发现关闭IndexWriter,直接删除索引文件然后基本上启动新索引会更有效。该操作只需很短的时间,并保证将您的索引保持在原始状态(如果有点空)状态。
答案 2 :(得分:0)
尝试为IndexWriter使用较小的RamBufferedSize。
IndexWriter如果缓冲区已满(或文档数达到某个级别),则刷新。通过将缓冲区大小设置为较大的数字,您隐式地推迟调用flush,这可能导致内存中包含太多文档。