注意:以下文章是參見(jiàn) http://lucene.apache.org/java/3_0_1/fileformats.html#Fields 和實(shí)踐中讀取文件內(nèi)容概括總結(jié)出來(lái)的。
?
Fields數(shù)據(jù)磁盤(pán)文件存儲(chǔ)細(xì)節(jié)
?
Lucene 的數(shù)據(jù)域在內(nèi)存中組織成Document和Field數(shù)據(jù)結(jié)構(gòu)。每次建立索引的Document對(duì)象都可能擁有不同的Fields,而查詢的時(shí)候,也可以通過(guò)查詢?cè)~找到文檔的相關(guān)Fields信息(這些Fields在創(chuàng)建的時(shí)候必須是 Field.Store.YES )。這些Fields信息存儲(chǔ)在后綴名為.fdx/.fdt/.fnm的磁盤(pán)文件中。
?
★ .fnm?? 域名存儲(chǔ)文件
?
???? FieldInfos (.fnm) --> FNMVersion,FieldsCount, <FieldName, FieldBits> FieldsCount
???? FNMVersion? --> VInt?? 域版本號(hào)(Lucene2.9新加的)
???? FieldsCount? --> VInt?? 域的數(shù)量
???? FieldName --> String?? 域名
???? FieldBits --> Byte? 域狀態(tài)標(biāo)志位
?
???? 每個(gè)域的8位FieldBits記錄了這個(gè)域的標(biāo)志信息。我們從最低位開(kāi)始,詳細(xì)闡述一下這些標(biāo)志位(其實(shí)大部分已經(jīng)在《Document/Fields》闡述過(guò)了):
(1) No.1 bit:1表示此域被索引,0則不被索引。所謂被索引,也就是需要將這個(gè)域的值加入倒排索引表中去。
????? * Field.Index.NO則表示不被索引。
????? * Field.Index.ANALYZED則表示不但被索引,而且被分詞。比如索引"hello world"后,無(wú)論是搜"hello",還是搜"world"都能夠被搜到。
????? * Field.Index.NOT_ANALYZED表示雖然被索引,但是不分詞。比如索引"hello world"后,僅當(dāng)搜"hello world"時(shí),能夠搜到,搜"hello"和搜"world"都搜不到。??
?????
?????
域還有一個(gè)標(biāo)志來(lái)設(shè)定此域的值是否要被存儲(chǔ)。
????? * Field.Store.Yes則表示存儲(chǔ)此域,F(xiàn)ield.Store.NO則表示不存儲(chǔ)此域。
?????
??????
索引域(indexed)和存儲(chǔ)域(Stored)的區(qū)別
????? * 建立索引的域可以將域值作為query來(lái)進(jìn)行搜索。Lucene中建立索引的域如果不被存儲(chǔ),是不會(huì)將其域數(shù)據(jù)內(nèi)容存放在.fdt文件中的,但其索引表會(huì)存放在另外的文件中。
????? * 只存儲(chǔ)而不建立索引的域則不能通過(guò)鍵入query來(lái)搜索,但是可以通過(guò)其他Indexed域的搜索來(lái)得到相應(yīng)的Stored域的信息。
????? 很明顯,這樣區(qū)分是有意義的。在現(xiàn)實(shí)文檔中的所有信息中,有這樣一部分信息,是不太適合作為查詢關(guān)鍵詞,但是有必須被搜索出來(lái)的。比如文件路徑,我們可以通過(guò)查詢文件名來(lái)找到該文件的路徑,但是誰(shuí)也不會(huì)通過(guò)完整的文件路徑去檢索文件名吧?
?
(2) No.2 bit:1表示保存詞向量,0為不保存詞向量。
????? * Field.TermVector.YES表示保存詞向量。
????? * Field.TermVector.NO表示不保存詞向量。
(3) No.3 bit:1表示在詞向量中保存位置信息。
????? * Field.TermVector.WITH_POSITIONS
(4) No.4 bit:1表示在詞向量中保存偏移量信息。
????? * Field.TermVector.WITH_OFFSETS
(5) No.5 bit:1表示不保存標(biāo)準(zhǔn)化因子
????? * Field.Index.ANALYZED_NO_NORMS
????? * Field.Index.NOT_ANALYZED_NO_NORMS
(6) No.6 bit:標(biāo)志是否保存Payload。
?
?
?
?
★ .fdx 域數(shù)據(jù)索引文件 ?? .fdt 域數(shù)據(jù)文件
?
1、fdx 用于查找指定document的所有fields在.fdt文件中的位置,因?yàn)樗氖枪潭ㄩL(zhǎng)度的數(shù)據(jù),因此這個(gè)文件可以很容易地進(jìn)行隨機(jī)訪問(wèn)。
?????
?? FieldIndex (.fdx) --> DocFieldCount? <FieldValuesPosition>
SegSize
?? DocFieldCount?--> UInt32 ? 記錄單個(gè)document存儲(chǔ)的域的個(gè)數(shù)
?? FieldValuesPosition? -->? UInt64? 記錄當(dāng)前document的域數(shù)據(jù)在.fdt文件中的偏移位置。
?? SegSize 指當(dāng)前段中有多少個(gè)document
?
2、fdt 存放域的數(shù)據(jù)值。 注意:fdt中只存放那些需要被存儲(chǔ)(Stored)的域數(shù)據(jù),而不被存儲(chǔ)的(Stored)域是不存放在這里面的。下面有一個(gè)實(shí)例會(huì)詳細(xì)解釋這一點(diǎn)。
?
??? FieldIndex (.fdt) -->? DocFieldCount? <DocFieldData> SegSize
?
??? DocFieldData --> FieldCount, <FieldNum, Bits, Value> FieldCount
??? FieldCount --> VInt??? 當(dāng)前document包含的域的個(gè)數(shù)
??? FieldNum --> VInt?? 當(dāng)前域號(hào)
??? Bits --> Byte 記錄域的標(biāo)志位 (下面從低位開(kāi)始)
?
??? (1) No.1 bit: 1 表示分詞后的field , 0 表示 沒(méi)有分詞的field
??? (2) No.2 bit: 域包含二進(jìn)制數(shù)據(jù)
??? (3) No.3 bit: 表示該 field 的壓縮選項(xiàng)被開(kāi)啟 ,如果壓縮選項(xiàng)開(kāi)啟,采用的壓縮算法 是 ZLIB。
?
??? Value --> String? 當(dāng)前域的數(shù)據(jù)值
?
?
?
★? 專題用例 :
?
關(guān)于例子的詳細(xì)信息參見(jiàn)《 索引文件格式(2):文件結(jié)構(gòu)總體框架 》最后的說(shuō)明。
?
(1) 解釋一下fnm文件中的數(shù)據(jù)
◆ 前五個(gè)字節(jié)(-2,-1,-1,-1,15,)表示fnm文件的版本號(hào)(粉紅色區(qū)域)。上面我們提到了FNMVersion是VInt類型,而VInt類型是可變類型,我們?cè)趺粗繤NMVersion有5個(gè)字節(jié)呢。
?? 在《 索引文件格式(1):基礎(chǔ)知識(shí) 》我們講到了VInt類型每個(gè)Byte的最高位是不表示數(shù)值的,而表示后面是否還有一個(gè)字節(jié)。顯然第1個(gè)byte=-2的最高位為1,后面有一個(gè)字節(jié)。知道第5個(gè)byte=15的最高位為0,因此后面沒(méi)有字節(jié)了。則FNMVersion就用5個(gè)字節(jié)表示的,值為:(-2,-1,-1,-1,15,)
◆ 綠色區(qū)域的3表示Field的數(shù)量。該實(shí)例確實(shí)只有3個(gè)Fields:name、path、content。
◆ 淺藍(lán)色部分就是這三個(gè)Fields的名字。拿其中一個(gè)來(lái)說(shuō)明:(4,110,97,109,101,1)。在上面我們已經(jīng)講到了每個(gè)域名數(shù)據(jù)都有兩部分構(gòu)成<FieldName, FieldBits>。
??? 先說(shuō)說(shuō)FieldName,它是一個(gè)String類型。在《 索引文件格式(1):基礎(chǔ)知識(shí) 》中我們講到String由一個(gè)VInt來(lái)表示字符的數(shù)量,而后面的Chars分別用UTF-8編碼每個(gè)字符。顯然(4,110,97,109,101,)中的第一個(gè)4表示后面有4個(gè)字符,分別是110('n'),97('a'),109('m'),101('e')。
??? 再說(shuō)說(shuō)FieldBits,在這里實(shí)例中最后一個(gè)字節(jié)byte=1表示這個(gè)數(shù)據(jù)。說(shuō)明標(biāo)志位的最低bit=1,而其他bit=0。因此說(shuō)明"name"域是需要索引的域(Indexed)。
?
?
(2) 解釋一下fdx文件中的數(shù)據(jù)
◆ ? 前4個(gè)字節(jié)(0,0,0,2)表示單個(gè)Document存儲(chǔ)于多少個(gè)域,UInt32類型說(shuō)明是固定4個(gè)字節(jié)大小。但是有個(gè)疑問(wèn)了,在這個(gè)實(shí)例中,Document明明有3個(gè)Field,為什么這個(gè)值是2呢。原因就是第三個(gè)Field("content")的Stored is false。這個(gè)域是要分詞并建立倒排索引的,但并不存儲(chǔ)在.fdx和.fdt中。
◆ ? 后面每8個(gè)字節(jié)(UInt64類型)表示一個(gè)數(shù)據(jù)項(xiàng)。其數(shù)據(jù)值表示該Document的域數(shù)據(jù)值在.fdt文件中的存儲(chǔ)位置。比如第一項(xiàng)(0,0,0,0,0,0,0,4)表示doc1中要存儲(chǔ)的兩個(gè)域(name和path)從.fdt數(shù)據(jù)中的第4個(gè)字節(jié)開(kāi)始,到下一項(xiàng)(0,0,0,0,0,0,0,49)第49個(gè)字節(jié)為止。
?
?
(3) 解釋一下fdt文件中的數(shù)據(jù)
◆? 前4個(gè)字節(jié)(0,0,0,2)和上面fdx文件一樣。
◆? 后面正好有4個(gè)DocFieldData,記錄了每個(gè)Document對(duì)象的name和path域的內(nèi)容值。上面也講到了Document有3個(gè)域,為什么content不存儲(chǔ)進(jìn)來(lái)呢。content是文檔內(nèi)容,遠(yuǎn)比name,path域的內(nèi)容大的多。如果都想這樣存儲(chǔ)進(jìn)fdt數(shù)據(jù)的話,這個(gè)文件將無(wú)比龐大。另外,content內(nèi)容提供了查詢倒排索引文件的關(guān)鍵字,我們?cè)趯?shí)際應(yīng)用中,通過(guò)content中的詞可以查詢到包含此詞的文檔的path,也就能夠進(jìn)一步讀取文檔內(nèi)容。沒(méi)有必要再去存儲(chǔ)一遍全部的原文檔內(nèi)容。這也就是為什么在建立索引的時(shí)候content域的Stored=false的原因了。
?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

