Lucene索引文件存儲

內(nèi)存管理與數(shù)據(jù)存儲

索引文檔的總體結(jié)構(gòu)

???????? 索引(index):Lucene的索引由許多個文件組成赶熟,這些文件放在同一個目錄下

???????? 段(segment):一個Lucene的索引由多個段組成逗噩,段與段之間是獨立的浸间。添加新的文檔時可以生成新的段玩徊,達到閾值(段的個數(shù)僧叉,段中包含的文件數(shù)等)時拌滋,不同的段可以合并赞辩。在文件夾下雌芽,具有相同前綴的文件屬于同一個段segments.gen 和 segments_N(N表示一個具體數(shù)字,eg:segments_5)是段的元數(shù)據(jù)文件辨嗽,他們保存了段的屬性信息世落。

??????? 文檔(document):文檔時建索引的基本單位,一個段中可以包含多篇文檔糟需。新添加的文檔時單獨保存在一個新生成的段中屉佳,隨著段的合并谷朝,不同的文檔會合并到至相同的段中。

???????? 域(Field):一個文檔有可由多個域(Field)組成武花,比如一篇新聞圆凰,有 標題,作者体箕,正文等多個屬性专钉,這些屬性可以看作是文檔的域。不同的域可以指定不同的索引方式累铅,比如指定不同的分詞方式跃须,是否構(gòu)建索引,是否存儲等

???????? 詞(Term):詞 是索引的最小單位争群,是經(jīng)過詞法分詞和語言處理后的字符串回怜。

Lucene的索引結(jié)構(gòu)中,即保存了正向信息换薄,也保存了反向信息玉雾。

正向信息:

按層次保存了從索引,一直到詞的包含關(guān)系:索引(Index) –> 段(segment) –> 文檔(Document) –> 域(Field) –> 詞(Term)

也即此索引包含了那些段轻要,每個段包含了那些文檔复旬,每個文檔包含了那些域,每個域包含了那些詞冲泥。

既然是層次結(jié)構(gòu)驹碍,則每個層次都保存了本層次的信息以及下一層次的元信息,也即屬性信息凡恍,比如一本介紹中國地理的書志秃,應該首先介紹中國地理的概況,以及中國包含多少個省嚼酝,每個省介紹本省的基本概況及包含多少個市浮还,每個市介紹本市的基本概況及包含多少個縣,每個縣具體介紹每個縣的具體情況闽巩。

如上圖钧舌,包含正向信息的文件有:

????????? segments_N保存了此索引包含多少個段,每個段包含多少篇文檔涎跨。

????????? XXX.fnm保存了此段包含了多少個域洼冻,每個域的名稱及索引方式。

????????? XXX.fdx隅很,XXX.fdt保存了此段包含的所有文檔撞牢,每篇文檔包含了多少域,每個域保存了那些信息。

????????? XXX.tvx普泡,XXX.tvd播掷,XXX.tvf保存了此段包含多少文檔审编,每篇文檔包含了多少域撼班,每個域包含了多少詞,每個詞的字符串垒酬,位置等信息砰嘁。

反向信息:

保存了詞典到倒排表的映射:詞(Term) –> 文檔(Document)

如上圖,包含反向信息的文件有:

????????? XXX.tis勘究,XXX.tii保存了詞典(Term Dictionary)矮湘,也即此段包含的所有的詞按字典順序的排序。

???????? XXX.frq保存了倒排表口糕,也即包含每個詞的文檔ID列表缅阳。

???????? XXX.prx保存了倒排表中每個詞在包含此詞的文檔中的位置。

倒排

倒排存儲示例

文章1的所有關(guān)鍵詞為:[tom] [live] [guangzhou] [i] [live] [guangzhou]     文章2的所有關(guān)鍵詞為:[he] [live] [shanghai]

索引結(jié)構(gòu)

通常有兩種位置:

a.字符位置景描,即記錄該詞是文章中第幾個字符(優(yōu)點是關(guān)鍵詞亮顯時定位快)十办;

b.關(guān)鍵詞位置,即記錄該詞是文章中第幾個關(guān)鍵詞(優(yōu)點是節(jié)約索引空間超棺、詞組(phase)查詢快)向族,lucene中記錄的就是這種位置。

lucene將上面三列分別作為詞典文件(Term Dictionary)棠绘、頻率文件(frequencies)件相、位置文件 (positions)保存。其中詞典文件不僅保存有每個關(guān)鍵詞氧苍,還保留了指向頻率文件和位置文件的指針夜矗,通過指針可以找到該關(guān)鍵字的頻率信息和位置信息。

倒排信息

參考鏈接:Lucene索引過程中的內(nèi)存管理與數(shù)據(jù)存儲

