Lucene Indexing在大约1百万个文件(nrm文件越来越大......)后卡住了

时间:2011-06-24 23:38:50

标签: java lucene indexing

有谁知道为什么会这样?我正在对XML文件进行基本索引+ SAX解析,并将每个路径添加为文档中的新字段。我喜欢150万个文件,它在这个文件上停留30分钟,而.nrm(规范化文件??)变得越来越大。

我不知道为什么会这样,我的IndexWriter的形式如下:

writer = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_30), IndexWriter.MaxFieldLength.UNLIMITED)

这对于大型指数来说不是最佳的吗?为什么它冻结在这个文件上?我已经多次使用超过100万个XML文件运行它,并且它不断地卡在不同的XML文件上(特别是这个文件 - 结构很好)。

编辑:

因此,假设我使用单独的java命令一次索引文件2000。索引编写完成后我调用indexwriter close方法,如果我想重写这个索引,我是否遗漏了什么?我应该优化指数吗?我想我记得Lucene in Action说要优化一段时间你是否会写它。

实际上,这种方法适用于180万个文件,但在我尝试在2000个批量添加更多文件后,这个NRM文件和另一个文件写入了大约70GB!如果仅在2000次批量调用java Lucene索引函数时,为什么内存会从JVM中耗尽?它看起来不像垃圾收集问题,除非我在关闭索引编写器之前需要在Lucene代码中添加一些内容。

编辑2:

我有大约400万个XML文件,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<person>
   <name>Candice Archie
   </name>
   <filmography>
      <direct>
         <movie>
            <title>Lucid (2006) (V)
            </title>
            <year>2006
            </year>
         </movie>
      </direct>
      <write>
         <movie>
            <title>Lucid (2006) (V)
            </title>
            <year>2006
            </year>
         </movie>
      </write>
      <edit>
         <movie>
            <title>Lucid (2006) (V)
            </title>
            <year>2006
            </year>
         </movie>
      </edit>
      <produce>
         <movie>
            <title>Lucid (2006) (V)
            </title>
            <year>2006
            </year>
         </movie>
      </produce>
   </filmography>
</person>

我解析这些XML文件并将内容添加到路径的字段中,例如/ person / produce / filmography / movie / title,Lucid(2006)(V)

问题是,我希望计算文档字段实例中给定术语的频率统计数据,对于索引中的每个文档(然后在所有文档上对该值求和)...所以如果有的话/ person / produce / filmography / movie / title的两个实例,它们都包含“Lucid”,我想要两个。如果有另一条路径(例如:/ person / name:Lucid),则Lucene给出的tf(t in d)将给出3,但是对于文档中类似字段内的术语不会这样做。

Lucene Indexing的核心是这样做:

public void endElement( String namespaceURI,String localName,String qName ) throws SAXException {
  if(this.ignoreTags.contains(localName)){
      ignoredArea = false;
      return;
  }
  String newContent = content.toString().trim();
  if(!empty.equals(newContent) && newContent.length()>1)
  {
      StringBuffer stb = new StringBuffer();
      for(int i=0; i<currpathname.size();i++){
      //System.out.println(i + "th iteration of loop. value:" + currpathname.get(i).toString() + k + "th call.");
      stb.append("/");
      stb.append(currpathname.get(i));
      }
      //stb.append("0");
      if(big.get(stb.toString())==null){
          big.put(stb.toString(), 1);
      }
      else{
          big.put(stb.toString(),big.get(stb.toString())+1);
      }
      if(map.get(stb.toString())==null){
          map.put(stb.toString(),0);
          stb.append(map.get(stb.toString())); //ADDED THIS FOR ZERO
      }
      else
      {
          map.put(stb.toString(),map.get(stb.toString())+1);
          stb.append(map.get(stb.toString()));
      }
      doc.add(new Field(stb.toString(),newContent,Field.Store.YES, Field.Index.ANALYZED));
      seenPaths.add(stb);
      //System.out.println(stb.toString());// This will print all fields indexed for each document (separating nonunique [e.x.: /person/name0 /person/name1]
      //System.out.println(newContent);
  }
  currpathname.pop();   
  content.delete(0,content.length()); //clear content
  //This method adds to the Lucene index the field of the unfolded Stack variable currpathname and the value in content (whitespace trimmed).

}

Map和BigMap是哈希映射(不用担心bigmap,它用于其他东西。只要实例化新的XML文件(Document对象),就会实例化map。毕竟有一个方法endDocument()可以添加文件调用startElement,endElement和character方法(这些是Xerces Parser方法)

  public void endDocument( ) throws SAXException {
  try {
      numIndexed++;
    writer.addDocument(doc);
} catch (CorruptIndexException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
  }

对不起,很长的帖子 - 谢谢你的帮助! 另外,我不认为服务器是问题。我一次运行了400万个文件的代码,即使我使用的是Xmx12000M Xms12000M,也会耗尽堆内存

它是一个功能强大的服务器,所以它绝对可以解决这个问题......

编辑3:

再次问好!谢谢,你是对的。 Lucene可能没有做到这一点。我们实际上会做其他实验,但我认为我借助你的想法和其他一些方法解决了这个问题。首先,我停止了对字段的规范化,并且多次缩小了索引的大小。另外,我使用了mergedocs和rambuffer方法并将它们加了起来。索引大大改善。我会用你的帮助标记问题的答案:)谢谢。

1 个答案:

答案 0 :(得分:1)

尝试批量编制索引。波纹管代码应该让你知道如何做到这一点。另外,我建议您查看最新版的Lucene in Action。

很可能你正在重载垃圾收集器(假设没有很难找到的内存泄漏),这最终会导致你的内存不足错误。

    private static final int FETCH_SIZE = 100;
    private static final int BATCH_SIZE = 1000;

    //Scrollable results will avoid loading too many objects in memory
    ScrollableResults scroll = query.scroll(ScrollMode.FORWARD_ONLY);
    int batch = 0;
    scroll.beforeFirst();
    while (scroll.next()) {
        batch++;

        index(scroll.get(0)); //index each element

        if (batch % BATCH_SIZE == 0) {
            //flushToIndexes(); //apply changes to indexes
            //optimize();
            //clear(); //free memory since the queue is processed
        }
    }