Elasticsearch基本概念和索引原理

我是啤酒就辣條。

但行好事,莫問前程。mysql

Elasticsearch是什麼?

Elasticsearch是一個基於文檔的NoSQL數據庫,是一個分佈式RESTful風格的搜索和數據分析引擎,同時也是Elastic Stack的核心,集中存儲數據。Elasticsearch、Logstash、Kibana常常被用做日誌分析系統,俗稱ELK。redis

說白了,就是一個數據庫,搜索賊快(可是插入更新較慢,要否則其餘數據庫別玩了)。速度快,還能夠進行分詞,很是適合作搜索,例如商城的商品搜索。爲何快,後面講原理的時候會說,不僅僅是緩存的問題,原理很是精彩。並且它是nosql的,數據格式能夠隨便造。Elasticsearch還爲咱們提供了豐富的RESTful風格的API,寫代碼的成本極低。最後它支持分佈式,高性能(搜索快),高可用(某些節點宕機能夠接着用),可伸縮(能夠方便的增長節點,解決物理內存上線問題),適合分佈式系統開發。算法

Elasticsearch基本概念

爲了快速瞭解Elasticsearch(後面可能會簡稱爲ES),能夠與mysql幾個概念作個對比。sql

Elasticsearch Mysql
字段(Filed) 屬性(列)
文檔(Document) 記錄(行)
類型(Type)
索引(Index) 數據庫

是否是清楚多了?咱們說Elasticsearch是基於文檔的,就是由於記錄元素(被搜索的最小單位)是文檔。例以下面就是一個文檔,數據庫

{
    "email":      "john@smith.com",
    "first_name": "John",
    "last_name":  "Smith",
    "info": {
        "bio":         "Eco-warrior and defender of the weak",
        "age":         25,
        "interests": [ "dolphins", "whales" ]
    },
    "join_date": "2014/05/01"
}

文檔格式看起來很像Json吧。emailfirst_name等等就是Filed。因爲結構是Json,因此value值就很方便聽任意類型,這就是nosql的好處。json

文檔(Document)

ES中的一個對象未來會和Java代碼中的一個對象對應。文檔的每個Filed能夠是任意類型,可是一旦某索引(Index)(咱們描述的時候,略過Type,可是Type依然存在)中插入了一個文檔,某Filed被第一次使用,ES就會設置好此Filed的類型。例如你插入user的name是字符串類型,之後再插入文檔,name字段必須是字符串類型。因此,建議在插入文檔以前,先設置好每一個Filed的類型。數組

若是插入文檔的時候,不指定id,ES會幫助咱們自動生成一個id,建議id是數字類型,這樣搜索會快速不少。商城系統中的商品id建議使用雪花算法生成,這樣既避免了自增id的安全性問題,又解決了字符串id檢索慢的問題。緩存

類型(Type)

關於Type,類型概念,在6.x版本中,一個索引(Index)能夠擁有多個Type。在7.x版本(目前最新版本),一個索引只能擁有一個Type,默認的type就是_doc,在7.x版本中,已經建議刪除了。在將來的8.x版本會完全刪除。可是在7.x版本中,一個文檔還必須歸屬於一個類型。安全

索引(Index)

都說ES中的索引相似於mysql中的數據庫,我以爲將來索引有成爲mysql中概念的潛質。咱們把相同特徵(Filed數量和類型基本相同)的文檔放到同一個索引(index)裏面。這樣方便提早經過mapping來規定各個Filed的類型。另外,索引名稱必須所有小寫,因此不建議寫成駝峯式。服務器

節點(Node)與分片(Shard)

在這裏插入圖片描述

因爲生產環境下ES基本都是集羣部署的,因此必定少不了節點的概念,一個節點就是一個ES實例,就是一個Java進程,這些Java進程部署在不一樣的服務器上,增長ES可用性。

ES節點根據功能能夠分爲三種:

  1. 主節點:職責是和集羣操做相關的內容,如建立或刪除索引,跟蹤哪些節點是羣集的一部分,並決定哪些分片分配給相關的節點。每一個節點均可訪問集羣的狀態,可是隻有主節點能夠修改集羣的狀態。
  2. 數據節點:數據節點主要是儲存數據的節點,對文檔進行增刪改查,聚合操做等等,數據節點對cpu,內存,io要求較高,當資源不夠的時候,能夠增長新的節點,很方便的進行數據拓展。
  3. 客戶端節點:本節點主要處理路由請求,分發索引的操做。實際上主節點和數據節點也有路由轉發的功能,可是爲了提升效率,仍是建議生產環境單首創建客戶端節點。

