我正在使用Lucene 2.4.0和JVM(JDK 1.6.0_07)。在尝试索引大型文本文件时,我一直在收到OutOfMemoryError: Java heap space
。
示例1:索引5 MB文本文件的内存不足,最大64 MB。堆大小。所以我增加了最大值。堆大小为512 MB。这适用于5 MB的文本文件,但Lucene仍然使用84 MB的堆空间来执行此操作。为什么这么多?
根据JConsole和Eclipse Ganymede的TPTP Memory Profiling插件,类FreqProxTermsWriterPerField
似乎是迄今为止最大的内存使用者。
示例2:索引62 MB文本文件的内存不足,最大512 MB。堆大小。增加最大值堆大小为1024 MB,但Lucene在执行此操作时使用了826 MB的堆空间。似乎还有太多的内存被用来做这件事。我确定较大的文件会导致错误,因为它似乎相关。
我在拥有2 GB RAM的Windows XP SP2平台上。那么索引大文件的最佳做法是什么?这是我正在使用的代码片段:
// Index the content of a text file.
private Boolean saveTXTFile(File textFile, Document textDocument) throws MyException {
try {
Boolean isFile = textFile.isFile();
Boolean hasTextExtension = textFile.getName().endsWith(".txt");
if (isFile && hasTextExtension) {
System.out.println("File " + textFile.getCanonicalPath() + " is being indexed");
Reader textFileReader = new FileReader(textFile);
if (textDocument == null)
textDocument = new Document();
textDocument.add(new Field("content", textFileReader));
indexWriter.addDocument(textDocument); // BREAKS HERE!!!!
}
} catch (FileNotFoundException fnfe) {
System.out.println(fnfe.getMessage());
return false;
} catch (CorruptIndexException cie) {
throw new MyException("The index has become corrupt.");
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
return false;
}
return true;
}
答案 0 :(得分:4)
作为对Gandalf
的评论作为回应我可以看到你将setMergeFactor设置为1000
API说
setMergeFactor
public void setMergeFactor(int 合并因子)
确定频率 段索引合并 addDocument()。值越小, 索引时使用的内存较少,以及 对未经优化的指数进行搜索 更快,但索引速度更慢。 值越大,使用的RAM就越多 索引期间,以及搜索时 未经优化的指数较慢, 索引更快。因此价值更大 (> 10)最适合批量索引 创造和更小的价值(< 10) 对于交互式的索引 保持。
此方法是一种方便的方法,它在您增加mergeFactor
时使用RAM我建议将它设置为15左右。 (在试验和错误的基础上)补充了setRAMBufferSizeMB,也调用 Commit()。那么 optimize()然后 close() indexwriter对象。(可能是一个JavaBean并将所有这些方法放在一个方法中)当你关闭索引时调用这个方法
发布您的结果,反馈=]
答案 1 :(得分:2)
对于hibernate用户(使用mysql)并使用grails(通过可搜索的插件)。
在索引3M行和5GB数据总量时,我一直收到OOM错误。
这些设置似乎解决了这个问题,而不需要我编写任何自定义索引器。
这里有一些尝试:
指南针设置:
'compass.engine.mergeFactor':'500',
'compass.engine.maxBufferedDocs':'1000'
和hibernate(不确定是否有必要,但可能有所帮助,尤其是默认情况下禁用jdbc结果流的mysql。[link text] [1]
hibernate.jdbc.batch_size = 50
hibernate.jdbc.fetch_size = 30
hibernate.jdbc.use_scrollable_resultset=true
另外,它似乎特别针对mysql,不得不在jdbc连接字符串中添加一些url参数。
url = "jdbc:mysql://127.0.0.1/mydb?defaultFetchSize=500&useCursorFetch=true"
(更新:使用url参数,内存不超过500MB)
在任何情况下,现在我都可以构建我的lucene / comapss索引,其堆大小小于2GB。以前我需要8GB以避免OOM。希望这有助于某人。
[1]:http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-implementation-notes.html mysql streaming jdbc resultset
答案 2 :(得分:1)
分析是确定如此大量内存消耗的唯一方法。
此外,在您的代码中,您没有关闭 Filehandlers,Indexreaders,Inderwriters ,也许是OOM的罪魁祸首,
答案 3 :(得分:0)
您可以根据内存使用情况或文档数量将IndexWriter设置为刷新 - 我建议根据内存将其设置为flsuh并查看是否可以解决您的问题。我的猜测是你的整个索引都存在于内存中,因为你永远不会将它刷新到磁盘上。
答案 4 :(得分:0)
我们在今年早些时候为maven repository search engine at jarvana.com构建搜索索引时遇到了类似的“内存不足”问题。我们在64位Windows Vista四核机器上构建索引,但我们运行的是32位Java和32位Eclipse。我们为JVM分配了1.5 GB的RAM。我们使用了Lucene 2.3.2。该应用程序索引大约100GB的大部分压缩数据,我们的索引最终约为20GB。
我们尝试了很多东西,例如刷新IndexWriter,通过System.gc()显式调用垃圾收集器,尝试取消引用所有可能的东西,等等。我们使用JConsole监视内存使用情况。奇怪的是,根据我们在JConsole中看到的情况,我们经常会遇到“OutOfMemoryError:Java堆空间”错误,当它们不应该发生时。我们尝试切换到32位Java的不同版本,这没有帮助。
我们最终切换到64位Java和64位Eclipse。当我们这样做时,在分配给64位JVM的1.5GB运行时,索引期间我们的堆内存崩溃消失了。此外,切换到64位Java让我们为JVM分配更多内存(我们切换到3GB),这加快了我们的索引。
如果您使用的话,不确定该建议的确切内容。对我们来说,我们的OutOfMemoryError问题似乎与Windows Vista 64和32位Java有关。也许切换到在不同的机器(Linux,Mac,不同的Windows)上运行可能会有所帮助。我不知道我们的问题是否已经消失,但现在它们似乎已经消失了。