lucene結構說明中文文檔

來源:互聯網
上載者:User

來源:www.matrix.com.cn

本文定義了Lucene(版本1.3)用到的索引檔案的格式。

Jakarta Lucene是用Java寫成的,同時有很多團體正在默默的用其他的程式語言來改寫它。如果這些新的版本想和Jakarta Lucene相容,就需要一個與具體語言無關的Lucene索引檔案格式。本文正是試圖提供一個完整的與語言無關的Jakarta Lucene 1.3索引檔案格式的規格定義。

隨著Lucene不斷髮展,本文也應該更新。不同語言寫成的Lucene實現版本應當儘力遵守檔案格式,也必須產生本文的新版本。

本文同時提供相容性批註,描述檔案格式上與前一版本不同的地方。

定義

Lucene中最基礎的概念是索引(index),文檔(document),域(field)和項(term)。

索引包含了一個文檔的序列。

·   文檔是一些域的序列。

·   域是一些項的序列。

·   項就是一個字串。

存在於不同域中的同一個字串被認為是不同的項。因此項實際是用一對字串表示的,第一個字串是網域名稱,第二個是域中的字串。

倒排索引

為了使得基於項的搜尋更有效率,索引中項是靜態儲存的。Lucene的索引屬於索引方式中的倒排索引,因為對於一個項這種索引可以列出包含它的文檔。這剛好是文檔與項自然聯絡的倒置。

域的類型

Lucene中,域的文本可能以逐字的非倒排的方式儲存在索引中。而倒排過的域稱為被索引過了。域也可能同時被儲存和被索引。

域的文本可能被分解許多項目而被索引,或者就被用作一個項目而被索引。大多數的域是被分解過的,但是有些時候某些標識符域被當做一個項目索引是很有用的。

段(Segment)

Lucene索引可能由多個子索引組成,這些子索引成為段。每一段都是完整獨立的索引,能被搜尋。索引是這樣作成的:

1.    為新加入的文檔建立新段。

2.    合并已經存在的段。

搜尋時需要涉及到多個段和/或者多個索引,每一個索引又可能由一些段組成。

文檔號(Document Number)

內部的來說,Lucene用一個整形(interger)的文檔號來指示文檔。第一個被加入到索引中的文檔就是0號,順序加入的文檔將得到一個由前一個號碼遞增而來的號碼。

注意文檔號是可能改變的,所以在Lucene外部儲存這些號碼時必須小心。特別的,號碼的改變的情況如下:

·   只有段內的號碼是相同的,不同段之間不同,因而在一個比段廣泛的上下文環境中使用這些號碼時,就必須改變它們。標準的技術是根據每一段號碼多少為每一段分配一個段號。將段內文檔號轉換到段外時,加上段號。將某段外的文檔號轉換到段內時,根據每段中可能的轉換後號碼範圍來判斷文檔屬於那一段,並減調這一段的段號。例如有兩個含5個文檔的段合并,那麼第一段的段號就是0,第二段段號5。第二段中的第三個文檔,在段外的號碼就是8。

·   文檔刪除後,連續的號碼就出現了間斷。這可以通過合并索引來解決,段合并時刪除的文檔相應也刪掉了,新合并而成的段並沒有號碼間斷。

緒論

索引段維護著以下的資訊:

·   域集合。包含了索引中用到的所有的域。

·   域值儲存表。每一個文檔都含有一個“屬性-值”對的列表,屬性即為網域名稱。這個列表用來儲存文檔的一些附加資訊,如標題,url或者訪問資料庫的一個ID。在搜尋時儲存域的集合可以被返回。這個表以文檔號標識。

·   項字典。這個字典含有所有文檔的所有域中使用過的的項,同時含有使用過它的文檔的文檔號,以及指向使用頻數資訊和位置資訊的指標。

·   項頻數資訊。對於項字典中的每個項,這些資訊包含含有這個項的文檔的總數,以及每個文檔中使用的次數。

·   項位置資訊。對於項字典中的每個項,都存有在每個文檔中出現的各個位置。

·   Normalization factors. For each field in each document, a value is stored that is multiplied into the score for hits on that field. 標準化因子。對於文檔中的每一個域,存有一個值,用來以後乘以這個這個域的命中數(hits)。

·   被刪除的文檔資訊。這是一個可選檔案,用來表明那些文檔已經刪除了。

接下來的各部分部分詳細描述這些資訊。

檔案的命名(File Naming)

同屬於一個段的檔案擁有相同的檔案名稱,不同的副檔名。副檔名由以下討論的各種檔案格式確定。

