【Lucene】Lucene 學習之索引文件結構


 Lucene 索引文件結構

基本概念

  • 索引(index)
    • Lucene的索引由許多個文件組成,這些文件放在同一個目錄下
  • 段(segment)
    • 一個Lucene的索引由多個段組成,段與段之間是獨立的。添加新的文檔時可以生成新的段,達到閾值(段的個數,段中包含的文件數等)時,不同的段可以合並。
    • 在文件夾下,具有相同前綴的文件屬於同一個段
    • segments.gen 和 segments_N(N表示一個具體數字,eg:segments_5)是段的元數據文件,他們保存了段的屬性信息。
  • 文檔(document)
    • 文檔時建索引的基本單位,一個段中可以包含多篇文檔
    • 新添加的文檔時單獨保存在一個新生成的段中,隨着段的合並,不同的文檔會合並到至相同的段中。
  • 域(Field)
    • 一個文檔有可由多個域(Field)組成,比如一篇新聞,有 標題,作者,正文等多個屬性,這些屬性可以看作是文檔的域。
    • 不同的域可以指定不同的索引方式,比如指定不同的分詞方式,是否構建索引,是否存儲等
  • 詞(Term)
    • 詞 是索引的最小單位,是經過詞法分詞和語言處理后的字符串

 

正向信息: 索引(index)——  文檔(document)—— 域(field)—— 詞(term)


 

總體結構(圖片來自網絡)

Lucene的一個index文件存放在同一個文件夾下,由多個文件組成。


 

segments.gen : 用於幫助定位到最新的segments_N。

segments.gen文件格式:,讀取gen文件,然后判定Version是否正確,接着讀取gen0和gen1,如果兩個值相當,那么genB=gen0;

此外,會選擇index所在文件夾下的segments_N文件,選擇最大的一個作為genA,然后比較genA和genB,找到最大的一個,最后才打開segments_N。

IndexInput genInput = directory.openInput(IndexFileNames.SEGMENTS_GEN);//"segments.gen" 
int version = genInput.readInt();//讀出版本號 
if (version == FORMAT_LOCKLESS) {//如果版本號正確 
    long gen0 = genInput.readLong();//讀出第一個N 
    long gen1 = genInput.readLong();//讀出第二個N 
    if (gen0 == gen1) {//如果兩者相等則為genB 
        genB = gen0; 
    } 
}

if (genA > genB) 
    gen = genA; 
else 
    gen = genB;

segments_N:段的元數據信息文件。保存了此索引包含多少個段,每個段包含多少篇文檔等信息。

  • Format:
    • 索引文件格式的版本號。由於Lucene是在不斷開發過程中的,不同版本的Lucene可能有不同索引文件格式,所以規定了文件格式的版本號。
  • Version  
    • 索引的版本號
  • NameCount
    • 下一個新段的段名
  • SegCount
    • 段的個數

SegCount個段的元數據信息:

  • segment:
    • segName
      • 段名
    • SegSize
      • 此段包含的文檔數
      • 包含已經刪除,尚未optimize的文檔。因為在optimize之前,Lucene的段中包含了所有被索引過的文檔,而被刪除的文檔時保存在.del文件中的,在搜索過程中,是從段中讀到了被刪除的文檔,然后再用.del的標志,將這篇文檔過濾掉。
      • optimize時,會觸發段的合並,此時不會將已刪除的文檔合並至新段中。
    • DelGen
      • .del文件的版本號
      • 在optimize之前,刪除的文檔是保存在.del文件中的。
      • 文檔刪除的幾種方式(可以通過IndexReader或者IndexWriter進行刪除)
        • IndexReader.deleteDocument(int docID) 根據文檔號刪除
        • IndexReader.deleteDocuemnts(Term term) 刪除包含此term的文檔
        • IndexWriter.deleteDocuemnts(Term term) 刪除 包含此term的文檔(使用的是InderWriter)
        • IndexWriter.deleteDocuments(Term[] terms) 刪除包含這些terms的文檔
        • IndexWriter.deleteDocuemnts(Query query) 刪除滿足次查詢的文檔
        • IndexWriter.deleteDocuemnts(Query[] queries)刪除滿足這些查詢的文檔
        • 原來的版本中Lucene的刪除一直是由InderReader來完成的,雖然后來可以同IndexWriter來刪除,其實真正還是由IndexReader來完成的。IndexWriter將IndexReader保存在readerpool中,刪除的時候從中取出完成少出操作。
        • DelGen 是每當IndexWriter向索引文件中提交刪除操作的時候,加1,並生成新的.del文件

 

  segment_N 與 segment 文件格式

 

