一. ElasticSearch 與 Lucene 的關(guān)系
Elasticsearch(ES)和Apache Lucene之間有密切的關(guān)系,可以總結(jié)如下:
-
Elasticsearch構(gòu)建于Lucene之上:Elasticsearch實際上是一個分布式的、實時的搜索和分析引擎,它構(gòu)建在Apache Lucene搜索引擎庫的基礎(chǔ)上。Lucene提供了全文搜索和索引功能,而Elasticsearch在此基礎(chǔ)上構(gòu)建了更多功能,如分布式性能、實時數(shù)據(jù)索引、聚合分析、RESTful API等。
-
Elasticsearch的高級功能:Elasticsearch擴(kuò)展了Lucene,并提供了一種更高級的搜索和分析功能。它支持JSON文檔存儲,分布式架構(gòu),復(fù)雜的查詢語言,實時索引等。
-
簡化的API:Elasticsearch提供了一個簡化的RESTful API,使其更易于使用和集成到應(yīng)用程序中。這使得開發(fā)人員能夠輕松地構(gòu)建搜索和分析功能,而無需深入了解Lucene的復(fù)雜性。
-
分布式和水平擴(kuò)展:Elasticsearch專注于分布式搜索和分析,可以輕松擴(kuò)展到數(shù)百臺甚至數(shù)千臺服務(wù)器。這使得它成為大規(guī)模數(shù)據(jù)處理和分析的有力工具。
-
動態(tài)索引:Elasticsearch具有實時索引功能,可以實時更新和檢索數(shù)據(jù),適用于大量數(shù)據(jù)的變化和分析。
1.1 結(jié)構(gòu)關(guān)系圖
Lucene是Apache下的一個子項目,是一個開放源代碼的全文檢索引擎工具包,但它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構(gòu),提供了完整的查詢引擎和索引引擎,它是ES實現(xiàn)全文檢索的核心基礎(chǔ),索引文檔以及搜索索引的的核心流程都是在Lucene中完成的。
1.2 整體處理流程
二. Apache Lucene 概述
2.1 Lucene介紹
Lucene是Apache下的一個開放源代碼的全文檢索引擎工具包。提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是為軟件開發(fā)人員提供一個簡單易用的工具包,以方便的在目標(biāo)系統(tǒng)中實現(xiàn)全文檢索的功能??梢允褂肔ucene實現(xiàn)全文檢索。
2.2 Lucene適用場景
這項技術(shù)幾乎適用于任何需要結(jié)構(gòu)化搜索、全文搜索、分面、跨高維向量的最近鄰搜索、拼寫糾正或查詢建議的應(yīng)用程序。
- 在應(yīng)用中為數(shù)據(jù)庫中的數(shù)據(jù)提供全文檢索實現(xiàn)。
- 開發(fā)獨立的搜索引擎服務(wù)、系統(tǒng)。
- 對于數(shù)據(jù)量大、數(shù)據(jù)結(jié)構(gòu)不固定的數(shù)據(jù)可采用全文檢索方式搜索。
2.3 Lucene功能
Lucene通過一個簡單的API提供了強(qiáng)大的功能。
1.可擴(kuò)展的高性能索引
- 在現(xiàn)代硬件上超過800GB/小時
- 小RAM要求——只有1MB堆
- 增量索引與批量索引一樣快
- 索引大小大約為索引文本大小的20-30%
2.強(qiáng)大、準(zhǔn)確、高效的搜索算法
- 排名搜索——最好的結(jié)果首先返回
- 許多強(qiáng)大的查詢類型:短語查詢、通配符查詢、鄰近查詢、范圍查詢等
- 現(xiàn)場搜索(例如標(biāo)題、作者、內(nèi)容)
- 高維向量的最近鄰搜索
- 按任何字段排序
- 合并結(jié)果的多索引搜索
- 允許同時更新和搜索
- 靈活的刻面、突出顯示、連接和結(jié)果分組
- 快速、節(jié)省內(nèi)存和容錯的建議器
- 可插拔排名模型,包括向量空間模型和Okapi BM25
- 可配置的存儲引擎(編解碼器)
3.跨平臺解決方案
- 可作為Apache許可證下的開源軟件,它允許您在商業(yè)和開源程序中使用Lucene
- 100%純Java
- 其他可用的與索引兼容的編程語言的實現(xiàn)
2.4 Lucene架構(gòu)
結(jié)構(gòu)化數(shù)據(jù)搜索與非結(jié)構(gòu)化數(shù)據(jù)搜索對比分析見下圖:?
搜索應(yīng)用程序和Lucene之間的關(guān)系,也反映了利用Lucene構(gòu)建搜索應(yīng)用程序的流程:
三. Lucene 基本概念
在深入解讀Lucene之前,先了解下Lucene的幾個基本概念,以及這幾個概念背后隱藏的一些內(nèi)容。
3.1 Index(索引)
類似數(shù)據(jù)庫的表的概念,但是與傳統(tǒng)表的概念會有很大的不同。傳統(tǒng)關(guān)系型數(shù)據(jù)庫或者NoSQL數(shù)據(jù)庫的表,在創(chuàng)建時至少要定義表的Scheme,定義表的主鍵或列等,會有一些明確定義的約束。而Lucene的Index,則完全沒有約束。Lucene的Index可以理解為一個文檔收納箱,你可以往內(nèi)部塞入新的文檔,或者從里面拿出文檔,但如果你要修改里面的某個文檔,則必須先拿出來修改后再塞回去。這個收納箱可以塞入各種類型的文檔,文檔里的內(nèi)容可以任意定義,Lucene都能對其進(jìn)行索引。
3.2 Document(文檔)
用戶提供的源是一條條記錄,它們可以是文本文件、字符串或者數(shù)據(jù)庫表的一條記錄等等。一條記錄經(jīng)過索引之后,就是以一個Document的形式存儲在索引文件中的。用戶進(jìn)行搜索,也是以Document列表的形式返回。
一個Index內(nèi)會包含多個Document。寫入Index的Document會被分配一個唯一的ID,即Sequence Number(序列號,更多被叫做DocId)。
3.3 Field(字段)
一個Document會由一個或多個Field組成,F(xiàn)ield是Lucene中數(shù)據(jù)索引的最小定義單位。Lucene提供多種不同類型的Field,例如StringField、TextField、LongFiled或NumericDocValuesField等,Lucene根據(jù)Field的類型(FieldType)來判斷該數(shù)據(jù)要采用哪種類型的索引方式(Invert Index、Store Field、DocValues或N-dimensional等)。
例如,一篇文章可以包含“標(biāo)題”、“正文”、“最后修改時間”等信息域,這些信息域就是通過Field在Document中存儲的。
Field有兩個屬性可選:存儲和索引。通過存儲屬性你可以控制是否對這個Field進(jìn)行存儲;通過索引屬性你可以控制是否對該Field進(jìn)行索引。
如果對標(biāo)題和正文進(jìn)行全文搜索,所以我們要把索引屬性設(shè)置為真,同時我們希望能直接從搜索結(jié)果中提取文章標(biāo)題,所以我們把標(biāo)題域的存儲屬性設(shè)置為真。但是由于正文域太大了,我們?yōu)榱丝s小索引文件大小,將正文域的存儲屬性設(shè)置為假,當(dāng)需要時再直接讀取文件;我們只是希望能從搜索解果中提取最后修改時間,不需要對它進(jìn)行搜索,所以我們把最后修改時間域的存儲屬性設(shè)置為真,索引屬性設(shè)置為假。上面的三個域涵蓋了兩個屬性的三種組合,還有一種全為假的沒有用到,事實上Field不允許你那么設(shè)置,因為既不存儲又不索引的域是沒有意義的。
3.4 Term和Term Dictionary
Lucene中索引和搜索的最小單位,一個Field會由一個或多個Term組成,Term是由Field經(jīng)過Analyzer(分詞)產(chǎn)生。Term Dictionary即Term詞典,是根據(jù)條件查找Term的基本索引。
Term由兩部分組成:它表示的詞語和這個詞語所出現(xiàn)的Field的名稱。
3.5 Segment(段)
一個Index會由一個或多個sub-index構(gòu)成,sub-index被稱為Segment。Lucene的Segment設(shè)計思想,與LSM類似但又有些不同,繼承了LSM中數(shù)據(jù)寫入的優(yōu)點,但是在查詢上只能提供近實時而非實時查詢。
Lucene中的數(shù)據(jù)寫入會先寫內(nèi)存的一個Buffer(類似LSM的MemTable,但是不可讀),當(dāng)Buffer內(nèi)數(shù)據(jù)到一定量后會被Flush成一個Segment,每個Segment有自己獨立的索引,可獨立被查詢,但數(shù)據(jù)永遠(yuǎn)不能被更改。這種模式避免了隨機(jī)寫,數(shù)據(jù)寫入都是Batch和Append,能達(dá)到很高的吞吐量。Segment中寫入的文檔不可被修改,但可被刪除,刪除的方式也不是在文件內(nèi)部原地更改,而是會由另外一個文件保存需要被刪除的文檔的DocID,保證數(shù)據(jù)文件不可被修改。Index的查詢需要對多個Segment進(jìn)行查詢并對結(jié)果進(jìn)行合并,還需要處理被刪除的文檔,為了對查詢進(jìn)行優(yōu)化,Lucene會有策略對多個Segment進(jìn)行合并,這點與LSM對SSTable的Merge類似。
Segment在被Flush或Commit之前,數(shù)據(jù)保存在內(nèi)存中,是不可被搜索的,這也就是為什么Lucene被稱為提供近實時而非實時查詢的原因。讀了它的代碼后,發(fā)現(xiàn)它并不是不能實現(xiàn)數(shù)據(jù)寫入即可查,只是實現(xiàn)起來比較復(fù)雜。原因是Lucene中數(shù)據(jù)搜索依賴構(gòu)建的索引(例如倒排依賴Term Dictionary),Lucene中對數(shù)據(jù)索引的構(gòu)建會在Segment Flush時,而非實時構(gòu)建,目的是為了構(gòu)建最高效索引。當(dāng)然它可引入另外一套索引機(jī)制,在數(shù)據(jù)實時寫入時即構(gòu)建,但這套索引實現(xiàn)會與當(dāng)前Segment內(nèi)索引不同,需要引入額外的寫入時索引以及另外一套查詢機(jī)制,有一定復(fù)雜度。
3.6 Sequence Number(序列號)
Sequence Number(后面統(tǒng)一叫DocId)是Lucene中一個很重要的概念,數(shù)據(jù)庫內(nèi)通過主鍵來唯一標(biāo)識一行記錄,而Lucene的Index通過DocId來唯一標(biāo)識一個Doc。不過有幾點要特別注意:
- DocId實際上并不在Index內(nèi)唯一,而是Segment內(nèi)唯一,Lucene這么做主要是為了做寫入和壓縮優(yōu)化。那既然在Segment內(nèi)才唯一,又是怎么做到在Index級別來唯一標(biāo)識一個Doc呢?方案很簡單,Segment之間是有順序的,舉個簡單的例子,一個Index內(nèi)有兩個Segment,每個Segment內(nèi)分別有100個Doc,在Segment內(nèi)DocId都是0-100,轉(zhuǎn)換到Index級的DocId,需要將第二個Segment的DocId范圍轉(zhuǎn)換為100-200。
- DocId在Segment內(nèi)唯一,取值從0開始遞增。但不代表DocId取值一定是連續(xù)的,如果有Doc被刪除,那可能會存在空洞。
- 一個文檔對應(yīng)的DocId可能會發(fā)生變化,主要是發(fā)生在Segment合并時。
Lucene內(nèi)最核心的倒排索引,本質(zhì)上就是Term到所有包含該Term的文檔的DocId列表的映射。所以Lucene內(nèi)部在搜索的時候會是一個兩階段的查詢,第一階段是通過給定的Term的條件找到所有Doc的DocId列表,第二階段是根據(jù)DocId查找Doc。Lucene提供基于Term的搜索功能,也提供基于DocId的查詢功能。
DocId采用一個從0開始底層的Int32值,是一個比較大的優(yōu)化,同時體現(xiàn)在數(shù)據(jù)壓縮和查詢效率上。例如數(shù)據(jù)壓縮上的Delta策略、ZigZag編碼,以及倒排列表上采用的SkipList等,這些優(yōu)化后續(xù)會詳述。?文章來源:http://www.zghlxwxcb.cn/news/detail-765928.html
感謝您的閱讀,別忘了點贊、關(guān)注、收藏一波~ Thanks?(?ω?)? ??文章來源地址http://www.zghlxwxcb.cn/news/detail-765928.html
到了這里,關(guān)于ElasticSearch與Lucene是什么關(guān)系?Lucene又是什么?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!