本文轉載自:http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623597.htmlhtml
Lucene的索引裏面存了些什麼,如何存放的,也即Lucene的索引文件格式,是讀懂Lucene源代碼的一把鑰匙。java
當咱們真正進入到Lucene源代碼之中的時候,咱們會發現:算法
本文詳細解讀了Apache Lucene - Index File Formats(http://lucene.apache.org/java/2_9_0/fileformats.html) 這篇文章。apache
下圖就是Lucene生成的索引的一個實例:數據結構
Lucene的索引結構是有層次結構的,主要分如下幾個層次:性能
Lucene的索引結構中,即保存了正向信息,也保存了反向信息。編碼
所謂正向信息:spa
所謂反向信息:指針
在瞭解Lucene索引的詳細結構以前,先看看Lucene索引中的基本數據類型。orm
Lucene索引文件中,用一下基本類型來保存信息:
Lucene爲了使的信息的存儲佔用的空間更小,訪問速度更快,採起了一些特殊的技巧,然而在看Lucene文件格式的時候,這些技巧卻容易使咱們感到困惑,因此有必要把這些特殊的技巧規則提取出來介紹一下。
在下不才,胡亂給這些規則起了一些名字,是爲了方便後面應用這些規則的時候可以簡單,不妥之處請你們諒解。
Lucene在反向索引中,要保存詞典(Term Dictionary)的信息,全部的詞(Term)在詞典中是按照字典順序進行排列的,然而詞典中包含了文檔中的幾乎全部的詞,而且有的詞仍是很是的長的,這樣索引文件會很是的大,所謂前綴後綴規則,即當某個詞和前一個詞有共同的前綴的時候,後面的詞僅僅保存前綴在詞中的偏移(offset),以及除前綴之外的字符串(稱爲後綴)。
好比要存儲以下詞:term,termagancy,termagant,terminal,
若是按照正常方式來存儲,須要的空間以下:
[VInt = 4] [t][e][r][m],[VInt = 10][t][e][r][m][a][g][a][n][c][y],[VInt = 9][t][e][r][m][a][g][a][n][t],[VInt = 8][t][e][r][m][i][n][a][l]
共須要35個Byte.
若是應用前綴後綴規則,須要的空間以下:
[VInt = 4] [t][e][r][m],[VInt = 4 (offset)][VInt = 6][a][g][a][n][c][y],[VInt = 8 (offset)][VInt = 1][t],[VInt = 4(offset)][VInt = 4][i][n][a][l]
共須要22個Byte。(原文勘誤:此處是18個Byte)
大大縮小了存儲空間,尤爲是在按字典順序排序的狀況下,前綴的重合率大大提升。
在Lucene的反向索引中,須要保存不少整型數字的信息,好比文檔ID號,好比詞(Term)在文檔中的位置等等。
由上面介紹,咱們知道,整型數字是以VInt的格式存儲的。隨着數值的增大,每一個數字佔用的Byte的個數也逐漸的增多。所謂差值規則(Delta)就是前後保存兩個整數的時候,後面的整數僅僅保存和前面整數的差便可。
好比要存儲以下整數:16386,16387,16388,16389
若是按照正常方式來存儲,須要的空間以下:
[(1) 000, 0010][(1) 000, 0000][(0) 000, 0001],[(1) 000, 0011][(1) 000, 0000][(0) 000, 0001],[(1) 000, 0100][(1) 000, 0000][(0) 000, 0001],[(1) 000, 0101][(1) 000, 0000][(0) 000, 0001]
供需12個Byte。
若是應用差值規則來存儲,須要的空間以下:
[(1) 000, 0010][(1) 000, 0000][(0) 000, 0001],[(0) 000, 0001],[(0) 000, 0001],[(0) 000, 0001]
共需6個Byte。
大大縮小了存儲空間,並且不管是文檔ID,仍是詞在文檔中的位置,都是按從小到大的順序,逐漸增大的。
Lucene的索引結構中存在這樣的狀況,某個值A後面可能存在某個值B,也可能不存在,須要一個標誌來表示後面是否跟隨着B。
通常的狀況下,在A後面放置一個Byte,爲0則後面不存在B,爲1則後面存在B,或者0則後面存在B,1則後面不存在B。
但這樣要浪費一個Byte的空間,其實一個Bit就能夠了。
在Lucene中,採起如下的方式:A的值左移一位,空出最後一位,做爲標誌位,來表示後面是否跟隨B,因此在這種狀況下,A/2是真正的A原來的值。
若是去讀Apache Lucene - Index File Formats這篇文章,會發現不少符合這種規則的:
固然還有一些帶?的但不屬於此規則的:
爲何會存在以上兩種狀況,實際上是能夠理解的:
文章中對以下格式的描述使人困惑: Positions --> <PositionDelta,Payload?> Freq Payload --> <PayloadLength?,PayloadData> PositionDelta和Payload是否適用或然跟隨規則呢?如何標識PayloadLength是否存在呢? 其實PositionDelta和Payload並不符合或然跟隨規則,Payload是否存在,是由.fnm文件中對於每一個域的配置中有關Payload的配置決定的(FieldOption.STORES_PAYLOADS) 。 當Payload不存在時,PayloadDelta自己不聽從或然跟隨原則。 當Payload存在時,格式應該變成以下:Positions --> <PositionDelta,PayloadLength?,PayloadData> Freq 從而PositionDelta和PayloadLength一塊兒適用或然跟隨規則。 |
爲了提升查找的性能,Lucene在不少地方採起的跳躍表的數據結構。
跳躍表(Skip List)是如圖的一種數據結構,有如下幾個基本特徵:
須要注意一點的是,在不少數據結構或算法書中都會有跳躍表的描述,原理都是大體相同的,可是定義稍有差異:
跳躍表比順序查找,大大提升了查找速度,如查找元素72,原來要訪問2,3,7,12,23,37,39,44,50,72總共10個元素,應用跳躍表後,只要首先訪問第1層的50,發現72大於50,而第1層無下一個節點,而後訪問第2層的94,發現94大於72,而後訪問原鏈表的72,找到元素,共須要訪問3個元素便可。
然而Lucene在具體實現上,與理論又有所不一樣,在具體的格式中,會詳細說明。