5分鐘了解搜尋引擎Lucene的原理

2021-02-15 代碼狂魔
5分鐘了解搜尋引擎Lucene的原理場景

假設現在有10W+份word文檔,讓你做個web頁面,給出關鍵詞能快速搜索結果,你會怎麼做?那至少有3種方案,

順序掃描,每次檢測文檔中是否包含關鍵詞,包含則加入結果列表,不包含繼續查找下一個,直到找完為止。

將文檔內容導入資料庫,用SQL的like關鍵詞搜索。

用Lucene做全文檢索。

你會選哪種?首先順序掃描在數據量大的時候太慢,數據量比較少的話可行;導入資料庫數據量太大用like會引起全表掃描也會很慢,那當然是第三種,因為搜尋引擎Lucene就是專門為這種場景設計的:大量的,分結構化數據的快速搜索

看看官網怎麼對Lucene的介紹

可擴展,高性能的索引過程

在現代化的硬體上面索引超過150G/小時

只需要1M的堆

增量索引和批量索引一樣快

索引大小大約是文本索引大小的20-30%

強大,準確和高效的搜索算法

全文檢索原理

全文檢索原理很簡單,就拿新華字典做比喻,假設字典沒有索引頁,你要找一個字的解釋你就得一頁一頁翻,直到找到為止,這效率可想而知

現在有了索引頁,就可以根據拼音首字母或偏旁部首快速定位到目標字在哪一頁,這個索引頁,就是全文檢索核心。

簡而言之:在非結構化數據中,將一部分結構化信息抽取出來,重新組織,然後針對這部分有結構的數據進行索引建立,從而達到加速查詢的目的。那麼

索引存啥?怎麼存?(對應字典的索引頁部分)

數據怎麼存?(對應字典非索引頁部分)

反向索引

在Lucene 中,關鍵詞就是Term(比如英文裡面的一個單詞,中文的詞語),字典就是Term的集合。下圖是Lucene 的索引的底層存儲結構,左邊是字典,右邊保存的是包含左邊字符串的文檔編碼鍊表,稱之為倒排表

上面這種就叫做反向索引,是相對正向索引而言的:

比如上圖中包含"lucene"這個關鍵詞的文檔編碼有3,7,15,30,35,67,其他同理

單個詞查詢

查詢的時候直接根據關鍵詞返回與之對應的倒排表即可。

多個詞查詢

將要查詢的字符串分詞,分成多個關鍵詞,根據關鍵詞返回倒排表,再根據邏輯條件(且或非)整合倒排表

且:很簡單,多個倒排表直接做交集運算

或:併集運算

非:差集運算

字典

當數據量很大時候,字典的數據就會很多,想想就知道一篇文章關鍵詞是很多的,字典要放到內存裡面隨時讀取才快,那麼字典的數據結構就顯得十分重要了,既不能太大太佔空間,效率也不能太低,下圖列了一些常見詞典的優缺點:

FST是Lucene現在使用的索引結構

理論基礎:   《Direct construction of minimal acyclic subsequential transducers》,通過輸入有序字符串構建最小有向無環圖。

優點:內存佔用率低,壓縮率一般在3倍~20倍之間、模糊查詢支持好、查詢快

缺點:結構複雜、輸入要求有序、更新不易 Lucene裡有個FST的實現,從對外接口上看,它跟Map結構很相似,有查找,有迭代

100萬數據性能測試:

數據結構HashMapTreeMapFST構建時間(ms)1855001512查詢所有key(ms)106218890

可以看出,FST性能基本跟HaspMap差距不大,但FST有個不可比擬的優勢就是佔用內存小,只有HashMap10分之一左右,這對大數據規模檢索是至關重要的,畢竟速度再快放不進內存也是沒用的。因此一個合格的詞典結構要求有:

查詢速度。

內存佔用。

內存+磁碟結合。

所以最終的樣子如下,Term dict index以FST的結構存緩存在內存中,從Term dict index查到關鍵詞對應的term dic的塊位置之後,再去磁碟上找term,大大減少了磁碟的IO次數。

數據分段

搞定了索引之後,再來看看數據是怎麼存儲的,試想一下如果所有數據(新華字典中所有的字)都存在一個文件中,如果數據有更新或者刪除(比如新增加一個字或者刪除一個字),那麼所有的索引都需要全量重新創建,這種方式在數據量很大時效率很低,並且由於創建一次索引的成本很高,所以對數據的更新不能過於頻繁,也就不能保證時效性。

