Lucene是一種高性能、可伸縮的信息搜索(IR)庫锡宋,在2000年開源,最初由鼎鼎大名的Doug Cutting開發(fā)咐容,是基于Java實現(xiàn)的高性能的開源項目。Lucene采用了基于倒排表的設(shè)計原理撞鹉,可以非常高效地實現(xiàn)文本查找疟丙,在底層采用了分段的存儲模式颖侄,使它在讀寫時幾乎完全避免了鎖的出現(xiàn),大大提升了讀寫性能享郊。
核心模塊
Lucene的寫流程和讀流程如圖1所示览祖。
其中,虛線箭頭(A炊琉、B展蒂、C、D)表示寫索引的主要過程苔咪,實線箭頭(1-9)表示查詢的主要過程锰悼。
Lucene中的主要模塊(見圖1)及模塊說明如下。
- analysis模塊:主要負(fù)責(zé)詞法分析及語言處理团赏,也就是我們常說的分詞箕般,通過該模塊可最終形成存儲或者搜索的最小單元Term。
- index模塊:主要負(fù)責(zé)索引的創(chuàng)建工作舔清。
- store模塊:主要負(fù)責(zé)索引的讀寫丝里,主要是對文件的一些操作,其主要目的是抽象出和平臺文件系統(tǒng)無關(guān)的存儲体谒。
- queryParser:主要負(fù)責(zé)語法分析杯聚,把我們的查詢語句生成Lucene底層可以識別的條件。
- search模塊:主要負(fù)責(zé)對索引的搜索工作抒痒。
- similarity模塊:主要負(fù)責(zé)相關(guān)性打分和排序的實現(xiàn)幌绍。
核心術(shù)語
下面介紹Lucene中的核心術(shù)語。
- Term:是索引里最小的存儲和查詢單元故响,對于英文來說一般指一個單詞傀广,對于中文來說一般指一個分詞后的詞彩届。
- 詞典(Term Dictionary,也叫作字典):是Term的集合。詞典的數(shù)據(jù)結(jié)構(gòu)可以有很多種丰捷,每種都有自己的優(yōu)缺點坯墨,比如:排序數(shù)組通過二分查找來檢索數(shù)據(jù)病往;HashMap(哈希表)比排序數(shù)組的檢索速度更快,但是會浪費存儲空間停巷;fst(finite-state transducer)有更高的數(shù)據(jù)壓縮率和查詢效率耍攘,因為詞典是常駐內(nèi)存的蕾各,而fst有很好的壓縮率,所以fst在Lucene的新版本中有非常多的使用場景妨托,也是默認(rèn)的詞典數(shù)據(jù)結(jié)構(gòu)吝羞。
- 倒排表(Posting List):一篇文章通常由多個詞組成钧排,倒排表記錄的是某個詞在哪些文章中出現(xiàn)過恨溜。
- 正向信息:原始的文檔信息,可以用來做排序柏腻、聚合五嫂、展示等沃缘。
- 段(segment):索引中最小的獨立存儲單元。一個索引文件由一個或者多個段組成则吟。在Lucene中的段有不變性,也就是說段一旦生成水慨,在其上只能有讀操作晰洒,不能有寫操作谍珊。
Lucene的底層存儲格式如圖2所示急侥。圖2由詞典和倒排表兩部分組成,其中的詞典就是Term的集合绊茧。詞典中的Term指向的文檔鏈表的集合按傅,叫作倒排表唯绍。詞典和倒排表是Lucene中很重要的兩種數(shù)據(jù)結(jié)構(gòu)况芒,是實現(xiàn)快速檢索的重要基石叶撒。詞典和倒排表是分兩部分存儲的祠够,在倒排表中不但存儲了文檔編號古瓤,還存儲了詞頻等信息落君。
在圖2所示的詞典部分包含三個詞條(Term):elasticsearch绎速、lucene和solr纹冤。詞典數(shù)據(jù)是查詢的入口萌京,所以這部分?jǐn)?shù)據(jù)是以fst的形式存儲在內(nèi)存中的枫夺。
在倒排表中绘闷,“l(fā)ucene”指向有序鏈表3,7,15,30,35,67,表示字符串“l(fā)ucene”在文檔編號為3丑勤、7法竞、15岔霸、30呆细、35八匠、67的文章中出現(xiàn)過梨树,elasticsearch和solr同理抡四。
檢索方式
在Lucene的查詢過程中的主要檢索方式有以下四種床嫌。
-
單個詞查詢
指對一個Term進行查詢厌处。比如,若要查找包含字符串“l(fā)ucene”的文檔缆娃,則只需在詞典中找到Term“l(fā)ucene”贯要,再獲得在倒排表中對應(yīng)的文檔鏈表即可崇渗,如圖3所示宅广。
3. 單個詞查詢 - AND
指對多個集合求交集跟狱。比如驶臊,若要查找既包含字符串“l(fā)ucene”又包含字符串“solr”的文檔关翎,則查找步驟如下笤休。
- 在詞典中找到Term“l(fā)ucene”店雅,得到“l(fā)ucene”對應(yīng)的文檔鏈表。
- 在詞典中找到Term“solr”沮明,得到“solr”對應(yīng)的文檔鏈表荐健。
-
合并鏈表江场,對兩個文檔鏈表做交集運算址否,合并后的結(jié)果既包含“l(fā)ucene”佑附,也包含“solr”音同。如圖4所示秃嗜。
4. AND查詢
- OR
指對多個集合求并集叽赊。比如蛇尚,若要查找包含字符串“l(fā)ucene”或者包含字符串“solr”的文檔取劫,則查找步驟如下谱邪。
- 在詞典中找到Term“l(fā)ucene”惦银,得到“l(fā)ucene”對應(yīng)的文檔鏈表末誓。
- 在詞典中找到Term“solr”喇澡,得到“solr”對應(yīng)的文檔鏈表晴玖。
-
合并鏈表呕屎,對兩個文檔鏈表做并集運算秀睛,合并后的結(jié)果包含“l(fā)ucene”或者包含“solr”琅催,如圖5所示藤抡。
5. OR查詢
- NOT
指對多個集合求差集缠黍。比如,若要查找包含字符串“solr”但不包含字符串“l(fā)ucene”的文檔语泽,則查找步驟如下踱卵。
- 在詞典中找到Term“l(fā)ucene”惋砂,得到“l(fā)ucene”對應(yīng)的文檔鏈表西饵。
- 在詞典中找到Term“solr”眷柔,得到“solr”對應(yīng)的文檔鏈表驯嘱。
-
合并鏈表宙拉,對兩個文檔鏈表做差集運算谢澈,用包含“solr”的文檔集減去包含“l(fā)ucene”的文檔集锥忿,運算后的結(jié)果就是包含“solr”但不包含“l(fā)ucene”敬鬓,如圖6所示钉答。
6. NOT查詢
通過上述四種查詢方式数尿,我們不難發(fā)現(xiàn)右蹦,由于Lucene是以倒排表的形式存儲的何陆,所以在Lucene的查找過程中只需在詞典中找到這些Term贷盲,根據(jù)Term獲得文檔鏈表慨灭,然后根據(jù)具體的查詢條件對鏈表進行交球及、并吃引、差等操作镊尺,就可以準(zhǔn)確地查到我們想要的結(jié)果庐氮,相對于在關(guān)系型數(shù)據(jù)庫中的“l(fā)ike”查找要做全表掃描來說弄砍,這種思路是非常高效的音婶。雖然在索引創(chuàng)建時要做很多工作衣式,但這種一次生成碴卧、多次使用的思路也是非常高明的。