Lucene文檔結構

4. Lucene文檔結構 
Lucene中最基礎的概念是索引(index),文檔(document),域(field)和項(term)。 
索引包含了一個文檔的序列。 
· 文檔是一些域的序列。 
· 域是一些項的序列。 
· 項就是一個字串。 
存在於不同域中的同一個字串被認爲是不同的項。因此項實際是用一對字串表示的,第一個字串是域名,第二個是域中的字串。 
 
4.1. Lucene概念詳細介紹 
4.1.1. 域的類型 
Lucene中,域的文本可能以逐字的非倒排的方式存儲在索引中。而倒排過的域稱爲被索引過了。域也可能同時被存儲和被索引。 
域的文本可能被分解許多項目而被索引,或者就被用作一個項目而被索引。大多數的域是被分解過的,但是有些時候某些標識符域被當做一個項目索引是很有用的。 
 
4.1.2. 段(Segment) 
Lucene索引可能由多個子索引組成,這些子索引成爲段。每一段都是完整獨立的索引,能被搜索。索引是這樣作成的: 
1. 爲新加入的文檔創建新段。 
2. 合併已經存在的段。 
搜索時需要涉及到多個段和/或者多個索引,每一個索引又可能由一些段組成。 
 
4.1.3. 文檔號(document.nbspNumber) 
內部的來說,Lucene用一個整形(interger)的文檔號來指示文檔。第一個被加入到索引中的文檔就是0號,順序加入的文檔將得到一個由前一個號碼遞增而來的號碼。 
 
注意文檔號是可能改變的,所以在Lucene外部存儲這些號碼時必須小心。特別的,號碼的改變的情況如下: 
 
· 只有段內的號碼是相同的,不同段之間不同,因而在一個比段廣泛的上下文環境中使用這些號碼時,就必須改變它們。標準的技術是根據每一段號碼多少爲每一段分配一個段號。將段內文檔號轉換到段外時,加上段號。將某段外的文檔號轉換到段內時,根據每段中可能的轉換後號碼範圍來判斷文檔屬於那一段,並減調這一段的段號。例如有兩個含5個文檔的段合併,那麼第一段的段號就是0,第二段段號5。第二段中的第三個文檔,在段外的號碼就是8。 
 
· 文檔刪除後,連續的號碼就出現了間斷。這可以通過合併索引來解決,段合併時刪除的文檔相應也刪掉了,新合併而成的段並沒有號碼間斷。 
 
4.1.4. 索引信息 
索引段維護着以下的信息: 
· 域集合。包含了索引中用到的所有的域。 
· 域值存儲表。每一個文檔都含有一個“屬性-值”對的列表,屬性即爲域名。這個列表用來存儲文檔的一些附加信息,如標題,url或者訪問數據庫的一個ID。在搜索時存儲域的集合可以被返回。這個表以文檔號標識。 
· 項字典。這個字典含有所有文檔的所有域中使用過的的項,同時含有使用過它的文檔的文檔號,以及指向使用頻數信息和位置信息的指針。 
· 項頻數信息。對於項字典中的每個項,這些信息包含含有這個項的文檔的總數,以及每個文檔中使用的次數。 
· 項位置信息。對於項字典中的每個項,都存有在每個文檔中出現的各個位置。 
· 標準化因子。對於文檔中的每一個域,存有一個值,用來以後乘以這個這個域的命中數(hits)。 
· 被刪除的文檔信息。這是一個可選文件,用來表明那些文檔已經刪除了。 
接下來的各部分部分詳細描述這些信息。 
 
4.1.5. 文件的命名(File Naming) 
同屬於一個段的文件擁有相同的文件名,不同的擴展名。擴展名由以下討論的各種文件格式確定。 
一般來說,一個索引存放一個目錄,其所有段都存放在這個目錄裏,不這樣作,也是可以的,在性能方面較低。 
 
4.2. Lucene基本數據類型(Primitive Types) 
4.2.1. 字節Byte 
最基本的數據類型就是字節(byte,8位)。文件就是按字節順序訪問的。其它的一些數據類型也定義爲字節的序列,文件的格式具有字節意義上的獨立性。 
UInt32 :32位無符號整數,由四個字節組成,高位優先。UInt32 --> <Byte>4 
Uint64 : 64位無符號整數,由八字節組成,高位優先。UInt64 --> <Byte>8 
VInt : 可變長的正整數類型,每字節的最高位表明還剩多少字節。每字節的低七位表明整數的值。因此單字節的值從0到127,兩字節值從128到16,383,等等。 
VInt 編碼示例 
value 
First byte 
Second byte 
Third byte 

00000000 

00000001 

00000010 
... 
127 
01111111 
128 
10000000 
00000001 
129 
10000001 
00000001 
130 
10000010 
00000001 
... 
16,383 
11111111 
01111111 
16,384 
10000000 
10000000 
00000001 
16,385 
10000001 
10000000 
00000001 
... 這種編碼提供了一種在高效率解碼時壓縮數據的方法。 
 