分片相似於mysql中的分表,在一個索引拆分紅幾個小索引,分佈在不一樣的節點(不一樣服務器)上,每一個小索引都具備完備的功能,當客戶端發來請求的時候,客戶端節點找到合適的分片上的小索引,進行數據查詢,這一過程對於用戶來講都是透明的,用戶表面上看只是在操做一個索引。利用分片,能夠避免單個節點的物理限制,還能夠增長吞吐量。建議最開始一個索引要用多少分片設計好,由於修改分片數量是個至關麻煩的過程。

做爲分佈式的數據庫,ES必須爲我們提供數據冗餘功能,這就是分片副本,就是將某個分片copy一份放到其餘節點上。注意,這裏分片和分片副本必須在不一樣的節點上!分片副本也能夠提升吞吐量。分片副本不一樣於分片,能夠很方便的進行修改。

說完了全部概念,再去看本節最開始那張圖,有一個索引,分了3分片在三個節點上,而且每一個分片在不一樣的節點上有分片副本。

Elasticsearch索引原理

看完上面的內容,你對Elasticsearch有了基本的認識,再去看基本操做(我後面要寫一篇基操博客),就能夠在項目中使用Elasticsearch了。此刻你能夠喘口氣,以放鬆的心態看後面的內容。下面咱們就講講索引爲何快?

首先,咱們知道mysql底層數據結構使用的是B+Tree,這種BTree,將搜索時間複雜度變成了logN,已經很快了,咱們Elasticsearch要比它還快。Elasticsearch是怎麼作的呢?首先儲存結構要優化,而後再提升下和磁盤的交互效率。

先說Elasticsearch索引結構,叫作倒排索引,啥是倒排索引呢?它的大概邏輯以下:

在這裏插入圖片描述

爲了講清楚這個概念,咱們先看個例子,以下爲咱們user的數據:

ID Name Age
1 Kate 24
2 John 24
3 Bill 29
4 Kate 26
5 Brand 29

Elasticsearch會爲以上數據創建兩個索引樹:

Term Posting List
Kate 1,4
Brand 5
John 2
Bill 3
Term Posting List
24 1,2
26 4
29 3,5

以上的索引樹就叫作倒排索引,每一個Filed字段對應着一組Term,每一個Term後面跟着的id(還記着嗎,這個主鍵用戶不指定就會自動生成,因此必定存在)就是Posting List,它是一組id,有了id再去磁盤中對應的文檔就so fast了。

你有沒有發現,Term若是按序找會快點,將Term按序排,在進行二分查找,是否是速度就跟BTree同樣了,時間複雜度爲LogN。這個有序的Term組就是Term Dictionary

那麼問題又來了,好比說數據庫中有name前綴爲A的同窗1000萬個,前綴爲Z的同窗有3個,我要查前綴爲Z的同窗,那二分查找不也不少次嗎,因此,Elasticsearch把每一個開頭的地方標記一下,拿出來,再放到一顆樹裏,速度不是就快了嘛。這棵樹就是Term IndexTerm Index前綴不必定是第一個字符,好比A、Ab、Abz,這種均可以在Term Index樹裏。而且Term Dictionary可能會太大,會被放到磁盤中,避免內存佔用太多。

再看下面這張結構圖是否是清楚多了。

在這裏插入圖片描述

因爲Term Index被放到內存中,因此最好壓縮一下,減小內存使用,壓縮使用的是FST,這個東西講起來比較複雜,反正就是能壓縮,內存變小就行了。

Term壓縮完了,那麼Posting List是否是也能夠壓縮一下,省省空間啊?既然都是id,使用過redis的同窗瞬間會想到bitMap,就是有個巨大的數組,儲存着0或1,有就是1,沒有就是0。例如上面的三、5放在BitMap中就是 1,0,1,0,0,0。雖然說空間已經明顯小多了,可是若是一個Posting List只儲存着1,10000001這兩個id,最後產生的數字是否是過大呢。因而乎,Roaring bitmaps就出來了,進行了一次指數降級,簡單點說就是取商和餘數儲存,被除數是65535。例如 1000,62101,131385,196658, 這幾個id,首先分組,分組規則就是商同樣,例如上面id可分組爲[(0,1000),(0,62101)],[],[(2,6915)],[(3,53)]。注意,沒有商爲1的值,我用空數組表示。此時,將某個組中的數字放到一個bitmap中。

相關文章
相關標籤/搜索