Lucene在搜索中引入了段(Segment)的概念(將一個索引文件拆分為多個子文件,每個子文件叫作段),每個段都是一個獨立的可被搜索的數據集,並且段具有不變性,一旦索引的數據被寫入硬碟,就不可再修改。

在分段的思想下,對數據寫操作的過程如下。

新增。當有新的數據需要創建索引時,由於段的不變性,所以選擇新建一個段來存儲新增的數據。

刪除。當需要刪除數據時,由於數據所在的段只可讀,不可寫,所以Lucene在索引文件下新增了一個.del的文件,用來專門存儲被刪除的數據id。當查詢時,被刪除的數據還是可以被查到的,只是在進行文檔鍊表合併時,才把已經刪除的數據過濾掉。被刪除的數據在進行段合併時才會真正被移除

更新。更新的操作其實就是刪除和新增的組合,先在.del文件中記錄舊數據,再在新段中添加一條更新後的數據。

段不可變的優點

段不變性的優點如下:

不需要鎖。因為數據不會更新,所以不用考慮多線程下的讀寫不一致情況。

可以常駐內存。段在被加載到內存後,由於具有不變性,所以只要內存的空間足夠大,就可以長時間駐存,大部分查詢請求會直接訪問內存,而不需要訪問磁碟,使得查詢的性能有很大的提升。

緩存友好。在段的生命周期內始終有效,不需要在每次數據更新時被重建。

增量創建。分段可以做到增量創建索引,可以輕量級地對數據進行更新,由於每次創建的成本很低,所以可以頻繁地更新數據,使系統接近實時更新。


段不可變的缺點

當對數據進行刪除時,舊數據不會被馬上刪除,而是在.del文件中被標記為刪除。而舊數據只能等到段更新時才能真正被移除,這樣會有大量的空間浪費

更新。更新數據由刪除和新增這兩個動作組成。若有一條數據頻繁更新,則會有大量的空間浪費

由於索引具有不變性,所以每次新增數據時,都需要新增一個段來存儲數據。當段的數量太多時,對伺服器的資源(如文件句柄)的消耗會非常大,查詢的性能也會受到影響。

在查詢後需要對已經刪除的舊數據進行過濾,這增加了查詢的負擔

延遲寫策略

為了提升寫的性能,Lucene並沒有每新增一條數據就增加一個段,而是採用延遲寫的策略,每當有新增的數據時,就將其先寫入內存中,然後批量寫入磁碟中。若有一個段被寫到硬碟,就會生成一個提交點,提交點就是一個用來記錄所有提交後的段信息的文件。一個段一旦擁有了提交點,就說明這個段只有讀的權限,失去了寫的權限

相反,當段在內存中時,就只有寫數據的權限,而不具備讀數據的權限,所以也就不能被檢索了。從嚴格意義上來說,Lucene或者Elasticsearch並不能被稱為實時的搜尋引擎,只能被稱為準實時的搜尋引擎。

寫索引的流程如下:

新數據被寫入時,並沒有被直接寫到硬碟中,而是被暫時寫到內存中。Lucene默認是一秒鐘,或者當內存中的數據量達到一定階段時,再批量提交到磁碟中,當然,默認的時間和數據量的大小是可以通過參數控制的。通過延時寫的策略,可以減少數據往磁碟上寫的次數,從而提升整體的寫入性能。如下圖所示。

在達到觸發條件以後,會將內存中緩存的數據一次性寫入磁碟中,並生成提交點。清空內存,等待新的數據寫入。如圖8所示。

分段合併

合併原因:雖然分段比每次都全量創建索引有更高的效率,但由於在每次新增數據時都會新增一個段,所以經過長時間的積累,會導致在索引中存在大量的段,當索引中段的數量太多時,不僅會嚴重消耗伺服器的資源,還會影響檢索的性能。

因為索引檢索的過程是:查詢所有段中滿足查詢條件的數據,然後對每個段裡查詢的結果集進行合併,所以為了控制索引裡段的數量,我們必須定期進行段合併操作。但是如果每次合併全部的段,則將造成很大的資源浪費,特別是"大段"的合併。

所以Lucene現在的段合併思路是:根據段的大小先將段進行分組,再將屬於同一組的段進行合併。但是由於對超級大的段的合併需要消耗更多的資源,所以Lucene會在段的大小達到一定規模,或者段裡面的數據量達到一定條數時,不會再進行合併。所以Lucene的段合併主要集中在對中小段的合併上,這樣既可以避免對大段進行合併時消耗過多的伺服器資源,也可以很好地控制索引中段的數量。

總結

反向索引:Lucene 採用了基於反向索引的設計原理,可以非常高效地實現文本查找

數據分段:在底層採用了數據分段的存儲模式,分段是只讀的,使它在讀寫時幾乎完全避免了鎖的出現,大大提升了讀寫性能。

參考

Apache Lucene Core

5分鐘了解lucene全文索引

Lucene段概念

lucene搜索原理

ElasticSearch底層搜尋引擎Lucene原理剖析

Lucene底層原理和優化經驗分享(1)-Lucene簡介和索引原理

掌握它才說明你真正懂 Elasticsearch - Lucene (一)

使用Lucene在知識圖譜上構建索引

相關焦點

  • 8 個基於 Lucene 的開源搜尋引擎 - OSCHINA - 中文開源技術交流社區
    Lucene是一種功能強大且被廣泛使用的搜尋引擎,以下列出8種基於Lucene的搜尋引擎,你可以想像他們有多麼強大...
  • 搜尋引擎Lucene的秘密,在10W篇文章中的表現如何?全文檢索 VS 順序查找
    簡介之前說過搜尋引擎Lucene的原理,詳情可見5分鐘了解搜尋引擎Lucene的原理,
  • Lucene 5.1.0 發布,Java 搜尋引擎
    Lucene 5.1.0 發布,此版本現已提供在:http://www.apache.org/dyn/closer.cgi/lucene
  • Apache Lucene 6.4.0 發布,Java 搜尋引擎
    Lucene最初是由Doug Cutting所撰寫的,是一位資深全文索引/檢索專家,曾經是V-Twin搜尋引擎的主要開發者,後來在Excite擔任高級系統架構設計師,目前從事 於一些INTERNET底層架構的研究。他貢獻出Lucene的目標是為各種中小型應用程式加入全文檢索功能。
  • 面試官是怎麼來考察你對ES搜尋引擎的理解?
    面試官心理分析問這個,其實面試官就是要看看你了解不了解 es 的一些基本原理,因為用 es 無非就是寫入數據,搜索數據。你要是不明白你發起一個寫入和搜索請求的時候,es 在幹什麼,那你真的是......對 es 基本就是個黑盒,你還能幹啥?你唯一能幹的就是用 es 的 api 讀寫數據了。
  • 搜尋引擎的工作原理:了解抓取工具所需的一切
    儘管Google和其他搜尋引擎都對搜索結果背後的機制保密,但營銷人員卻從了解搜尋引擎的工作原理中受益。了解搜尋引擎如何查找,組織和選擇結果意味著您可以更好地優化網頁排名。一、搜尋引擎的工作原理:基礎知識「搜尋引擎」是幾種相互關聯的機制,這些機制可以根據您在搜索欄中輸入的文字一起識別網頁內容(圖像,視頻,網站頁面等)。
  • 搜尋引擎工作原理——排名
    這只是為了簡化的說明原理而已,實際上還是可以看到只包含一部分關鍵詞的搜索結果。另外用戶輸入的查詢詞中還可能包含一些高級搜索指令(以後文章裡會提及),如加號。減號等。搜尋引擎都需要做出相應識別和相應處理。(4)、拼寫錯誤矯正。用戶如果輸入了明顯錯誤的字或英文單詞拼錯,搜尋引擎會提示用戶正確的用字和拼法。
  • Lucene集成IK Analyzer中文分詞器
    4.採用了多子處理器分析模式,支持:英文字母、數字、中文詞彙等分詞處理,兼容韓文、日文字符5.優化的詞典存儲,更小的內存佔用。支持用戶詞典擴展定義。特別的,在2012版本,詞典支持中文,英文,數字混合詞語。
  • 什麼是搜尋引擎蜘蛛?工作原理是什麼?
    通過昨天的分享,我們知道了如何發布文章更容易被搜尋引擎收錄,我們同時提到了「蜘蛛」這個程序,今天帶大家認識一下搜尋引擎蜘蛛。1、搜尋引擎蜘蛛介紹網絡爬蟲,是一種負責收集網絡信息的程序,每個搜尋引擎都配有蜘蛛程序。
  • 產品經理學技術:搜尋引擎工作原理
    在網際網路時代,搜尋引擎可以說是日常生活的一部分。不僅如此,搜尋引擎歷經20多年的風霜雨雪,仍然牢牢佔據著流量入口,不得不讓人感嘆。而且,提起搜尋引擎,我們都會想到一家高大上的巨無霸公司和一家被黑出xiang的巨霸公司。足以見得搜尋引擎的巨大作用。作為產品人,對此當然不能視而不見,也應該了解了解其工作原理。
  • 搜尋引擎基本原理
    如,早期的AltaVista.連結分析。典型:Google的PageRank,極大擴充了網頁內容,質量有提高,隨之而來各種作弊方法。用戶為中心?現在的大部分搜尋引擎對相同查詢返回相同的結果,但是不同用戶可能關注不一樣,未來也許更多考慮用戶的差異性。
  • 搜尋引擎優化:搜尋引擎原理,分詞技術解析,中文搜索排名核心
    搜尋引擎對中文頁面就是這樣通過中文分詞來理解網頁所描述的內容。搜尋引擎會使用自己強大的詞庫來對網頁內容進行拆分,或者對內容進行機械切割,統計出現次數最多的詞,進而判斷該網頁是幹什麼的。很多SEO的工作人員知道分詞技術卻不知道分詞技術的原理,以及不明白如何將該技術運用到實際操作中。
  • LucenePlus 改版正式歸來、初步滿足,簡、易、穩、快
    lucenePlus 改名為 lucenex 短的好記lucenex基於JDK 1.8 &
  • 搜尋引擎蜘蛛(爬蟲)工作過程及原理
    什麼是搜尋引擎爬蟲,搜尋引擎爬蟲是如何工作的。搜尋引擎爬蟲也叫做搜尋引擎蜘蛛,是用來抓取網頁信息的,搜尋引擎抓取過程分為大致五個步驟。#Python爬蟲#分別是:抓取 → 存放 → 甄別 → 收錄 → 權重衡量分配排名搜尋引擎蜘蛛首先會抓取網頁信息
  • 「萬能」的搜尋引擎
    每當我們需要查什麼資料或者新聞的時候,都會打開搜尋引擎,輸入詞組就可以直接搜出自己想要的內容。搜尋引擎不但能搜索出海量內容,而且搜索速度很快。它到底是怎麼工作的呢?搜尋引擎是逐個打開檢索的網頁嗎?就算搜尋引擎的伺服器1秒鐘能夠打開並檢索1萬個網頁,這五百億的網頁就需要檢索將近兩個月。我們為了得到一個信息居然要等兩個月,這顯然不是搜尋引擎伺服器的工作方式。伺服器能夠快速得出結果,是因為它利用了「關鍵詞索引」。伺服器會將所有網頁掃描一遍,然後為網頁中的每個詞語都建立一個跟這個詞語有關的關鍵詞索引。
  • Nut 19.2 發布,Lucene+Hadoop 分布式運行框架
    Nut 是一個為lucene提供分布式搜索的框架。理論上可對千G以上索引文件支持數千萬級的用戶搜索訪問。Nut由Client、Server、Cache和DB四 部分構成。Client處理用戶請求和對搜索結果排序。Server對請求進行搜索,Server上只放索引,數據存儲在DB中,Nut將索引和存儲分 離。Cache緩存的是搜索條件和結果文檔id。
  • 5分鐘了解什麼是自然語言處理技術
    *本文約3000字,閱讀大約需要5分鐘。自然語言處理(Nature Language Processing,NLP)被譽為「人工智慧技術皇冠上的明珠」,一方面表明了它的重要性,另一方面也顯現出了它的技術難度。但NLP並不像語音識別、圖像識別等人工智慧技術一樣為人熟知,接下來的5分鐘,我們來快速了解NLP技術,感受它的魅力。
  • seamSearch:一個簡單的nodejs版本開源全文搜尋引擎
    這幾年nodejs越來越火爆,js程式設計師們終於可以不局限於瀏覽器那一畝三分地了,很多以前由java,c等實現的東西紛紛有了nodejs版本,我也隨波逐流一把,寫了一個nodejs的搜尋引擎addon,現在已經放GitHub: https://github.com/luyongfugx/seamSearch這個開源addon其實是對我幾年前寫的c++ 版的