最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Elasticsearch 基礎(chǔ)介紹及索引原理分析

 更新時間:2019年07月24日 09:30:58   作者:神一樣的存在  
這篇文章主要介紹了Elasticsearch 基礎(chǔ)介紹及索引原理分析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

前言

最近在參與一個基于Elasticsearch作為底層數(shù)據(jù)框架提供大數(shù)據(jù)量(億級)的實時統(tǒng)計查詢的方案設(shè)計工作,花了些時間學習Elasticsearch的基礎(chǔ)理論知識,整理了一下,希望能對Elasticsearch感興趣/想了解的同學有所幫助。 同時也希望有發(fā)現(xiàn)內(nèi)容不正確或者有疑問的地方,望指明,一起探討,學習,進步。

介紹

Elasticsearch 是一個分布式可擴展的實時搜索和分析引擎,一個建立在全文搜索引擎 Apache Lucene(TM) 基礎(chǔ)上的搜索引擎.當然 Elasticsearch 并不僅僅是 Lucene 那么簡單,它不僅包括了全文搜索功能,還可以進行以下工作:

  • 分布式實時文件存儲,并將每一個字段都編入索引,使其可以被搜索。
  • 實時分析的分布式搜索引擎。
  • 可以擴展到上百臺服務(wù)器,處理PB級別的結(jié)構(gòu)化或非結(jié)構(gòu)化數(shù)據(jù)。

基本概念

先說Elasticsearch的文件存儲,Elasticsearch是面向文檔型數(shù)據(jù)庫,一條數(shù)據(jù)在這里就是一個文檔,用JSON作為文檔序列化的格式,比如下面這條用戶數(shù)據(jù):

{
  "name" :   "John",
  "sex" :   "Male",
  "age" :   25,
  "birthDate": "1990/05/01",
  "about" :  "I love to go rock climbing",
  "interests": [ "sports", "music" ]
}

用Mysql這樣的數(shù)據(jù)庫存儲就會容易想到建立一張User表,有balabala的字段等,在Elasticsearch里這就是一個文檔,當然這個文檔會屬于一個User的類型,各種各樣的類型存在于一個索引當中。這里有一份簡易的將Elasticsearch和關(guān)系型數(shù)據(jù)術(shù)語對照表:

關(guān)系數(shù)據(jù)庫   ⇒ 數(shù)據(jù)庫 ⇒ 表  ⇒ 行  ⇒ 列(Columns)

Elasticsearch ⇒ 索引(Index)  ⇒ 類型(type) ⇒ 文檔(Docments) ⇒ 字段(Fields) 

一個 Elasticsearch 集群可以包含多個索引(數(shù)據(jù)庫),也就是說其中包含了很多類型(表)。這些類型中包含了很多的文檔(行),然后每個文檔中又包含了很多的字段(列)。Elasticsearch的交互,可以使用Java API,也可以直接使用HTTP的Restful API方式,比如我們打算插入一條記錄,可以簡單發(fā)送一個HTTP的請求:

PUT /megacorp/employee/1 
{
  "name" :   "John",
  "sex" :   "Male",
  "age" :   25,
  "about" :  "I love to go rock climbing",
  "interests": [ "sports", "music" ]
}

更新,查詢也是類似這樣的操作,具體操作手冊可以參見Elasticsearch權(quán)威指南

索引

Elasticsearch最關(guān)鍵的就是提供強大的索引能力了,其實InfoQ的這篇文章寫的非常好,我這里也是圍繞這篇結(jié)合自己的理解進一步梳理下,也希望可以幫助大家更好的理解這篇文章。

Elasticsearch索引的精髓:

一切設(shè)計都是為了提高搜索的性能