?在Lucene的設計里让虐,IntBlockPool和ByteBlockPool的作用域是IndexChain紊撕,即每個IndexChain都會生成獨立的ByteBlockPool和IntBlockPool ,這樣就不會出現(xiàn)多線程間可變數(shù)據(jù)共享的問題澄干,這種做法實際上是一種約定方式的線程封閉逛揩,即ByteBlockPool本身并不是線程安全的,不像ThreadLocal或者棧封閉麸俘。由于每個IndexChain都需要處理多個Field辩稽,所以IntBlockPool和ByteBlockPool是Field所共享的。需要注意的是ParallelPostingsArray的作用域是Field从媚,即每個Field都有一個postingsArray逞泄。

? ParallelPostingsArray的三個成員變量:

?? textStarts存儲的是每一個term在ByteBlockPool里面的起始位置,通過textStarts[termID]可以快速找到termID對應的term 。

?? byteStarts存儲的是term在ByteBlockPool的結(jié)束位置的下一個位置喷众。

?? IntStarts存儲的是term在IntBlockPool的地址信息各谚,而IntBlockPool則存儲著term在ByteBlockPool中的Slice位置信息。

ParallelPostingsArray成員變量關(guān)系示例

DOCID;Freq;Positions這三種信息都是隨著Term存儲在ByteBlockPool中到千,其存儲過程如下:

???? 第一步:把term.length存儲到ByteBlockPool.buffer中昌渤。這會占用1或者2個byte,由term的大小決定憔四。由于term的最大長度為32766膀息,所以term.length最多會占用兩個byte。

??? 第二步:把term的byte數(shù)組形式存儲到ByteBlockPool.buffer中了赵。

??? 第三步:緊接著term開辟5個byte大小的slice,用來存儲term在每個doc中的freq信息潜支。

??? 第四步:再開辟一塊Slice用來存儲positions信息。

Lucene存儲在索引中的并非真正的docId,而是docDelta,即兩個docId的差值.這樣存儲能夠起到節(jié)約空間的作用柿汛。

索引實現(xiàn)

參考鏈接:Lucene底層實現(xiàn)原理冗酿,它的索引結(jié)構(gòu)

Lucene3.0之前使用的也是跳躍表結(jié)構(gòu),后換成了FST络断,但跳躍表在Lucene其他地方還有應用如倒排表合并和文檔號索引裁替。

FST

理論基礎:《Direct constructionofminimal acyclic subsequential transducers》,通過輸入有序字符串構(gòu)建最小有向無環(huán)圖妓羊。

優(yōu)點:內(nèi)存占用率低胯究,壓縮率一般在3倍~20倍之間、模糊查詢支持好躁绸、查詢快

缺點:結(jié)構(gòu)復雜裕循、輸入要求有序、更新不易

Lucene里有個FST的實現(xiàn)净刮,從對外接口上看剥哑,它跟Map結(jié)構(gòu)很相似,有查找淹父,有迭代株婴。

與Map的性能對比

倒排索引

索引文件結(jié)構(gòu)

往索引庫里插入四個單詞abd、abe暑认、acf困介、acg,看看它的索引文件內(nèi)容如下:

索引結(jié)構(gòu)圖

構(gòu)建過程如下:

構(gòu)建過程

Lucene的FST實現(xiàn)的主要優(yōu)化策略有:

1. 最小后綴數(shù)。Lucene對寫入tip的前綴有個最小后綴數(shù)要求蘸际,默認25座哩,這時為了進一步減少內(nèi)存使用。如果按照25的后綴數(shù)粮彤,那么就不存在ab根穷、ac前綴姜骡,將只有一個跟節(jié)點,abd屿良、abe圈澈、acf、acg將都作為后綴存在tim文件中尘惧。我們的10g的一個索引庫康栈,索引內(nèi)存消耗只占20M左右。

2.前綴計算基于byte褥伴,而不是char谅将,這樣可以減少后綴數(shù)漾狼,防止后綴數(shù)太多重慢,影響性能。如對宇(e9 b8 a2)逊躁、守(e9 b8 a3)似踱、安(e9 b8 a4)這三個漢字,F(xiàn)ST構(gòu)建出來稽煤,不是只有根節(jié)點核芽,三個漢字為后綴,而是從unicode碼出發(fā)酵熙,以e9轧简、b8為前綴,a2匾二、a3哮独、a4為后綴。

倒排表的docId壓縮

docId壓縮存儲

跳躍表加速合并察藐,因為布爾查詢時皮璧,and 和or 操作都需要合并倒排表,這時就需要快速定位相同文檔號分飞,所以利用跳躍表來進行相同文檔號查找悴务。

正排:

正向信息在Lucene中只有docId-document的映射,由CompressingStoredFieldsWriter類來完成譬猫。

Lucene的正向信息存儲比較簡單讯檐,按Field依次把內(nèi)容寫入到bufferedDocs中,然后把偏移量寫入到endOffsets中就OK了染服。

當滿足flush條件或者執(zhí)行了IndexWriter.commit()方法别洪,則會進行一次flush操作,把內(nèi)存中緩存的document及倒排信息flush到硬盤中肌索。

正向索引

正向索引結(jié)構(gòu)

fnm中為元信息存放了各列類型蕉拢、列名特碳、存儲方式等信息。

