天天看點

Lucene.net(4.8.0) 學習問題記錄三: 索引的建立 IndexWriter 和索引速度的優化

前言:目前自己在做使用Lucene.net和PanGu分詞實作全文檢索的工作,不過自己是把别人做好的項目進行遷移。因為項目整體要遷移到ASP.NET Core 2.0版本,而Lucene使用的版本是3.6.0 ,PanGu分詞也是對應Lucene3.6.0版本的。不過好在Lucene.net 已經有了Core 2.0版本(4.8.0 bate版),而PanGu分詞,目前有人正在做,貌似已經做完,隻是還沒有測試~,Lucene更新的改變我都會加粗表示。

Lucene.net 4.8.0   

https://github.com/apache/lucenenet

PanGu分詞(可以直接使用的)

https://github.com/SilentCC/Lucene.Net.Analysis.PanGu

 JIEba分詞(可以直接使用的)

https://github.com/SilentCC/JIEba-netcore2.0

Lucene.net 4.8.0 和之前的Lucene.net 3.6.0 改動還是相當多的,這裡對自己開發過程遇到的問題,做一個記錄吧,希望可以幫到和我一樣需要更新Lucene.net的人。我也是第一次接觸Lucene ,也希望可以幫助初學Lucene的同學。

一,Lucene 建立索引:IndexWriter

1.IndexWriter的介紹

IndexWriter 是用來建立和維護索引的。IndexWriter的建立:在Lucene4.8.0中,建立IndexWriter對象,需要用到IndexWriterConfig 參數,IndexWriterConfig用來設定一些IndexWriter的屬性:

IndexWriterConfig _indexWriterConfig = new IndexWriterConfig(Lucene.Net.Util.LuceneVersion.LUCENE_48,analyze)
IndexWriter _indexWriter = new IndexWriter(dir,_indexWriterConfig)      

上面的代碼建立了一個基本的IndexWriter對象,每個基本IndexWriter都必須有兩個必要的屬性:1.操作的索引目錄 dir ;2. 分詞器 analyze .這裡要注意,IndexWriter的分詞器和IndexSearch的分詞器應該是相同的,否則将會影響搜尋結果。

我們通過IndexWriterConfig 可以設定IndexWriter的屬性,已達到我們希望建構索引的需求,這裡舉一些屬性,這些屬性可以影響到IndexWriter寫入索引的速度:

IndexWriterConfig.setRAMBufferSizeMB(double);
IndexWriterConfig.setMaxBufferedDocs(int);
IndexWriterConfig.setMergePolicy(MergePolicy)      

setRAMBufferSizeMB() 是設定,當IndexWriter添加的文檔的大小超過RAMBufferSizeMB ,IndexWriter就會把在記憶體中的操作,寫入到硬碟中。具體一點:IndexWriter在執行AddDocuments(寫入文檔),DeleteDocuments(删除文檔),UpdateDocuments(更新文檔),這些操作的時候,這些操作都會先緩沖到記憶體中,也就是說執行完這些函數,其實儲存的索引目錄下是沒有任何改變的,當AddDocuments的容量超過上述的屬性的時候,這些操作才會具體執行到儲存索引的硬碟當中。預設的

DEFAULT_RAM_BUFFER_SIZE_MB 是16MB.

setMaxBufferedDocs() 是設定,當IndexWriter添加的文檔數量超過MaxBufferedDocs的時候,IndexWriter就會把記憶體中寫入的文檔,寫到硬碟中,并生成一個新的索引檔案segment。關于Lucene的索引結構會在下面說到。

setMergePolicy 是設定索引合并的政策,MergePolicy中有一個參數DEFAULT_MAX_CFS_SEGMENT_SIZE 表示索引中最多有多少個segment檔案。 

1.1 提高索引的速度 

上面提到了三個IndexWriterConfig的三個屬性。我們知道,IndexWriter是當緩存中的容量達到一定的限制條件之後,才開始将緩存中的操作寫入到硬碟中,事實上,如果我們把限制條件定的值越大,索引的速度是越快的。顯而易見,如果設定RAMBufferSizeMB和MAXBufferedDocu越大,IndexWriter 寫入硬碟的次數就越少,而寫索引的時間耗費大多在對硬碟的操作之上。

IndexWriter寫入索引之後,在索引目錄裡會有很多segment檔案。segment檔案數量達到MergeFactor (設定合并因子)的時候,IndexWriter會将這些segment檔案合并,形成一個新的segment檔案,類似于壓縮。而在索引目錄中,如果segment檔案越多,則搜尋的速度會降低,segement檔案越少,搜尋的速度也就越快。是以當我們設定MergeFactor的值越大的時候,搜尋的速度就會越快,而合并segement的速度則會降低,也即索引的速度會降低。

2. 索引檔案的結構

Lucene.net(4.8.0) 學習問題記錄三: 索引的建立 IndexWriter 和索引速度的優化

這是,一個索引目錄下的索引檔案。結構是這樣的:

  (索引)Index  

     ---(段)Segment  

       ---(文檔)Document

          --- (域)Field

            --- (詞)Term

上面的圖檔中,隻有一個段,_v6.fdt ;_v6.fdx ....... 都屬于_v6 segment中的内容。而segments_5u 和segments.gen 是段的中繼資料檔案,也即它們儲存了段的屬性資訊。

  • XXX.fnm儲存了此段包含了多少個域,每個域的名稱及索引方式。
  • XXX.fdx,XXX.fdt儲存了此段包含的所有文檔,每篇文檔包含了多少域,每個域儲存了那些資訊。
  • XXX.tvx,XXX.tvd,XXX.tvf儲存了此段包含多少文檔,每篇文檔包含了多少域,每個域包含了多少詞,每個詞的字元串,位置等資訊。

上面的是正向資訊,還有反向資訊就不詳細說了。

3.IndexWriter的優化  

在Lucene中IndexWriter.Optimize 用來優化索引,而在Lucene4.8.0中Optimize 已經更名為ForceMerge,為的是少讓你使用。IndexWriter的優化實際上就是把Segment檔案進行合并,你可以輸入參數,ForceMerge(segments) 表示,合并到索引目錄裡最多有segments個段檔案。而當參數越小的時候,也即合并的檔案越多的時候,消耗的時間和空間就越大。很顯然,合并是為了讓我們的搜尋速度變的更快。

在優化的過程中,需要目前索引容量兩倍的空間,比如你現在的索引大小是40個G,在優化過程中,索引的大小會增加到80多個G,然後再合并直到最後隻有30多個G。當你的索引更新不是特别頻繁的時候,可以優化一下,如果更新特别頻繁,那麼調用ForceMerge就會效率很低,這個時候,我們可以設定上面提到過的MergeFactor來,讓索引中segments檔案少一些。

4.IndexWriter的注意事項

1.IndexWriter在操作一個索引的時候會建立一個鎖定檔案,Writer.lock 。如果有另一個IndexWriter要打開這個目錄,将會報錯。

2.IndexWriter執行個體是完全線程安全的,多個線程可以同時調用它的任何方法.

繼續閱讀