[英]Lucene 4.x performance issues
在過去的幾周中,我一直在努力將應用程序從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 API的優化和使用實際上提高了3.6.2的性能,因此,除了Lucene之外,其他任何問題都沒有道理。 我只是不知道我還可以在程序中進行哪些更改以修復它。
我們有一個分為20個分片的索引-這在Lucene 3.x和Lucene 4.x中都提供了最佳性能
該索引目前包含約1.5億個文檔,所有文檔都非常簡單且經過高度規范化,因此存在很多重復的令牌。 僅存儲一個字段(ID)-其他字段不可檢索。
我們有一組固定的相對簡單的查詢,這些查詢填充有用戶輸入並執行-它們由多個BooleanQueries,TermQueries和TermRangeQueries組成。 其中一些是嵌套的,但現在只有一個級別。
我們不會對結果進行任何高級處理-我們只獲取分數和存儲的ID字段
我們正在使用MmapDirectories指向tmpfs中的索引文件。 我們玩過useUnmap“ hack”,因為我們不經常打開新目錄,因此有了很大的發展
我們對所有查詢都使用一個IndexSearcher
我們的測試機具有94GB的RAM和64個邏輯內核
1)套接字監聽器收到的請求
2)最多生成4個查詢對象,並使用規范化的用戶輸入填充(查詢的所有必需輸入都必須存在,否則將不執行)
3)使用Fork / Join框架並行執行查詢
4)聚合和其他簡單的后處理
為4.x系統重新創建了索引,但是數據是相同的。 我們嘗試了普通的Lucene42編解碼器以及不使用壓縮的擴展編解碼器(根據網絡上的建議)
在3.x中,我們使用了ParallelMultisearcher的修改版,在4.x中,我們將IndexSearcher與ExecutorService一起使用,並將所有閱讀器合並到MultiReader中
在3.x中,我們使用ThreadPoolExecutor代替了Fork / Join(在我的測試中,Fork / Join的表現更好)
方法 自我時間(%)| 自拍時間(毫秒)| 自拍時間(以毫秒為單位的CPU)
java.util.concurrent.CountDownLatch.await()| 11.29%| 140887.219 | 0.0 <-這只是等待實際工作完成的tcp線程-您可以忽略它
org.apache.lucene.codecs.lucene41.Lucene41PostingsReader $ BlockDocsEnum。<init>()| 9.74%| 21594.03 | 121594
org.apache.lucene.codecs.BlockTreeTerReader $ FieldReader $ SegmentTermsEnum $ Frame。<init>()| 9.59%| 119680.956 | 119680
org.apache.lucene.codecs.lucene41.ForUtil.readBlock()| 6.91%| 86208.621 | 86208
org.apache.lucene.search.DisjunctionScorer.heapAdjust()| 6.68%| 83332.525 | 83332
java.util.concurrent.ExecutorCompletionService.take()| 5.29%| 66081.499 | 6153
org.apache.lucene.search.DisjunctionSucorer.afterNext()| 4.93%| 61560.872 | 61560
org.apache.lucene.search.Tercorer.advance()| 4.53%| 56530.752 | 56530
java.nio.DirectByteBuffer.get()| 3.96%| 49470.349 | 49470
org.apache.lucene.codecs.BlockTreeTerReader $ FieldReader $ SegmentTerEnum。<init>()| 2.97%| 37051.644 | 37051
org.apache.lucene.codecs.BlockTreeTerReader $ FieldReader $ SegmentTerEnum.getFrame()| 2.77%| 34576.54 | 34576
org.apache.lucene.codecs.MultiLevelSkipListReader.skipTo()| 2.47%| 30767.711 | 30767
org.apache.lucene.codecs.lucene41.Lucene41PostingsReader.newTertate()| 2.23%| 27782.522 | 27782
java.net.ServerSocket.accept()| 2.19%| 27380.696 | 0.0
org.apache.lucene.search.DisjunctionSucorer.advance()| 1.82%| 22775.325 | 22775
org.apache.lucene.search.HitQueue.getSentinelObject()| 1.59%| 19869.871 | 19869
org.apache.lucene.store.ByteBufferIndexInput.buildSlice()| 1.43%| 17861.148 | 17861
org.apache.lucene.codecs.BlockTreeTerReader $ FieldReader $ SegmentTerEnum.getArc()| 1.35%| 16813.927 | 16813
org.apache.lucene.search.DisjunctionSucorer.countMatches()| 1.25%| 15603.283 | 15603
org.apache.lucene.codecs.lucene41.Lucene41PostingsReader $ BlockDocsEnum.refillDocs()| 1.12%| 13929.646 | 13929
java.util.concurrent.locks.ReentrantLock.lock()| 1.05%| 13145.631 | 8618
org.apache.lucene.util.PriorityQueue.downHeap()| 1.00%| 12513.406 | 12513
java.util.TreeMap.get()| 0.89%| 11070.192 | 11070
org.apache.lucene.codecs.lucene41.Lucene41PostingsReader.docs()| 0.80%| 10026.117 | 10026
org.apache.lucene.codecs.BlockTreeTerReader $ FieldReader $ SegmentTerEnum $ Frame.decodeMetaData()| 0.62%| 7746.05 | 7746
org.apache.lucene.codecs.BlockTreeTerReader $ FieldReader.iterator()| 0.60%| 7482.395 | 7482
org.apache.lucene.codecs.BlockTreeTerReader $ FieldReader $ SegmentTerEnum.seekExact()| 0.55%| 6863.069 | 6863
org.apache.lucene.store.DataInput.clone()| 0.54%| 6721.357 | 6721
java.nio.DirectByteBufferR.duplicate()| 0.48%| 5930.226 | 5930
org.apache.lucene.util.fst.ByteSequenceOutputs.read()| 0.46%| 5708.354 | 5708
org.apache.lucene.util.fst.FST.findTargetArc()| 0.45%| 5601.63 | 5601
org.apache.lucene.codecs.lucene41.Lucene41PostingsReader.readTermsBlock()| 0.45%| 5567.914 | 5567
org.apache.lucene.store.ByteBufferIndexInput.toString()| 0.39%| 4889.302 | 4889
org.apache.lucene.codecs.lucene41.Lucene41SkipReader。<init>()| 0.33%| 4147.285 | 4147
org.apache.lucene.search.TermQuery $ TermWeight.scorer()| 0.32%| 4045.912 | 4045
org.apache.lucene.codecs.MultiLevelSkipListReader。<init>()| 0.31%| 3890.399 | 3890
org.apache.lucene.codecs.BlockTreeTermsReader $ FieldReader $ SegmentTermsEnum $ Frame.loadBlock()| 0.31%| 3886.194 | 3886
如果您還有其他可能有用的信息,請告訴我。
對於關心或正在嘗試執行類似操作(查詢中的受控並行性)的任何人,我遇到的問題是IndexSearcher在每個分片的每個段中創建一個任務,而不是在每個分片中創建任務-我誤讀了Javadoc。
我通過在分片上使用forceMerge(1)限制了額外線程的數量來解決了這個問題。 在我的用例中,這並不是什么大問題,因為我目前不使用NRT搜索,但是它仍然為更新+從屬同步過程增加了不必要的復雜性,因此我正在研究避免forceMerge的方法。
作為快速解決方案,我可能會擴展IndexSearcher並使其為每個閱讀器而不是每個段產生一個線程,但是Lucene郵件列表中提出了“虛擬段”的概念。 這將是一個更好的長期解決方案。
如果要查看更多信息,可以在此處關注lucene郵件列表線程: http : //www.mail-archive.com/java-user@lucene.apache.org/msg42961.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.