为什么Lucene在索引大文件时会导致OOM?

时间:2009-09-01 13:21:53

标签: file indexing lucene

我正在使用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;
  }

5 个答案:

答案 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(不确定是否有必要,但可能有所帮助,尤其是默认情况下禁用jdb​​c结果流的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)上运行可能会有所帮助。我不知道我们的问题是否已经消失,但现在它们似乎已经消失了。