另一層意思:為了提高搜索的性能,難免會犧牲某些其他方面,比如插入/更新,否則其他數(shù)據(jù)庫不用混了。前面看到往Elasticsearch里插入一條記錄,其實就是直接PUT一個json的對象,這個對象有多個fields,比如上面例子中的name, sex, age, about, interests,那么在插入這些數(shù)據(jù)到Elasticsearch的同時,Elasticsearch還默默1的為這些字段建立索引--倒排索引,因為Elasticsearch最核心功能是搜索。

Elasticsearch是如何做到快速索引的

InfoQ那篇文章里說Elasticsearch使用的倒排索引比關(guān)系型數(shù)據(jù)庫的B-Tree索引快,為什么呢?

什么是B-Tree索引?

上大學讀書時老師教過我們,二叉樹查找效率是logN,同時插入新的節(jié)點不必移動全部節(jié)點,所以用樹型結(jié)構(gòu)存儲索引,能同時兼顧插入和查詢的性能。因此在這個基礎(chǔ)上,再結(jié)合磁盤的讀取特性(順序讀/隨機讀),傳統(tǒng)關(guān)系型數(shù)據(jù)庫采用了B-Tree/B+Tree這樣的數(shù)據(jù)結(jié)構(gòu):

為了提高查詢的效率,減少磁盤尋道次數(shù),將多個值作為一個數(shù)組通過連續(xù)區(qū)間存放,一次尋道讀取多個數(shù)據(jù),同時也降低樹的高度。

什么是倒排索引?

繼續(xù)上面的例子,假設(shè)有這么幾條數(shù)據(jù)(為了簡單,去掉about, interests這兩個field):

| ID | Name | Age | Sex   |
| -- |:------------:| -----:| -----:| 
| 1 | Kate     | 24 | Female
| 2 | John     | 24 | Male
| 3 | Bill     | 29 | Male

ID是Elasticsearch自建的文檔id,那么Elasticsearch建立的索引如下:

Name:

| Term | Posting List |
| -- |:----:|
| Kate | 1 |
| John | 2 |
| Bill | 3 |

Age:

| Term | Posting List |
| -- |:----:|
| 24 | [1,2] |
| 29 | 3 |

Sex:

| Term | Posting List |
| -- |:----:|
| Female | 1 |
| Male | [2,3] |

Posting List

Elasticsearch分別為每個field都建立了一個倒排索引,Kate, John, 24, Female這些叫term,而[1,2]就是Posting List。Posting list就是一個int的數(shù)組,存儲了所有符合某個term的文檔id。

看到這里,不要認為就結(jié)束了,精彩的部分才剛開始...

通過posting list這種索引方式似乎可以很快進行查找,比如要找age=24的同學,愛回答問題的小明馬上就舉手回答:我知道,id是1,2的同學。但是,如果這里有上千萬的記錄呢?如果是想通過name來查找呢?

Term Dictionary

Elasticsearch為了能快速找到某個term,將所有的term排個序,二分法查找term,logN的查找效率,就像通過字典查找一樣,這就是Term Dictionary?,F(xiàn)在再看起來,似乎和傳統(tǒng)數(shù)據(jù)庫通過B-Tree的方式類似啊,為什么說比B-Tree的查詢快呢?

Term Index

B-Tree通過減少磁盤尋道次數(shù)來提高查詢性能,Elasticsearch也是采用同樣的思路,直接通過內(nèi)存查找term,不讀磁盤,但是如果term太多,term dictionary也會很大,放內(nèi)存不現(xiàn)實,于是有了Term Index,就像字典里的索引頁一樣,A開頭的有哪些term,分別在哪頁,可以理解term index是一顆樹:

這棵樹不會包含所有的term,它包含的是term的一些前綴。通過term index可以快速地定位到term dictionary的某個offset,然后從這個位置再往后順序查找。

所以term index不需要存下所有的term,而僅僅是他們的一些前綴與Term Dictionary的block之間的映射關(guān)系,再結(jié)合FST(Finite State Transducers)的壓縮技術(shù),可以使term index緩存到內(nèi)存中。從term index查到對應(yīng)的term dictionary的block位置之后,再去磁盤上找term,大大減少了磁盤隨機讀的次數(shù)。

