2011-08-05 97 views
2

我正在嘗試刷新增量模式下的Lucene索引,該模式正在更新已更改的文檔並將其他未更改的文檔保持原樣。如何在Lucene索引中更新文檔時避免OutOfMemoryErrors?

爲了更新已更改的文檔,我使用IndexWriter.deleteDocuments(Query)刪除這些文檔,然後使用IndexWriter.addDocument()添加更新的文檔。

用於IndexWriter.deleteDocumentsQuery對象包含大約12-15個術語。在刷新索引的過程中,我有時還需要使用IndexWriter.deleteDocuments刪除所有文檔,然後添加新文檔來進行全面刷新。

問題是當我說在調用約100000個文檔刪除之後調用IndexWriter.flush()時,執行並拋出OutOfMemoryError需要很長時間。如果我禁用了刷新功能,那麼索引就會快速上升到2000000個文檔刪除,然後它會拋出一個OutOfMemoryError。我試圖將IndexWriter.setRAMBufferSizeMB設置爲500以避免內存不足錯誤,但是沒有運氣。索引大小爲1.8 GB。

回答

0

在我想從我的Lucene索引中清除所有文檔的(罕見)場合,我發現關閉IndexWriter更爲高效,直接刪除索引文件,然後基本上開始一個新的索引。該操作所花費的時間非常少,並且保證將您的索引保留在原始狀態(如果某種程度上爲空)。

1

第一個。增加RAM緩衝區不是你的解決方案。據我所知,這是一個緩存,我寧願爭辯說,它會增加你的問題。 OutOfMemoryError是一個JVM問題,不是Lucene的問題。您可以將RAM緩衝區設置爲1TB - 如果您的虛擬機沒有足夠的內存,則無論如何都會有問題。所以你可以做兩件事:增加JVM內存或減少消耗。

第二。你是否已經考慮增加堆內存設置?沖洗永遠需要的原因是系統在內存不足之前不久就會進行大量垃圾回收。這是一個典型的症狀。你可以使用像jvisualvm這樣的工具來檢查。您需要首先安裝GC詳細信息插件,但您可以選擇並監控您的瘋狂OutOfMemory應用程序。如果你已經瞭解了你的記憶問題,可以增加這樣的最大堆空間:

的java -Xmx512M MyLuceneApp(或不過你開始你的Lucene的應用程序)

但同樣,我會用工具首先檢查你的內存消耗概況和垃圾收集行爲。您的目標應該是避免內存不足,因爲這會導致垃圾回收,從而導致應用程序的性能下降。

第三。現在,如果你增加你的堆,你必須確保你有足夠的本機內存。因爲如果你不這樣做(在Linux上檢查工具top),你的系統將開始交換到磁盤,這也會讓Lucene的性能變得如此瘋狂。由於Lucene針對順序磁盤讀取進行了優化,並且如果您的系統開始交換,您的硬盤將執行大量磁盤搜索,這比順序讀取慢2個數量級。所以情況會更糟。

第四。如果您沒有足夠的內存,請考慮批量刪除。在1,000或10,000個文件完成沖洗後,再重複一次。這個OutOfMemoryError的原因是Lucene必須將所有內容都保存在內存中,直到執行flush操作。因此無論如何不允許沖洗過大的批次以避免將來出現問題可能是個好主意。

+0

我將JVM最大內存堆大小設置爲12G。我也曾嘗試在刷新調用後調用'IndexWriter.expungeDeletes(boolean)',我想刪除與已刪除文檔關聯的索引中的所有未使用的數據。但仍會出現OOM。我很驚訝爲什麼1.8 GB的索引文件刪除會佔用全部12 GB的內存。 – JP10

+0

你看過它嗎?它是否真的消耗了所有的內存? ... 我對此表示懷疑。使用jvisualvm,執行手動GC並查看剩下的內容。 –

+0

添加:如果您確實沒有內存問題,我的回答已過時,則我可以刪除它。無論如何,我仍然很難理解爲什麼刪除100k文檔對Lucene來說應該是個問題。 Lucene的人會說這是一個可笑的小數字,如果我問他們這樣的事情: -/ –

0

嘗試爲您的IndexWriter使用較小的RamBufferedSize。

IndexWriter如果緩衝區已滿(或文檔數量達到某個級別),則刷新刷新。通過將緩衝區大小設置爲較大的數值,可以隱式推遲調用刷新,這可能會導致內存中的文檔太多。

相關問題