一個段(Segment)包含多個域,每個域都有一些元數據信息,保存在.fnm文件中,.fnm文件的格式如下:

 

 

的數據信息存儲在 .fdt 和 .fdx 文件中:

  其中,.fdx 文件中存放FieldValuesPositon,指向.fdt文件,也就是說 域 的具體數據是存放在fdt文件中的。

  • 域數據文件(fdt):
    • 真正保存存儲域(stored field)信息的是fdt文件
    • 在一個段中總共有segment size 篇文檔,所有fdt文檔中共有segment size 個項,每一個項保存一篇文檔的域信息。
    • 每一篇文檔對應一個FieldCount,表示此文檔包含的域的數目,接着是fieldcount個項,每個項保存一個域的信息
    • 對於每一個域,fieldnum是域號,接着是一個byte,8bit,根據填充的0/1,代表不同的意義,最低一位表示此域是否分詞,倒數第二位表示此域保存的是字符串數據還是二進制數據,倒數第三位表示此域是否被壓縮。最后存儲的是這個存儲域的值。

          

 

  • 域索引文件(fdx):
    • 由域數據文件格式可知,每篇文檔包含的域的個數、每個存儲域的值都是不一樣的,因為域數據文件中的segment size篇文檔,每篇文檔占用的大小也是一樣的,那么如何快速在fdt文件中辨別每一篇文檔的起始地址和終止地址?如何能夠更快的找到第n篇文檔的存儲域的信息呢?這就需要借組域索引文件
    • 域索引文件也總共有segment size 個項,每篇文檔都有一個項,每一項都是一個long,大小固定,每一項都是對應的文檔在fdt中的起始地址偏移量。

 

詞向量(Term Vector)的數據信息(.tvx, .tvd, .tvf)

  詞向量 信息是從索引(index)到文檔(document)到域(field)到詞(term)的正向信息,有了詞向量信息,就可以得到一篇文檔包含哪些詞的信息。

  • 詞向量索引文件(tvx):
    • 一個段(segment)包含N篇文檔,此文件就有N項,每一項代表一篇文檔
    • 每一項包含兩部分信息:第一部分是詞向量文檔文件(tvd)中此文檔的偏移量;第二部分是詞向量文件(tvf)中此文檔的第一個域的偏移量。
  • 詞向量文檔文件(tvd):
    • 每一項首先是此文檔包含的域的個數NumFields,然后是一個NumFields大小的數組,數組每一項都是域號,然后是(NumField - 1)大小的數組,每一篇文檔的第一個域在tvf文件中的偏移量信息存儲在 tvx 文件中,而其他(NumFields - 1)個域在 tvf 中的偏移量就是第一個域的偏移量加上這(NumField - 1)個數組的每一項的值。
  • 詞向量域文件(tvf):
    • 此文件包含了此段中的所有域,並不對文檔做區分,到底第幾個域到第幾個域是屬於那篇文件,是由tvx文件中的第一個域的偏移量以及tvd文件中的(NumField - 1)個域的偏移量來決定哪些域數據那個文檔的。
    • 對於每一個域,首先是此域包含的詞的個數NumTerms,然后是8bit的byte,最后一位指定是否保存位置信息,倒數第二位表示是否保存偏移量信息。然后是NumTerms個項的數組,每一項代表一個詞(Term),對於每一個詞,由詞的文本TermText,詞頻TermFreq(詞在該文檔中出現的次數),詞的位置信息,詞的偏移量信息。

 

參考:http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623599.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM