★ .frq??
詞語頻率數據
文件 ?? .prx? 詞語位置數據文件
?
1、frq 保存了
詞語所在文檔的文檔列表(docID)和該詞語出現在文檔中的頻率信息。
?
FreqFile (.frq) --> <TermFreqs, SkipData>
TermCount
????? frq文件包含TermCount個項。每一項都代表一個詞,按照tis中的term的順序排列。它分成兩個部分:一部分是倒排表本身,也即一串的文檔號及詞頻;另一部分是跳躍表,為了更快的訪問和定位倒排表中文檔號及詞頻的位置。
?
TermFreqs --> <TermFreq>
DocFreq
????
TermFreq
按文檔編號遞增的順序排序。DocFreq表示
出現
該詞的文檔數量。
?
TermFreq --> DocDelta[, Freq?]?? 一個TermFreq結構是由一個DocDelta后面或許跟著Freq組成。DocDelta是存儲包含此Term的文檔的ID號了,Freq是在此文檔中出現的次數。
注意:TermFreq的存儲數據時比較特別的,其中用到了差值規則和或然跟隨規則。我們在下面解釋一下TermFreq的存儲數據。
(關于差值規則和或然跟隨規則,請參見:《
索引文件格式(1):基礎知識
》
(http://lucene.apache.org/java/3_0_1/fileformats.html#Frequencies)
Lucene官方網站解析freq文件中我們可以看到這樣一段話
For example, the TermFreqs for a term which occurs once in document seven and three times in document eleven, with omitTf false, would be the following sequence of VInts: 15, 8, 3
If omitTf were true it would be this sequence of VInts instead: 7,4
(1) 首先我們看omitTf=false的情況,也即我們在索引中會存儲一個文檔中term出現的次數。
例子中說了,表示在文檔7中出現1次,并且又在文檔11中出現3次的文檔用以下序列表示:15,8,3.
那這三個數字是怎么計算出來的呢?
首先,根據定義TermFreq --> DocDelta[, Freq?],一個TermFreq結構是由一個DocDelta后面或許跟著Freq組成,也即上面我們說的A+B?結構。
DocDelta自然是想存儲包含此Term的文檔的ID號了,Freq是在此文檔中出現的次數。
所以根據例子,應該存儲的完整信息為[DocID = 7, Freq = 1] [DocID = 11, Freq = 3](見全文檢索的基本原理章節)。
然而為了節省空間,Lucene對編號此類的數據都是用差值來表示的,也即上面說的規則2,Delta規則,于是文檔ID就不能按完整信息存了,就應該存放如下:
[DocDelta = 7, Freq = 1][DocDelta = 4 (11-7), Freq = 3]
然而Lucene對于A+B?這種或然跟隨的結果,有其特殊的存儲方式,見規則3,即A+B?規則,如果DocDelta后面跟隨的Freq為1,則用 DocDelta最后一位置1表示。
如果DocDelta后面跟隨的Freq大于1,則DocDelta得最后一位置0,然后后面跟隨真正的值,從而對于第一個Term,由于Freq 為1,于是放在
DocDelta的最后一位表示,DocIDDelta = 7的二進制是000 0111,必須要左移一位,且最后一位置1,000 1111 = 15,對于第二個Term,由于Freq大于1,于是放在DocDelta的最后一位置零,DocIDDelta = 4的二進制是0000 0100,必須要左移一位,且最后一位置零,0000 1000 = 8,然后后面跟隨真正的Freq = 3。
于是得到序列:[DocDleta = 15][DocDelta = 8, Freq = 3],也即序列,15,8,3。
(2) 如果omitTf=true,也即我們不在索引中存儲一個文檔中Term出現的次數,則只存DocID就可以了,因而不存在A+B?規則的應用。[DocID = 7][DocID = 11],然后應用規則2,Delta規則,于是得到序列[DocDelta = 7][DocDelta = 4 (11 - 7)].
?
?
SkipData --> <<SkipLevelLength, SkipLevel>
NumSkipLevels-1
, SkipLevel> <SkipDatum>??
SkipLevel --> <SkipDatum>
DocFreq/(SkipInterval^(Level + 1))
SkipDatum --> DocSkip,PayloadLength?,FreqSkip,ProxSkip,SkipChildLevelPointer?
?
跳躍表可根據倒排表本身的長度(DocFreq)和跳躍的幅度(SkipInterval)而分不同的層次,層次數為NumSkipLevels = Min(MaxSkipLevels, floor(log(DocFreq/log(SkipInterval)))).
?
第Level層的節點數為DocFreq/(SkipInterval^(Level + 1)),level從零計數。
?
除了最高層之外,其他層都有SkipLevelLength來表示此層的二進制長度(而非節點的個數),方便讀取某一層的跳躍表到緩存里面。
?
低層在前,高層在后,當讀完所有的低層后,剩下的就是最后一層,因而最后一層不需要SkipLevelLength。這也是為什么Lucene文 檔中的格式描述為
NumSkipLevels-1
, SkipLevel,也即低NumSKipLevels-1層有SkipLevelLength,最后一層只有SkipLevel,沒有 SkipLevelLength。
?
除最低層以外,其他層都有SkipChildLevelPointer來指向下一層相應的節點。
?
每一個跳躍節點包含以下信息:文檔號,payload的長度,文檔號對應的倒排表中的節點在frq中的偏移量,文檔號對應的倒排表中的節點在 prx中的偏移量。
?
?
2、
prx文件容納了每一個term出現在所有文檔中的位置的列表。注意如果在fields中的omitTf設置為 true時將不會在此文件中存儲任何信息,并且如果索引中所有fields中的omitTf都設置為true,此.prx文件將不會存在
?
ProxFile (.prx) --> <TermPositions>
TermCount
TermPositions --> <Positions>
DocFreq
Positions --> <PositionDelta,Payload?>
Freq
Payload --> <PayloadLength?,PayloadData>
PositionDelta --> VInt
PayloadLength --> VInt
PayloadData --> byte
PayloadLength
?
此文件包含TermCount個項,每一個詞都有一項,因為每一個詞都有自己的詞位置倒排表。
?
對于每一個詞的 都有一個DocFreq大小的數組,每項代表一篇文檔,記錄此文檔中此詞出現的位置。這個文檔數組也是和frq文件中的跳躍表有關 系的,從上面我們知道,在frq的跳躍表節點中有ProxSkip,當SkipInterval為3的時候,frq的跳躍表節點指向prx文件中的此數組 中的第1,第4,第7,第10,第13,第16篇文檔。
?
而有一個Freq大小的數組,每一項代表此詞在此文檔中出現 一次,則有一個位置信息。
?
每一個位置信息包含:PositionDelta(采用差值規則),還可以保存 payload,應用或然跟隨規則。
?
?
?
?
?
★?
專題用例 :
?
?關于例子的詳細信息參見《
索引文件格式 (2):文件 結構總體框架
》最后的說明。
?
?
(1)
解釋一下frq文件的數據
◆
? frq文件的數據很顯然使用了差值規則和或然跟隨規則,比如“term”詞語。其存儲結構應該為[DocID=0,Freq=1][DocID=1,Freq=2][DocID=2,Freq=3][DocID=3,Freq=1]。
差值規則: [DocCode=0,Freq=1][DocCode=1(1-0),Freq=2][DocCode=1(2-1),Freq=2][DocCode=1(3-2),Freq=2]
或然跟隨規則:[DocCode=0,Freq=1] 如果DocCode后面的數據為1,則將DocCode<<1后將最后的bit存儲Freq內容。即DocCode=00000000<<1=00000000 再將最后一個bit存儲Freq=1,則變成00000001。因此、在文件中本來需要2個byte空間,壓縮成1個byte來存儲DocCode+Freq。
???????????????????? [DocCode=1,Freq=2]如果DocCode后面的數據不為1,則將DocCode<<1得到DocCode=00000001<<1=2后,在用另外一個byte來存儲Freq=1。這里沒有壓縮為什么還要左移呢?為了能夠將壓縮數據和沒有壓縮的數據區別開來。
?
(2) 解釋一下prx文件的數據
◆
? 同上,依然使用了差值規則。
?
注意: 這里詞頻和位置信息并沒有使用到跳表結構,是因為所只用的例子中4篇文檔內容很少。如果Dictionary非常大,則會向上面敘述的那樣使用跳表結構來進行存儲。
【Lucene3.0 初窺】索引文件格式(5):posting數據[.frq/.prx]