4.2.2. 字符串Chars 
Lucene輸出UNICODE字符序列,使用標準UTF-8編碼。 
String :Lucene輸出由VINT和字符串組成的字串,VINT表示字串長,字符串緊接其後。 
String --> VInt, Chars 
 
4.3. 索引包含的文件(Per-Index Files) 
4.3.1. Segments文件 
索引中活動的段存儲在Segments文件中。每個索引只能含有一個這樣的文件,名爲"segments".這個文件依次列出每個段的名字和每個段的大小。 
Segments --> SegCount, <SegName, SegSize>SegCount 
SegCount, SegSize --> UInt32 
SegName --> String 
SegName表示該segment的名字,同時作爲索引其他文件的前綴。 
SegSize是段索引中含有的文檔數。 
 
4.3.2. Lock文件 
有一些文件用來表示另一個進程在使用索引。 
· 如果存在"commit.lock"文件,表示有進程在寫"segments"文件和刪除無用的段索引文件,或者表示有進程在讀"segments"文件和打開某些段的文件。在一個進程在讀取"segments"文件段信息後,還沒來得及打開所有該段的文件前,這個Lock文件可以防止另一個進程刪除這些文件。 
· 如果存在"index.lock"文件,表示有進程在向索引中加入文檔,或者是從索引中刪除文檔。這個文件防止很多文件同時修改一個索引。 
 
4.3.3. Deleteable文件 
名爲"deletetable"的文件包含了索引不再使用的文件的名字,這些文件可能並沒有被實際的刪除。這種情況只存在與Win32平臺下,因爲Win32下文件仍打開時並不能刪除。 
Deleteable --> DelableCount, <DelableName>DelableCount 
DelableCount --> UInt32 
DelableName --> String 
 
4.3.4. 段包含的文件(Per-Segment Files) 
剩下的文件是每段中包含的文件,因此由後綴來區分。 
域(Field) 
域集合信息(Field Info) 
所有域名都存儲在這個文件的域集合信息中,這個文件以後綴.fnm結尾。 
 
FieldInfos (.fnm) --> FieldsCount, <FieldName, FieldBits>FieldsCount 
FieldsCount --> VInt 
FieldName --> String 
FieldBits --> Byte 
目前情況下,FieldBits只有使用低位,對於已索引的域值爲1,對未索引的域值爲0。 
文件中的域根據它們的次序編號。因此域0是文件中的第一個域,域1是接下來的,等等。這個和文檔號的編號方式相同。 
 