一般來說,一個索引存放一個目錄,其所有段都存放在這個目錄裡,儘管我們不要求您這樣做。

基礎資料型別 (Elementary Data Type)(Primitive Types)

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

0
00000000
  
  

1
00000001
  
  

2
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

...
  
  
  

這種編碼提供了一種在高效率解碼時壓縮資料的方法。

Chars

Lucene輸出UNICODE字元序列,使用標準UTF-8編碼。

String

Lucene輸出由VINT和字串組成的字串,VINT表示字串長,字串緊接其後。

String --> VInt, Chars

索引包含的檔案(Per-Index Files)

這部分介紹每個索引包含的檔案。

Segments檔案

索引中活動的段儲存在Segments檔案中。每個索引只能含有一個這樣的檔案,名為"segments".這個檔案依次列出每個段的名字和每個段的大小。

Segments --> SegCount, <SegName, SegSize>SegCount

SegCount, SegSize --> UInt32

SegName --> String

SegName表示該segment的名字,同時作為索引其他檔案的首碼。

SegSize是段索引中含有的文檔數。

Lock檔案

有一些檔案用來表示另一個進程在使用索引。

·   如果存在"commit.lock"檔案,表示有進程在寫"segments"檔案和刪除無用的段索引檔案,或者表示有進程在讀"segments"檔案和開啟某些段的檔案。在一個進程在讀取"segments"檔案段資訊後,還沒來得及開啟所有該段的檔案前,這個Lock檔案可以防止另一個進程刪除這些檔案。

·   如果存在"index.lock"檔案,表示有進程在向索引中加入文檔,或者是從索引中刪除文檔。這個檔案防止很多檔案同時修改一個索引。

Deleteable檔案

名為"deletetable"的檔案包含了索引不再使用的檔案的名字,這些檔案可能並沒有被實際的刪除。這種情況只存在與Win32平台下,因為Win32下檔案仍開啟時並不能刪除。

Deleteable --> DelableCount, <DelableName>DelableCount

DelableCount --> UInt32

DelableName --> String

段包含的檔案(Per-Segment Files)

剩下的檔案是每段中包含的檔案,因此由尾碼來區分。

域(Field)

域集合資訊(Field Info)

所有網域名稱都儲存在這個檔案的域集合資訊中,這個檔案以尾碼.fnm結尾。

FieldInfos (.fnm) --> FieldsCount, <FieldName, FieldBits>FieldsCount

FieldsCount --> VInt

FieldName --> String

FieldBits --> Byte

目前情況下,FieldBits只有使用低位,對於已索引的域值為1,對未索引的域值為0。

檔案中的域根據它們的次序編號。因此域0是檔案中的第一個域,域1是接下來的,等等。這個和文檔號的編號方式相同。

域值儲存表(Stored Fields)

域值儲存表使用兩個檔案表示:

1.    域索引(.fdx檔案)。

如下,對於每個文檔這個檔案包含指向域值的指標:

FieldIndex (.fdx) --> <FieldValuesPosition>SegSize

FieldValuesPosition --> Uint64

FieldValuesPosition指示的是某一文檔的某域的域值在域值檔案中的位置。因為域值檔案含有定長的資料資訊,因而很容易隨機訪問。在域值檔案中,文檔n的域值資訊就存在n*8位置處(The position of document n&#39;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表示未分解過。

項字典(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,對於檔案中第一個項)。

項頻數(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

項位置(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

標準化因子(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。

被刪除的文檔(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已經刪除了。

局限性(Limitations)

在以上的檔案格式中,好幾處都有限制項和文檔的最大個數為32位元的極限,即接近於40億。今天看來,這不會造成問題,但是,長遠的看,可能造成問題。因此,這些極限應該或者換為UInt64類型的值,或者更好的,換為VInt類型的值(VInt值沒有上限)。

有兩處地方的代碼要求必須是定長的值,他們是:

1.    FieldValuesPosition變數(儲存於域索引檔案中,.fdx檔案)。它已經是一個UInt64型,所以不會有問題。

2.    TermCount變數(儲存於項資訊檔中,.tis檔案)。這是最後輸出到檔案中的,但是最先被讀取,因此是儲存於檔案的最前端 。索引代碼先在這裡寫入一個0值,然後在其他檔案輸出完畢後覆蓋這個值。所以無論它儲存在什麼地方,它都必須是一個定長的值,它應該被變成UInt64型。

除此之外,所有的UInt值都可以換成VInt型以去掉限制。
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.