国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Lucene解析 - 基本概念

sunnyxd / 397人閱讀

摘要:基本概念在深入解讀之前,先了解下的幾個基本概念,以及這幾個概念背后隱藏的一些東西。如圖是一個內的基本組成,內數據只是一個抽象表示,不代表其內部真實數據結構。即詞典,是根據條件查找的基本索引。

前言

Apache Lucene是一個開源的高性能、可擴展的信息檢索引擎,提供了強大的數據檢索能力。Lucene已經發展了很多年,其功能越來越強大,架構也越來越精細。它目前不僅僅能支持全文索引,也能夠提供多種其他類型的索引方式,來滿足不同類型的查詢需求。

基于Lucene的開源項目有很多,最知名的要屬Elasticsearch和Solr,如果說Elasticsearch和Solr是一輛設計精美、性能卓越的跑車,那Lucene就是為其提供強大動力的引擎。為了駕馭這輛跑車讓它跑的更快更穩定,我們需要對它的引擎研究透徹。

在此之前我們在專欄已經發表了多篇文章來剖析Elasticsearch的數據模型、讀寫路徑、分布式架構以及Data/Meta一致性等問題,這篇文章之后我們會陸續發表一系列的關于Lucene的原理和源碼解讀,來全面解析Lucene的數據模型和數據讀寫路徑。

Lucene官方對自己的優勢總結為幾點:
Scalable, High-Performance Indexing
Powerful, Accurate and Efficient Search Algorithms
希望通過我們的系列文章,能夠讓讀者理解Lucene是如何達到這些目標的。

整個分析會基于Lucene 7.2.1版本,在讀這篇文章之前,需要有一定的知識基礎,例如了解基本的搜索和索引原理,知道什么是倒排、分詞、相關性等基本概念,了解Lucene的基本使用,例如Directory、IndexWriter、IndexSearcher等。

基本概念

在深入解讀Lucene之前,先了解下Lucene的幾個基本概念,以及這幾個概念背后隱藏的一些東西。

如圖是一個Index內的基本組成,Segment內數據只是一個抽象表示,不代表其內部真實數據結構。

Index(索引)
類似數據庫的表的概念,但是與傳統表的概念會有很大的不同。傳統關系型數據庫或者NoSQL數據庫的表,在創建時至少要定義表的Scheme,定義表的主鍵或列等,會有一些明確定義的約束。而Lucene的Index,則完全沒有約束。Lucene的Index可以理解為一個文檔收納箱,你可以往內部塞入新的文檔,或者從里面拿出文檔,但如果你要修改里面的某個文檔,則必須先拿出來修改后再塞回去。這個收納箱可以塞入各種類型的文檔,文檔里的內容可以任意定義,Lucene都能對其進行索引。

Document(文檔)
類似數據庫內的行或者文檔數據庫內的文檔的概念,一個Index內會包含多個Document。寫入Index的Document會被分配一個唯一的ID,即Sequence Number(更多被叫做DocId),關于Sequence Number后面會再細說。

Field(字段)
一個Document會由一個或多個Field組成,Field是Lucene中數據索引的最小定義單位。Lucene提供多種不同類型的Field,例如StringField、TextField、LongFiled或NumericDocValuesField等,Lucene根據Field的類型(FieldType)來判斷該數據要采用哪種類型的索引方式(Invert Index、Store Field、DocValues或N-dimensional等),關于Field和FieldType后面會再細說。

Term和Term Dictionary
Lucene中索引和搜索的最小單位,一個Field會由一個或多個Term組成,Term是由Field經過Analyzer(分詞)產生。Term Dictionary即Term詞典,是根據條件查找Term的基本索引。

Segment
一個Index會由一個或多個sub-index構成,sub-index被稱為Segment。Lucene的Segment設計思想,與LSM類似但又有些不同,繼承了LSM中數據寫入的優點,但是在查詢上只能提供近實時而非實時查詢。

Lucene中的數據寫入會先寫內存的一個Buffer(類似LSM的MemTable,但是不可讀),當Buffer內數據到一定量后會被flush成一個Segment,每個Segment有自己獨立的索引,可獨立被查詢,但數據永遠不能被更改。這種模式避免了隨機寫,數據寫入都是Batch和Append,能達到很高的吞吐量。Segment中寫入的文檔不可被修改,但可被刪除,刪除的方式也不是在文件內部原地更改,而是會由另外一個文件保存需要被刪除的文檔的DocID,保證數據文件不可被修改。Index的查詢需要對多個Segment進行查詢并對結果進行合并,還需要處理被刪除的文檔,為了對查詢進行優化,Lucene會有策略對多個Segment進行合并,這點與LSM對SSTable的Merge類似。