這時候愛提問的小明又舉手了:"那個FST是神馬東東啊?"

一看就知道小明是一個上大學讀書的時候跟我一樣不認真聽課的孩子,數(shù)據(jù)結(jié)構(gòu)老師一定講過什么是FST。但沒辦法,我也忘了,這里再補下課:

FSTs are finite-state machines that map a term (byte sequence) to an arbitrary output.

假設(shè)我們現(xiàn)在要將mop, moth, pop, star, stop and top(term index里的term前綴)映射到序號:0,1,2,3,4,5(term dictionary的block位置)。最簡單的做法就是定義個Map<string, integer="">,大家找到自己的位置對應(yīng)入座就好了,但從內(nèi)存占用少的角度想想,有沒有更優(yōu)的辦法呢?答案就是:FST(理論依據(jù)在此,但我相信99%的人不會認真看完的)

O表示一種狀態(tài)

-->表示狀態(tài)的變化過程,上面的字母/數(shù)字表示狀態(tài)變化和權(quán)重

將單詞分成單個字母通過⭕️和-->表示出來,0權(quán)重不顯示。如果⭕️后面出現(xiàn)分支,就標記權(quán)重,最后整條路徑上的權(quán)重加起來就是這個單詞對應(yīng)的序號。

FSTs are finite-state machines that map a term (byte sequence) to an arbitrary output.

FST以字節(jié)的方式存儲所有的term,這種壓縮方式可以有效的縮減存儲空間,使得term index足以放進內(nèi)存,但這種方式也會導致查找時需要更多的CPU資源。

后面的更精彩,看累了的同學可以喝杯咖啡……

壓縮技巧

Elasticsearch里除了上面說到用FST壓縮term index外,對posting list也有壓縮技巧。

小明喝完咖啡又舉手了:"posting list不是已經(jīng)只存儲文檔id了嗎?還需要壓縮?"

嗯,我們再看回最開始的例子,如果Elasticsearch需要對同學的性別進行索引(這時傳統(tǒng)關(guān)系型數(shù)據(jù)庫已經(jīng)哭暈在廁所……),會怎樣?如果有上千萬個同學,而世界上只有男/女這樣兩個性別,每個posting list都會有至少百萬個文檔id。 Elasticsearch是如何有效的對這些文檔id壓縮的呢?

Frame Of Reference

增量編碼壓縮,將大數(shù)變小數(shù),按字節(jié)存儲

首先,Elasticsearch要求posting list是有序的(為了提高搜索的性能,再任性的要求也得滿足),這樣做的一個好處是方便壓縮,看下面這個圖例:

如果數(shù)學不是體育老師教的話,還是比較容易看出來這種壓縮技巧的。

原理就是通過增量,將原來的大數(shù)變成小數(shù)僅存儲增量值,再精打細算按bit排好隊,最后通過字節(jié)存儲,而不是大大咧咧的盡管是2也是用int(4個字節(jié))來存儲。

Roaring bitmaps

說到Roaring bitmaps,就必須先從bitmap說起。Bitmap是一種數(shù)據(jù)結(jié)構(gòu),假設(shè)有某個posting list:

[1,3,4,7,10]

對應(yīng)的bitmap就是:

[1,0,1,1,0,0,1,0,0,1]

非常直觀,用0/1表示某個值是否存在,比如10這個值就對應(yīng)第10位,對應(yīng)的bit值是1,這樣用一個字節(jié)就可以代表8個文檔id,舊版本(5.0之前)的Lucene就是用這樣的方式來壓縮的,但這樣的壓縮方式仍然不夠高效,如果有1億個文檔,那么需要12.5MB的存儲空間,這僅僅是對應(yīng)一個索引字段(我們往往會有很多個索引字段)。于是有人想出了Roaring bitmaps這樣更高效的數(shù)據(jù)結(jié)構(gòu)。

