【问题标题】:How can I avoid OutOfMemoryErrors when updating documents in a Lucene index?更新 Lucene 索引中的文档时如何避免 OutOfMemoryErrors?
【发布时间】:2011-08-05 13:01:11
【问题描述】:

我正在尝试以增量模式刷新 Lucene 索引,该模式正在更新已更改的文档并保持其他未更改的文档不变。

为了更新更改的文档,我使用IndexWriter.deleteDocuments(Query) 删除这些文档,然后使用IndexWriter.addDocument() 添加更新的文档。

IndexWriter.deleteDocuments 中使用的 Query 对象包含大约 12-15 个术语。在刷新索引的过程中,有时我还需要通过使用IndexWriter.deleteDocuments 删除所有文档然后添加新文档来进行完全刷新。

问题是当我在删除大约 100000 个文档后调用 IndexWriter.flush() 时,执行需要很长时间并抛出 OutOfMemoryError。如果我禁用刷新,索引会快速到 2000000 个文档删除,然后它会抛出一个OutOfMemoryError。我试图将IndexWriter.setRAMBufferSizeMB 设置为 500 以避免内存不足错误,但没有运气。索引大小为 1.8 GB。

【问题讨论】:

    标签: java lucene


    【解决方案1】:

    首先。增加 RAM 缓冲区不是您的解决方案。据我了解,它是一个缓存,我宁愿争辩说它正在增加你的问题。 OutOfMemoryError 是 JVM 问题而不是 Lucene 问题。您可以将 RAM 缓冲区设置为 1TB - 如果您的 VM 没有足够的内存,那么无论如何您都会遇到问题。所以你可以做两件事:增加 JVM 内存或减少消耗。

    第二。您是否已经考虑增加堆内存设置?刷新需要永远的原因是系统在内存耗尽之前不久进行了大量的垃圾收集。这是典型的症状。您可以使用jvisualvm 之类的工具进行检查。你需要先安装 GC details 插件,然后你可以选择和监控你疯狂的 OutOfMemory 应用程序。如果您了解了内存问题,您可以像这样增加最大堆空间:

    java -Xmx512M MyLuceneApp(或者你启动你的 Lucene 应用程序)

    但是,我还是会先使用工具检查您的内存消耗配置文件和垃圾收集行为。您的目标应该是避免内存不足,因为这会导致垃圾收集降低您的应用程序的性能。

    第三。现在,如果你增加你的堆,你必须确保你也有足够的本机内存。因为如果你不这样做(使用 Linux 上的 top 之类的工具检查)你的系统将开始交换到磁盘,这也会像疯了一样地影响 Lucene 的性能。因为 Lucene 针对顺序磁盘读取进行了优化,如果您的系统开始交换,您的硬盘将执行大量磁盘查找,这比顺序读取慢 2 个数量级。所以情况会更糟。

    第四。如果你没有足够的内存考虑批量删除。在 1,000 或 10,000 个文档后执行刷新,然后一次又一次。这个 OutOfMemoryError 的原因是 Lucene 必须将所有内容保存在内存中,直到您执行刷新。因此,无论如何最好不要刷新太大的批次,以避免将来出现问题。

    【讨论】:

    • 我将 JVM 最大内存堆大小设置为 12G。我还尝试在刷新调用之后调用IndexWriter.expungeDeletes(boolean),我想删除与已删除文档关联的索引中所有未使用的数据。但仍然会发生 OOM。我很惊讶为什么删除 1.8 GB 索引文档会消耗所有 12 GB 内存。
    • 你调查过吗?它实际上会消耗所有内存吗? ... 我对此表示怀疑。使用 jvisualvm,做一个手动 GC,看看还剩下什么。
    • 补充:如果你确实没有记忆问题,我的答案已经过时了,那么我/你可以删除它。无论如何,我仍然很难理解为什么删除 100k 文档对 Lucene 来说应该是个问题。 Lucene 家伙会说这是一个可笑的小数字,如果我问他们这样的话:-/
    • 问题似乎与用于删除文档的查询有关,其中包含大量大约 12-15 的术语,使用了大量内存。当查询只包含一个词时,内存消耗最小
    • “术语”是什么意思。您按文本字词删除文档?
    【解决方案2】:

    在(罕见的)我想从我的 Lucene 索引中擦除所有文档的情况下,我发现关闭 IndexWriter、直接删除索引文件然后基本上开始一个新的索引会更有效。该操作只需要很少的时间,并且保证让您的索引处于原始(如果有些空)状态。

    【讨论】:

      【解决方案3】:

      尝试为您的 IndexWriter 使用较小的 RamBufferedSize。

      如果缓冲区已满(或文档数量达到一定水平),IndexWriter 会刷新。通过将缓冲区大小设置为较大的数字,您会隐式推迟调用刷新,这可能会导致内存中的文档过多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多