Lucene 4.x性能问题



在过去的几周里,我一直在努力将一个应用程序从Lucene 3.x升级到Lucene 4.x,希望能提高性能。不幸的是,在经历了完整的迁移过程并进行了我在网上和文档中发现的各种调整之后,Lucene 4的运行速度明显慢于Lucene 3(约50%)。在这一点上,我几乎没有想法,我想知道是否有其他人对如何加快进度有任何建议。我甚至不想在3.x上有什么大的改进;我很乐意与之匹配,并继续使用Lucene的最新版本。

<编辑>

为了确认没有任何标准迁移更改对性能产生负面影响,我将Lucene 4.x版本移植回Lucene 3.6.2,并保留了较新的API,而不是使用自定义的ParallelMultiSearcher和其他不推荐使用的方法/类。

3.6.2中的性能甚至比以前更快:

  • 旧应用程序(Lucene 3.6.0)-约5700个请求/分钟
  • 使用新的API和一些小的优化(Lucene 4.4.0)更新了应用程序-约2900个请求/分钟
  • 新版本的应用程序移植回来,但保留了优化和更新的IndexSearcher/etc API(Lucene 3.6.2)-约6200个请求/分钟

由于更新的Lucene API的优化和使用实际上提高了3.6.2的性能,因此除了Lucene之外,这对任何事情都没有意义。我只是不知道我还能在程序中更改什么来修复它。

<编辑>

应用程序信息

  • 我们有一个索引,它被分解为20个碎片-这在Lucene 3.x和Lucene 4.x 中都提供了最好的性能

  • 该索引目前包含约1.5亿个文档,所有这些文档都相当简单且高度规范化,因此存在大量重复的令牌。只存储一个字段(ID),其他字段是不可检索的。

  • 我们有一组固定的相对简单的查询,这些查询由用户输入填充并执行——它们由多个BooleanQueries、TermQueries和TermRangeQueries组成。其中一些是嵌套的,但现在只有一个级别。

  • 我们没有对结果做任何改进——我们只是获取分数和存储的ID字段

  • 我们使用的是指向tmpfs中索引文件的MMapDirectories。我们玩了useUnmap"破解",因为我们不经常打开新目录,并且从中得到了很好的提升

  • 我们使用单一的IndexSearcher进行所有查询

  • 我们的测试机器有94GB的RAM和64个逻辑核心

一般处理

1) 套接字侦听器收到的请求

2) 最多生成4个查询对象,并使用规范化的用户输入填充(查询所需的所有输入必须存在,否则将不会执行)

3) 使用Fork/Join框架并行执行查询

  • 使用IndexSearcher w/ExecutorService并行执行对每个碎片的子查询

4)聚合和其他简单的后处理

其他相关信息

  • 为4.x系统重新创建了索引,但数据是相同的。我们尝试了普通的Lucene42编解码器以及不使用压缩的扩展编解码器(根据网络上的建议)

  • 在3.x中我们使用了ParallelMultisearcher的修改版本,在4.x中我们将IndexSearcher与ExecutorService结合使用,并将我们所有的阅读器组合在一个MultiReader 中

  • 在3.x中,我们使用了ThreadPoolExecutor而不是Fork/Join(Fork/Join在我的测试中表现更好)

4.x热点

方法|自身时间(%)|自身时间

java.util.concurrent.CountDownLatch.await()| 11.29%| 140887.219 | 0.0<-这只是来自等待真正工作完成的tcp线程-您可以忽略它
org.apache.locene.codecs.locene41.Lucene41PostingsReader$BlockDocsEnum<init>()|9.74%|21594.03|121594
org.apache.locene.codecs.BlockTreeTerReader$FieldReader$SegmentTermsNum$Frame<init>()|9.59%|119680.956|119680
org.apache.locene.codecs.locene41.ForUtil.readBlock()|6.91%|86208.621|86208
.org.apache.locene.search.DisjunctionScorer.heapAdjust()|6.68%|83332.525|83332
java.util.concurrent.ExecutorCompletionService.take()| 5.29%|66081.499|6153
org.apache.loxene.search.DisjunationSucorer.afterNext()|4.93%|61560.872|61560
org.apache.locene.search.Tercorer.advanced()|4.53%|56530.752|56530
java.nio.DirectByteBuffer.get()|3.96%|49470.349|49470
.org.apache.locene.codecs.BlockTreeTerReader$FieldReader$SegmentTerEnum<init>()|2.97%|37051.644|37051
org.apache.locene.codecs.BlockTreeTerReader$FieldReader$SegmentTerEnum.getFrame(9%| 27380.696|0.0
org.apache.locene.search.DisjunctionSucorer.advanced()|1.82%|22775.325|22775
org/apache.locenes.search.HitQueue.getSentinelObject16813
org.apache.locene.search.DisjunctionSucorer.countMatches12513
java.util.TreeMap.get()|0.89%|1170.192|11070
org.apache.locene.codecs.locene41PostingsReader.docs()|0.80%|10026.117|10026
org/apache.locenE.codecs.BlockTreeTerReader$FieldReader$SegmentTerEnum$Frame.decodeMetaData()|0.62%|7746.05|7746
org.apache.loxee.codecs.BBlockTreeterReader$FieldReader.迭代器()|0.60%|7482.395|7482
org.apache.locene.codecs.BlockTreeTerReader$FieldReader$SegmentTerEnum.seekExact()|0.55%|6863.069|6863
org/apache.locenes.store.DataInput.clone()|0.54%|6721.357|6721
java.nio.DirectByteBufferR.duplicate()|0.48%|5930.226|5930
.org.apache.locene.util.fst.ByteSequenceOutputs.read()| 0.46%|5708.354|5708
org.apache。lucene.util.fst.fst.findTargetArc()|0.45%|5601.63|5601
org.apache.locene.codecs.locene41.Lucene41PostingsReader.readTermsBlock()|0.45%|5567.914|5567
org/apache.locenes.store.ByteBufferIndexInput.toString;init>()|0.33%|4147.285|4147
org.apache.locene.search.TermQuery$TermWeight.scorer()|0.32%|4045.912|4045
org.apache.locine.codecs.MultiLevelSkipListReader。<init>()|0.31%|3890.399|3890
org.apache.locene.codecs.BlockTreeTermsReader$FieldReader$SegmentTermsNum$Frame.loadBlock()|0.301%|38886.194|3886


如果您可以使用任何其他可能有帮助的信息,请告诉我。

对于那些关心或试图做类似事情(在查询中控制并行度)的人来说,我遇到的问题是IndexSearcher正在为每个碎片的每个片段创建一个任务,而不是为每个碎片创建任务——我误读了javadoc。

我在碎片上使用forceMerge(1)来限制额外线程的数量,从而解决了这个问题。在我的用例中,这没什么大不了的,因为我目前不使用NRT搜索,但它仍然给更新+从同步过程增加了不必要的复杂性,所以我正在寻找避免forceMerge的方法。

作为一个快速解决方案,我可能只是扩展IndexSearcher,让它为每个读取器生成一个线程,而不是为每个段生成一个螺纹,但"虚拟段"的想法是在Lucene邮件列表中提出的。这将是一个更好的长期解决方案。

如果你想查看更多信息,你可以关注lucene邮件列表线程:http://www.mail-archive.com/java-user@lucene.apache.org/msg42961.html

最新更新