Bitmap的缺點是存儲空間隨著文檔個數(shù)線性增長,Roaring bitmaps需要打破這個魔咒就一定要用到某些指數(shù)特性:

將posting list按照65535為界限分塊,比如第一塊所包含的文檔id范圍在0~65535之間,第二塊的id范圍是65536~131071,以此類推。再用<商,余數(shù)>的組合表示每一組id,這樣每組里的id范圍都在0~65535內(nèi)了,剩下的就好辦了,既然每組id不會變得無限大,那么我們就可以通過最有效的方式對這里的id存儲。

細心的小明這時候又舉手了:"為什么是以65535為界限?"

程序員的世界里除了1024外,65535也是一個經(jīng)典值,因為它=2^16-1,正好是用2個字節(jié)能表示的最大數(shù),一個short的存儲單位,注意到上圖里的最后一行“If a block has more than 4096 values, encode as a bit set, and otherwise as a simple array using 2 bytes per value”,如果是大塊,用節(jié)省點用bitset存,小塊就豪爽點,2個字節(jié)我也不計較了,用一個short[]存著方便。

那為什么用4096來區(qū)分大塊還是小塊呢?

個人理解:都說程序員的世界是二進制的,4096*2bytes = 8192bytes < 1KB, 磁盤一次尋道可以順序把一個小塊的內(nèi)容都讀出來,再大一位就超過1KB了,需要兩次讀。

聯(lián)合索引

上面說了半天都是單field索引,如果多個field索引的聯(lián)合查詢,倒排索引如何滿足快速查詢的要求呢?

  • 利用跳表(Skip list)的數(shù)據(jù)結(jié)構(gòu)快速做“與”運算,或者
  • 利用上面提到的bitset按位“與”

先看看跳表的數(shù)據(jù)結(jié)構(gòu):

將一個有序鏈表level0,挑出其中幾個元素到level1及l(fā)evel2,每個level越往上,選出來的指針元素越少,查找時依次從高level往低查找,比如55,先找到level2的31,再找到level1的47,最后找到55,一共3次查找,查找效率和2叉樹的效率相當,但也是用了一定的空間冗余來換取的。

假設(shè)有下面三個posting list需要聯(lián)合索引:

如果使用跳表,對最短的posting list中的每個id,逐個在另外兩個posting list中查找看是否存在,最后得到交集的結(jié)果。

如果使用bitset,就很直觀了,直接按位與,得到的結(jié)果就是最后的交集。

總結(jié)和思考

Elasticsearch的索引思路:

將磁盤里的東西盡量搬進內(nèi)存,減少磁盤隨機讀取次數(shù)(同時也利用磁盤順序讀特性),結(jié)合各種奇技淫巧的壓縮算法,用及其苛刻的態(tài)度使用內(nèi)存。

所以,對于使用Elasticsearch進行索引時需要注意:

  • 不需要索引的字段,一定要明確定義出來,因為默認是自動建索引的
  • 同樣的道理,對于String類型的字段,不需要analysis的也需要明確定義出來,因為默認也是會analysis的
  • 選擇有規(guī)律的ID很重要,隨機性太大的ID(比如java的UUID)不利于查詢

關(guān)于最后一點,個人認為有多個因素:

其中一個(也許不是最重要的)因素: 上面看到的壓縮算法,都是對Posting list里的大量ID進行壓縮的,那如果ID是順序的,或者是有公共前綴等具有一定規(guī)律性的ID,壓縮比會比較高;