段的元數(shù)據(jù)信息

fdt為文檔值晕换,里面一個chunk就是一個塊午乓,Lucene索引文檔時,先緩存文檔闸准,緩存大于16KB時益愈,就會把文檔壓縮存儲。一個chunk包含了該chunk起始文檔夷家、多少個文檔蒸其、壓縮后的文檔內(nèi)容。

域數(shù)據(jù)文件

fdx為文檔號索引库快,倒排表存放的時文檔號摸袁,通過fdx才能快速定位到文檔位置即chunk位置,它的索引結(jié)構(gòu)比較簡單义屏,就是跳躍表結(jié)構(gòu)靠汁,首先它會把1024個chunk歸為一個block,每個block記載了起始文檔值,block就相當于一級跳表闽铐。


域索引文件的作用示意

所以查找文檔蝶怔,就分為三步:

??? 第一步二分查找block,定位屬于哪個block兄墅。

??? 第二步就是根據(jù)從block里根據(jù)每個chunk的起始文檔號踢星,找到屬于哪個chunk和chunk位置。

?? 第三步就是去加載fdt的chunk隙咸,找到文檔沐悦。這里還有一個細節(jié)就是存放chunk起始文檔值和chunk位置不是簡單的數(shù)組,而是采用了平均值壓縮法扎瓶。所以第N個chunk的起始文檔值由DocBase + AvgChunkDocs * n + DocBaseDeltas[n]恢復而來所踊,而第N個chunk再fdt中的位置由StartPointerBase + AvgChunkSize * n + StartPointerDeltas[n]恢復而來。

???? 從上面分析可以看出概荷,lucene對原始文件的存放是行式存儲秕岛,并且為了提高空間利用率,是多文檔一起壓縮误证,因此取文檔時需要讀入和解壓額外文檔继薛,因此取文檔過程非常依賴隨機IO,以及l(fā)ucene雖然提供了取特定列愈捅,但從存儲結(jié)構(gòu)可以看出遏考,并不會減少取文檔時間。

列式存儲

詞向量(Term Vector)的數(shù)據(jù)信息

詞向量 信息是從索引(index)到文檔(document)到域(field)到詞(term)的正向信息蓝谨,有了詞向量信息灌具,就可以得到一篇文檔包含哪些詞的信息青团。

Lucene目前有五種類型的DocValues:NUMERIC、BINARY咖楣、SORTED督笆、SORTED_SET、SORTED_NUMERIC诱贿,針對每種類型Lucene都有特定的壓縮方法娃肿。

如對NUMERIC類型即數(shù)字類型,數(shù)字類型壓縮方法很多珠十,如:增量料扰、表壓縮、最大公約數(shù)焙蹭,根據(jù)數(shù)據(jù)特征選取不同壓縮方法晒杈。

SORTED類型即字符串類型,壓縮方法就是表壓縮:預先對字符串字典排序分配數(shù)字ID壳嚎,存儲時只需存儲字符串映射表桐智,和數(shù)字數(shù)組即可,而這數(shù)字數(shù)組又可以采用NUMERIC壓縮方法再壓縮烟馅。

列式存儲

對DocValues的應用,ElasticSearch功能實現(xiàn)地更系統(tǒng)然磷、更完整郑趁,即ElasticSearch的Aggregations——聚合功能,它的聚合功能分為三類: Metric -> 統(tǒng)計 姿搜、 Bucket ->分組 寡润、 Pipline -> 基于聚合再聚合 。

ElasticSearch基于倒排索引和DocValues實現(xiàn)SQL過程

相關(guān)鏈接:Lucene原理與代碼分析完整版

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舅柜,一起剝皮案震驚了整個濱河市梭纹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌致份,老刑警劉巖变抽,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異氮块,居然都是意外死亡绍载,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門滔蝉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來击儡,“玉大人,你說我怎么就攤上這事蝠引⊙舻” “怎么了蛀柴?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矫夯。 經(jīng)常有香客問我名扛,道長,這世上最難降的妖魔是什么茧痒? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任肮韧,我火速辦了婚禮,結(jié)果婚禮上旺订,老公的妹妹穿的比我還像新娘弄企。我一直安慰自己,他們只是感情好区拳,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布拘领。 她就那樣靜靜地躺著,像睡著了一般樱调。 火紅的嫁衣襯著肌膚如雪约素。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天笆凌,我揣著相機與錄音圣猎,去河邊找鬼。 笑死乞而,一個胖子當著我的面吹牛送悔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播爪模,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼欠啤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屋灌?” 一聲冷哼從身側(cè)響起洁段,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎共郭,沒想到半個月后祠丝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡落塑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年纽疟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片憾赁。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡污朽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出龙考,到底是詐尸還是另有隱情蟆肆,我是刑警寧澤矾睦,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站炎功,受9級特大地震影響枚冗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蛇损,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一赁温、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧淤齐,春花似錦股囊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至祭务,卻和暖如春内狗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背义锥。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工柳沙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缨该。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓偎行,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贰拿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容