4.3.5. 域值存儲表(Stored Fields) 
域值存儲表使用兩個文件表示: 
1. 域索引(.fdx文件)。 
如下,對於每個文檔這個文件包含指向域值的指針: 
FieldIndex (.fdx) --> <FieldvaluesPosition>SegSize 
FieldvaluesPosition --> Uint64 
FieldvaluesPosition指示的是某一文檔的某域的域值在域值文件中的位置。因爲域值文件含有定長的數據信息,因而很容易隨機訪問。在域值文件中,文檔n的域值信息就存在n*8位置處(The position of document.nbspn's field data is the Uint64 at n*8 in this file.)。 
2. 域值(.fdt文件)。 
如下,每個文檔的域值信息包含: 
FieldData (.fdt) --> <DocFieldData>SegSize 
DocFieldData --> FieldCount, <FieldNum, Bits, value>FieldCount 
FieldCount --> VInt 
FieldNum --> VInt 
Bits --> Byte 
value --> String 
目前情況下,Bits只有低位被使用,值爲1表示域名被分解過,值爲0表示未分解過。÷ 
 
4.3.6. 項字典(Term Dictionary) 
項字典用以下兩個文件表示: 
1. 項信息(.tis文件)。 
TermInfoFile (.tis)--> TermCount, TermInfos 
TermCount --> UInt32 
TermInfos --> <TermInfo>TermCount 
TermInfo --> <Term, DocFreq, FreqDelta, ProxDelta> 
Term --> <PrefixLength, Suffix, FieldNum> 
Suffix --> String 
PrefixLength, DocFreq, FreqDelta, ProxDelta 
--> VInt 
 
項信息按項排序。項信息排序時先按項所屬的域的文字順序排序,然後按照項的字串的文字順序排序。 
 
項的字前綴往往是共同的,與字的後綴組成字。PrefixLength變量就是表示與前一項相同的前綴的字數。因此,如果前一個項的字是"bone",後一個是"boy"的話,PrefixLength值爲2,Suffix值爲"y"。 
 
FieldNum指明瞭項屬於的域號,而域名存儲在.fdt文件中。 
 
DocFreg表示的是含有該項的文檔的數量。 
 
FreqDelta指明瞭項所屬TermFreq變量在.frq文件中的位置。詳細的說,就是指相對於前一個項的數據的位置偏移量(或者是0,表示文件中第一個項)。 
 
ProxDelta指明瞭項所屬的TermPosition變量在.prx文件中的位置。詳細的說,就是指相對於前一個項的數據的位置偏移量(或者是0,表示文件中第一個項)。 
 
2. 項信息索引(.tii文件)。 
 
每個項信息索引文件包含.tis文件中的128個條目,依照條目在.tis文件中的順序。這樣設計是爲了一次將索引信息讀入內存能,然後使用它來隨機的訪問.tis文件。 
這個文件的結構和.tis文件非常類似,只在每個條目記錄上增加了一個變量IndexDelta。 
TermInfoIndex (.tii)--> IndexTermCount, TermIndices 
IndexTermCount --> UInt32 
TermIndices --> <TermInfo, IndexDelta>IndexTermCount 
IndexDelta --> VInt 
IndexDelta表示該項的TermInfo變量值在.tis文件中的位置。詳細的講,就是指相對於前一個條目的偏移量(或者是0,對於文件中第一個項)。 
 
4.3.7. 項頻數(Frequencies) 
.frq文件包含每一項的文檔的列表,還有該項在對應文檔中出現的頻數。 
FreqFile (.frq) --> <TermFreqs>TermCount 
TermFreqs --> <TermFreq>DocFreq 
TermFreq --> DocDelta, Freq? 
DocDelta,Freq --> VInt 
TermFreqs序列按照項來排序(依據於.tis文件中的項,即項是隱含存在的)。 
TermFreq元組按照文檔號升序排列。 
DocDelta決定了文檔號和頻數。詳細的說,DocDelta/2表示相對於前一文檔號的偏移量(或者是0,表示這是TermFreqs裏面的第一項)。當DocDelta是奇數時表示在該文檔中頻數爲1,當DocDelta是偶數時,另一個VInt(Freq)就表示在該文檔中出現的頻數。 
例如,假設某一項在文檔7中出現一次,在文檔11中出現了3次,在TermFreqs中就存在如下的VInts序列: 
15, 22, 3 
 
4.3.8. 項位置(Position) 
.prx文件包含了某文檔中某項出現的位置信息的列表。 
ProxFile (.prx) --> <TermPositions>TermCount 
TermPositions --> <Positions>DocFreq 
Positions --> <PositionDelta>Freq 
PositionDelta --> VInt 
TermPositions按照項來排序(依據於.tis文件中的項,即項是隱含存在的)。 
Positions元組按照文檔號升序排列。 
PositionDelta是相對於前一個出現位置的偏移位置(或者爲0,表示這是第一次在這個文檔中出現)。 
例如,假設某一項在某文檔第4項出現,在另一個文檔中第5項和第9項出現,將存在如下的VInt序列: 
4, 5, 4 
 
4.3.9. 標準化因子(Normalization Factor) 
.nrm文件包含了每個文檔的標準化因子,標準化因子用來以後乘以這個這個域的命中數。 
Norms (.nrm) --> <Byte>SegSize 
每個字節記錄一個浮點數。位0-2包含了3位的尾數部分,位3-8包含了5位的指數部分。 
按如下規則可將這些字節轉換爲IEEE標準單精度浮點數: 
1. 如果該字節是0,就是浮點0; 
2. 否則,設置新浮點數的標誌位爲0; 
3. 將字節中的指數加上48後作爲新的浮點數的指數; 
4. 將字節中的尾數映射到新浮點數尾數的高3位;並且 
5. 設置新浮點數尾數的低21位爲0。 
 
4.3.10. 被刪除的文檔(Deleted document) 
.del文件是可選的,只有在某段中存在刪除操作後才存在: 
Deletions (.del) --> ByteCount,BitCount,Bits 
ByteSize,BitCount --> Uint32 
Bits --> <Byte>ByteCount 
ByteCount表示的是Bits列表中Byte的數量。典型的,它等於(SegSize/8)+1。 
BitCount表示Bits列表中多少個已經被設置過了。 
Bits列表包含了一些位(bit),順序表示一個文檔。當對應於文檔號的位被設置了,就標誌着這個文檔已經被刪除了。位的順序是從低到高。因此,如果Bits包含兩個字節,0x00和0x02,那麼表示文檔9已經刪除了。 
 
4.3.11. 侷限性(Limitations) 
在以上的文件格式中,好幾處都有限制項和文檔的最大個數爲32位數的極限,即接近於40億。今天看來,這不會造成問題,但是,長遠的看,可能造成問題。因此,這些極限應該或者換爲UInt64類型的值,或者更好的,換爲VInt類型的值(VInt值沒有上限)。 
 
有兩處地方的代碼要求必須是定長的值,他們是: 
 
1. FieldvaluesPosition變量(存儲於域索引文件中,.fdx文件)。它已經是一個UInt64型,所以不會有問題。 
 
2. TermCount變量(存儲於項信息文件中,.tis文件)。這是最後輸出到文件中的,但是最先被讀取,因此是存儲於文件的最前端 。索引代碼先在這裏寫入一個0值,然後在其他文件輸出完畢後覆蓋這個值。所以無論它存儲在什麼地方,它都必須是一個定長的值,它應該被變成UInt64型。 
除此之外,所有的UInt值都可以換成VInt型以去掉限制。 
發佈了16 篇原創文章 · 獲贊 5 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章