Segment在被flush或commit之前,數據保存在內存中,是不可被搜索的,這也就是為什么Lucene被稱為提供近實時而非實時查詢的原因。讀了它的代碼后,發現它并不是不能實現數據寫入即可查,只是實現起來比較復雜。原因是Lucene中數據搜索依賴構建的索引(例如倒排依賴Term Dictionary),Lucene中對數據索引的構建會在Segment flush時,而非實時構建,目的是為了構建最高效索引。當然它可引入另外一套索引機制,在數據實時寫入時即構建,但這套索引實現會與當前Segment內索引不同,需要引入額外的寫入時索引以及另外一套查詢機制,有一定復雜度。

Sequence Number
Sequence Number(后面統一叫DocId)是Lucene中一個很重要的概念,數據庫內通過主鍵來唯一標識一行,而Lucene的Index通過DocId來唯一標識一個Doc。不過有幾點要特別注意:
DocId實際上并不在Index內唯一,而是Segment內唯一,Lucene這么做主要是為了做寫入和壓縮優化。那既然在Segment內才唯一,又是怎么做到在Index級別來唯一標識一個Doc呢?方案很簡單,Segment之間是有順序的,舉個簡單的例子,一個Index內有兩個Segment,每個Segment內分別有100個Doc,在Segment內DocId都是0-100,轉換到Index級的DocId,需要將第二個Segment的DocId范圍轉換為100-200。
DocId在Segment內唯一,取值從0開始遞增。但不代表DocId取值一定是連續的,如果有Doc被刪除,那可能會存在空洞。
一個文檔對應的DocId可能會發生變化,主要是發生在Segment合并時。

Lucene內最核心的倒排索引,本質上就是Term到所有包含該Term的文檔的DocId列表的映射。所以Lucene內部在搜索的時候會是一個兩階段的查詢,第一階段是通過給定的Term的條件找到所有Doc的DocId列表,第二階段是根據DocId查找Doc。Lucene提供基于Term的搜索功能,也提供基于DocId的查詢功能。

DocId采用一個從0開始底層的Int32值,是一個比較大的優化,同時體現在數據壓縮和查詢效率上。例如數據壓縮上的Delta策略、ZigZag編碼,以及倒排列表上采用的SkipList等,這些優化后續會詳述。

索引類型

Lucene中支持豐富的字段類型,每種字段類型確定了支持的數據類型以及索引方式,目前支持的字段類型包括LongPoint、TextField、StringField、NumericDocValuesField等。

如圖是Lucene中對于不同類型Field定義的一個基本關系,所有字段類都會繼承自Field這個類,Field包含3個重要屬性:name(String)、fieldsData(BytesRef)和type(FieldType)。name即字段的名稱,fieldsData即字段值,所有類型的字段的值最終都會轉換為二進制字節流來表示。type是字段類型,確定了該字段被索引的方式。
FieldType是一個很重要的類,包含多個重要屬性,這些屬性的值決定了該字段被索引的方式。
Lucene提供的多種不同類型的Field,本質區別就兩個:一是不同類型值到fieldData定義了不同的轉換方式;二是定義了FieldType內不同屬性不同取值的組合。這種模式下,你也能夠通過自定義數據以及組合FieldType內索引參數來達到定制類型的目的。
要理解Lucene能夠提供哪些索引方式,只需要理解FieldType內每個屬性的具體含義,我們來一個一個看:
stored: 代表是否需要保存該字段,如果為false,則lucene不會保存這個字段的值,而搜索結果中返回的文檔只會包含保存了的字段。
tokenized: 代表是否做分詞,在lucene中只有TextField這一個字段需要做分詞。
termVector: 這篇文章很好的解釋了term vector的概念,簡單來說,term vector保存了一個文檔內所有的term的相關信息,包括Term值、出現次數(frequencies)以及位置(positions)等,是一個per-document inverted index,提供了根據docid來查找該文檔內所有term信息的能力。對于長度較小的字段不建議開啟term verctor,因為只需要重新做一遍分詞即可拿到term信息,而針對長度較長或者分詞代價較大的字段,則建議開啟term vector。Term vector的用途主要有兩個,一是關鍵詞高亮,二是做文檔間的相似度匹配(more-like-this)。
omitNorms: Norms是normalization的縮寫,lucene允許每個文檔的每個字段都存儲一個normalization factor,是和搜索時的相關性計算有關的一個系數。Norms的存儲只占一個字節,但是每個文檔的每個字段都會獨立存儲一份,且Norms數據會全部加載到內存。所以若開啟了Norms,會消耗額外的存儲空間和內存。但若關閉了Norms,則無法做index-time boosting(elasticsearch官方建議使用query-time boosting來替代)以及length normalization。
indexOptions: Lucene提供倒排索引的5種可選參數(NONE、DOCS、DOCS_AND_FREQS、DOCS_AND_FREQS_AND_POSITIONS、DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS),用于選擇該字段是否需要被索引,以及索引哪些內容。
docValuesType: DocValue是Lucene 4.0引入的一個正向索引(docid到field的一個列存),大大優化了sorting、faceting或aggregation的效率。DocValues是一個強schema的存儲結構,開啟DocValues的字段必須擁有嚴格一致的類型,目前Lucene只提供NUMERIC、BINARY、SORTED、SORTED_NUMERIC和SORTED_SET五種類型。
dimension:Lucene支持多維數據的索引,采取特殊的索引來優化對多維數據的查詢,這類數據最典型的應用場景是地理位置索引,一般經緯度數據會采取這個索引方式。