另外一個因素: 可能是最影響查詢性能的,應(yīng)該是最后通過Posting list里的ID到磁盤中查找Document信息的那步,因為Elasticsearch是分Segment存儲的,根據(jù)ID這個大范圍的Term定位到Segment的效率直接影響了最后查詢的性能,如果ID是有規(guī)律的,可以快速跳過不包含該ID的Segment,從而減少不必要的磁盤讀次數(shù)。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring?Security過濾器鏈體系的實例詳解

    Spring?Security過濾器鏈體系的實例詳解

    這篇文章主要介紹了Spring?Security過濾器鏈體系,通過思維導圖可以很好的幫助大家理解配置類的相關(guān)知識,結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • JAVA獲取文件絕對路徑的方法

    JAVA獲取文件絕對路徑的方法

    這篇文章主要介紹了JAVA獲取文件絕對路徑的方法,涉及針對文件路徑的操作技巧,需要的朋友可以參考下
    2015-02-02
  • Spring?Boot中WebMvcConfig配置詳解及示例代碼

    Spring?Boot中WebMvcConfig配置詳解及示例代碼

    WebMvcConfig是一個配置類,它繼承了WebMvcConfigurationSupport,允許我們對SpringMVC進行更細粒度的控制,這篇文章主要給大家介紹了關(guān)于Spring?Boot中WebMvcConfig配置詳解及示例的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • springboot實現(xiàn)定時器(一看即會,非常簡單)

    springboot實現(xiàn)定時器(一看即會,非常簡單)

    這篇文章主要介紹了springboot實現(xiàn)定時器(一看即會,非常簡單),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • maven私服的配置使用方法

    maven私服的配置使用方法

    這篇文章主要介紹了maven私服的配置使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • Spring Cloud詳解實現(xiàn)聲明式微服務(wù)調(diào)用OpenFeign方法

    Spring Cloud詳解實現(xiàn)聲明式微服務(wù)調(diào)用OpenFeign方法

    這篇文章主要介紹了Spring Cloud實現(xiàn)聲明式微服務(wù)調(diào)用OpenFeign方法,OpenFeign 是 Spring Cloud 家族的一個成員, 它最核心的作用是為 HTTP 形式的 Rest API 提供了非常簡潔高效的 RPC 調(diào)用方式,希望對大家有所幫助。一起跟隨小編過來看看吧
    2022-07-07
  • java反轉(zhuǎn)鏈表的多種解決方法舉例詳解

    java反轉(zhuǎn)鏈表的多種解決方法舉例詳解

    這篇文章主要介紹了java反轉(zhuǎn)鏈表的多種解決方法,分別是使用棧、雙指針和遞歸,每種方法都有其實現(xiàn)原理和代碼示例,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-04-04
  • Java使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片

    Java使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片

    PDF轉(zhuǎn)文本的插件常用的有pdfbox ,itextpdf 和 spire.pdf,本文主要介紹如何使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片,需要的可以參考一下
    2025-01-01
  • 在Spring Boot中從類路徑加載文件的示例

    在Spring Boot中從類路徑加載文件的示例

    創(chuàng)建Spring Boot Web應(yīng)用程序時,有時有時需要從類路徑中加載文件;war和jar的加載文件格式是不一樣的,在下面,您將找到在WAR和JAR中加載文件的解決方案。
    2020-10-10
  • Java中List集合的常用方法詳解

    Java中List集合的常用方法詳解

    這篇文章主要為大家詳細介紹了Java中List集合的常用方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02

最新評論

梨树县| 温州市| 栾川县| 六安市| 谷城县| 巴彦淖尔市| 翼城县| 晋州市| 罗平县| 麻栗坡县| 宝丰县| 奎屯市| 巍山| 喀喇| 汉源县| 卫辉市| 资兴市| 遂川县| 海门市| 贡山| 塘沽区| 响水县| 乌兰浩特市| 开鲁县| 九台市| 万全县| 游戏| 泽普县| 邯郸县| 丹凤县| 织金县| 广汉市| 岱山县| 沧源| 郴州市| 密山市| 桑日县| 昭苏县| 汝城县| 千阳县| 汤阴县|