來看下Lucene中對StringField的一個定義:

StringFiled有兩種類型索引定義,TYPE_NOT_STORED和TYPE_STORED,唯一的區別是這個Field是否需要Store。從其他的幾個屬性也可以解讀出,StringFiled選擇omitNorms,需要進行倒排索引并且不需要被分詞。

Elasticsearch數據類型

Elasticsearch內對用戶輸入文檔內Field的索引,也是按照Lucene能提供的幾種模式來提供。除了用戶能自定義的Field,Elasticsearch還有自己預留的系統字段,用作一些特殊的目的。這些字段映射到Lucene本質上也是一個Field,與用戶自定義的Field無任何區別,只不過Elasticsearch根據這些系統字段不同的使用目的,定制有不同的索引方式。

舉個例子,上圖?是Elasticsearch內兩個系統字段_version和_uid的FieldType定義,我們來解讀下它們的索引方式。Elasticsearch通過_uid字段唯一標識一個文檔,通過_version字段來記錄該文檔當前的版本。從這兩個字段的FieldType定義上可以看到,_uid字段會做倒排索引,不需要分詞,需要被Store。而_version字段則不需要被倒排索引,也不需要被Store,但是需要被正排索引。很好理解,因為_uid需要被搜索,而_version不需要。但_version需要通過docId來查詢,而且Elasticsearch內versionMap內需要通過docId做大量查詢且只需要查詢出_version字段,所以_version最合適的是被正排索引。

關于Elasticsearch內系統字段全面的解析,可以看下這篇文章。

總結

這篇文章主要介紹了Lucene的一些基本概念以及提供的索引類型。后續我們會有一系列文章來解析Lucene提供的IndexWriter的寫入流程,其In-Memory Buffer的結構以及持久化后的索引文件結構,來了解Lucene為何能達到如此高效的數據索引性能。也會去解析IndexSearcher的查詢流程,以及一些特殊的查詢優化的數據結構,來了解為何Lucene能提供如此高效的搜索和查詢。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94419.html

相關文章

  • Lucene解析 - 基本概念

    摘要:基本概念在深入解讀之前,先了解下的幾個基本概念,以及這幾個概念背后隱藏的一些東西。如圖是一個內的基本組成,內數據只是一個抽象表示,不代表其內部真實數據結構。即詞典,是根據條件查找的基本索引。 前言 Apache Lucene是一個開源的高性能、可擴展的信息檢索引擎,提供了強大的數據檢索能力。Lucene已經發展了很多年,其功能越來越強大,架構也越來越精細。它目前不僅僅能支持全文索引,也...

    appetizerio 評論0 收藏0
  • Lucene構建個人搜索引擎解析

    摘要:倒排索引是基于詞的搜索。關于倒排索引要學習搜索引擎,就需要了解倒排索引,要更加深刻地理解倒排索引,就要先了解什么是正排索引表。由于不是由記錄來確定屬性值,而是由屬性值來確定記錄的位置,因而稱為倒排索引。 Lucene是什么? Lucene是apache軟件基金會4 jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具包,但它不是一個完整的全文檢索引擎,而是一個全文檢索引...

    wenshi11019 評論0 收藏0
  • Lucene 查詢原理

    摘要:介紹如何優化數值類范圍查詢。查詢過程在中查詢是基于。在中為了查詢的這樣一個條件,會建立基于的倒排鏈。在單查詢上可能相比并沒有明顯優勢,甚至會慢一些。所以為了支持高效的數值類或者多維度查詢,引入類。 前言 Lucene 是一個基于 Java 的全文信息檢索工具包,目前主流的搜索系統Elasticsearch和solr都是基于lucene的索引和搜索能力進行。想要理解搜索系統的實現原理,就...

    FullStackDeveloper 評論0 收藏0

發表評論

0條評論

sunnyxd

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<