「掃盲」 Elasticsearch

什麼是Elasticsearch?

Elasticsearch is a real-time, distributed storage, search, and analytics engine
Elasticsearch 是一個實時的分佈式存儲、搜索、分析的引擎。node

介紹那兒有幾個關鍵字:
實時、分佈式、搜索、分析web

因而咱們就得知道Elasticsearch是怎麼作到實時的,Elasticsearch的架構是怎麼樣的(分佈式)。存儲、搜索和分析(得知道Elasticsearch是怎麼存儲、搜索和分析的)算法

爲何要用Elasticsearch

在學習一項技術以前,必須先要了解爲何要使用這項技術。因此,爲何要使用Elasticsearch呢?咱們在平常開發中,數據庫也能作到(實時、存儲、搜索、分析)。數據庫

相對於數據庫,Elasticsearch的強大之處就是能夠模糊查詢。segmentfault

有的同窗可能就會說:我數據庫怎麼就不能模糊查詢了??我反手就給你寫一個SQL:
select * from user where name like '%公衆號Java%'
這不就能夠把公衆號Java相關的內容搜索出來了嗎?緩存

的確,這樣作的確能夠。可是要明白的是:name like %Java%這類的查詢是不走索引的,不走索引意味着:只要你的數據庫的量很大(1億條),你的查詢確定會是秒級別的數據結構

並且,即使給你從數據庫根據模糊匹配查出相應的記錄了,那每每會返回大量的數據給你,每每你須要的數據量並無這麼多,可能50條記錄就足夠了。架構

還有一個就是:用戶輸入的內容每每並無這麼的精確,好比我從Google輸入ElastcSeach(打錯字),可是Google仍是能估算我想輸入的是Elasticsearchapp

而Elasticsearch是專門作搜索的,就是爲了解決上面所講的問題而生的,換句話說:異步

Elasticsearch對模糊搜索很是擅長(搜索速度很快)

從Elasticsearch搜索到的數據能夠根據評分過濾掉大部分的,只要返回評分高的給用戶就行了(原生就支持排序)

沒有那麼準確的關鍵字也能搜出相關的結果(能匹配有相關性的記錄)

下面咱們就來學學爲何Elasticsearch能夠作到上面的幾點。

Elasticsearch的數據結構

衆所周知,你要在查詢的時候花得更少的時間,你就須要知道他的底層數據結構是怎麼樣的;舉個例子:

樹型的查找時間複雜度通常是O(logn)

鏈表的查找時間複雜度通常是O(n)

哈希表的查找時間複雜度通常是O(1)

….不一樣的數據結構所花的時間每每不同,你想要查找的時候要快,就須要有底層的數據結構支持

從上面說Elasticsearch的模糊查詢速度很快,那Elasticsearch的底層數據結構是什麼呢?咱們來看看。

咱們根據「完整的條件」查找一條記錄叫作正向索引;咱們一本書的章節目錄就是正向索引,經過章節名稱就找到對應的頁碼。
file
http://img.blog.itpub.net/blo...

分詞

首先咱們得知道爲何Elasticsearch爲何能夠實現快速的「模糊匹配」/「相關性查詢」,其實是你寫入數據到Elasticsearch的時候會進行分詞。

仍是以上圖爲例,上圖出現了4次「算法」這個詞,咱們能不能根據此次詞爲它找他對應的目錄?Elasticsearch正是這樣乾的,若是咱們根據上圖來作這個事,會獲得相似這樣的結果:

算法 ->2,13,42,56

這表明着「算法」這個詞確定是在第二頁、第十三頁、第四十二頁、第五十六頁出現過。這種根據某個詞(不完整的條件)再查找對應記錄,叫作倒排索引。

再看下面的圖,好好體會一下:
file
http://img.blog.itpub.net/blo...

分詞器

衆所周知,世界上有這麼多的語言,那Elasticsearch怎麼切分這些詞呢?,Elasticsearch內置了一些分詞器
Standard Analyzer 。按詞切分,將詞小寫
Simple Analyzer。按非字母過濾(符號被過濾掉),將詞小寫
WhitespaceAnalyzer。按照空格切分,不轉小寫
….等等等

Elasticsearch分詞器主要由三部分組成:
Character Filters(文本過濾器,去除HTML)
Tokenizer(按照規則切分,好比空格)
TokenFilter(將切分後的詞進行處理,好比轉成小寫)

顯然,Elasticsearch是老外寫的,內置的分詞器都是英文類的,而咱們用戶搜索的時候每每搜的是中文,如今中文分詞器用得最多的就是IK。

分詞後的數據結構

file
http://img.blog.itpub.net/blo...

咱們輸入一段文字,Elasticsearch會根據分詞器對咱們的那段文字進行分詞(也就是圖上所看到的Ada/Allen/Sara..),這些分詞彙總起來咱們叫作Term Dictionary,而咱們須要經過分詞找到對應的記錄,這些文檔ID保存在PostingList

在Term Dictionary中的詞因爲是很是很是多的,因此咱們會爲其進行排序,等要查找的時候就能夠經過二分來查,不須要遍歷整個Term Dictionary

因爲Term Dictionary的詞實在太多了,不可能把Term Dictionary全部的詞都放在內存中,因而Elasticsearch還抽了一層叫作Term Index,這層只存儲 部分 詞的前綴,Term Index會存在內存中(檢索會特別快)

Term Index在內存中是以FST(Finite State Transducers)的形式保存的,其特色是很是節省內存。FST有兩個優勢:
1)空間佔用小。經過對詞典中單詞前綴和後綴的重複利用,壓縮了存儲空間;
2)查詢速度快。O(len(str))的查詢時間複雜度。

前面講到了Term Index是存儲在內存中的,且Elasticsearch用FST(Finite State Transducers)的形式保存(節省內存空間)。Term Dictionary在Elasticsearch也是爲他進行排序(查找的時候方便),其實PostingList也有對應的優化。
PostingList會使用Frame Of Reference(FOR)編碼技術對裏邊的數據進行壓縮,節約磁盤空間。
file
http://img.blog.itpub.net/blo...

PostingList裏邊存的是文檔ID,咱們查的時候每每須要對這些文檔ID作交集和並集的操做(好比在多條件查詢時),PostingList使用Roaring Bitmaps來對文檔ID進行交併集操做。

使用Roaring Bitmaps的好處就是能夠節省空間和快速得出交併集的結果。
file
http://img.blog.itpub.net/blo...

因此到這裏咱們總結一下Elasticsearch的數據結構有什麼特色:
file
https://mmbiz.qpic.cn/sz_mmbi...

Elasticsearch的術語和架構

在講解Elasticsearch的架構以前,首先咱們得了解一下Elasticsearch的一些常見術語。

Index:Elasticsearch的Index至關於數據庫的Table

Type:這個在新的Elasticsearch版本已經廢除(在之前的Elasticsearch版本,一個Index下支持多個Type--有點相似於消息隊列一個topic下多個group的概念)

Document:Document至關於數據庫的一行記錄

Field:至關於數據庫的Column的概念

Mapping:至關於數據庫的Schema的概念

DSL:至關於數據庫的SQL(給咱們讀取Elasticsearch數據的API)

file
http://img.blog.itpub.net/blo...

相信你們看完上面的對比圖,對Elasticsearch的一些術語就不難理解了。那Elasticsearch的架構是怎麼樣的呢?下面咱們來看看:

一個Elasticsearch集羣會有多個Elasticsearch節點,所謂節點實際上就是運行着Elasticsearch進程的機器。
file
http://img.blog.itpub.net/blo...

在衆多的節點中,其中會有一個Master Node,它主要負責維護索引元數據、負責切換主分片和副本分片身份等工做(後面會講到分片的概念),若是主節點掛了,會選舉出一個新的主節點。
file
http://img.blog.itpub.net/blo...

從上面咱們也已經得知,Elasticsearch最外層的是Index(至關於數據庫 表的概念);一個Index的數據咱們能夠分發到不一樣的Node上進行存儲,這個操做就叫作分片。

好比如今我集羣裏邊有4個節點,我如今有一個Index,想將這個Index在4個節點上存儲,那咱們能夠設置爲4個分片。這4個分片的數據合起來就是Index的數據
file
http://img.blog.itpub.net/blo...

爲何要分片?緣由也很簡單:
若是一個Index的數據量太大,只有一個分片,那隻會在一個節點上存儲,隨着數據量的增加,一個節點未必能把一個Index存儲下來。
多個分片,在寫入或查詢的時候就能夠並行操做(從各個節點中讀寫數據,提升吞吐量)

如今問題來了,若是某個節點掛了,那部分數據就丟了嗎?顯然Elasticsearch也會想到這個問題,因此分片會有主分片和副本分片之分(爲了實現高可用)

數據寫入的時候是寫到主分片,副本分片會複製主分片的數據,讀取的時候主分片和副本分片均可以讀。

Index須要分爲多少個主分片和副本分片都是能夠經過配置設置的
file
http://img.blog.itpub.net/blo...

若是某個節點掛了,前面所提升的Master Node就會把對應的副本分片提拔爲主分片,這樣即使節點掛了,數據就不會丟。

到這裏咱們能夠簡單總結一下Elasticsearch的架構了:
file
http://img.blog.itpub.net/blo...

Elasticsearch 寫入的流程

上面咱們已經知道當咱們向Elasticsearch寫入數據的時候,是寫到主分片上的,咱們能夠了解更多的細節。

客戶端寫入一條數據,到Elasticsearch集羣裏邊就是由節點來處理此次請求:
file
http://img.blog.itpub.net/blo...

集羣上的每一個節點都是coordinating node(協調節點),協調節點代表這個節點能夠作路由。好比節點1接收到了請求,但發現這個請求的數據應該是由節點2處理(由於主分片在節點2上),因此會把請求轉發到節點2上。

coodinate(協調)節點經過hash算法能夠計算出是在哪一個主分片上,而後路由到對應的節點
shard = hash(document_id) % (num_of_primary_shards)

路由到對應的節點以及對應的主分片時,會作如下的事:
一、將數據寫到內存緩存區
二、而後將數據寫到translog緩存區
三、每隔1s數據從buffer中refresh到FileSystemCache中,生成segment文件,一旦生成segment文件,就能經過索引查詢到了
四、refresh完,memory buffer就清空了。
五、每隔5s中,translog 從buffer flush到磁盤中
六、按期/定量從FileSystemCache中,結合translog內容flush index到磁盤中。

file
http://img.blog.itpub.net/blo...

解釋一下:
一、Elasticsearch會把數據先寫入內存緩衝區,而後每隔1s刷新到文件系統緩存區(當數據被刷新到文件系統緩衝區之後,數據才能夠被檢索到)。因此:Elasticsearch寫入的數據須要1s才能查詢到
二、爲了防止節點宕機,內存中的數據丟失,Elasticsearch會另寫一份數據到日誌文件上,但最開始的仍是寫到內存緩衝區,每隔5s纔會將緩衝區的刷到磁盤中。因此:Elasticsearch某個節點若是掛了,可能會形成有5s的數據丟失。
三、等到磁盤上的translog文件大到必定程度或者超過了30分鐘,會觸發commit操做,將內存中的segement文件異步刷到磁盤中,完成持久化操做。

說白了就是:寫內存緩衝區(定時去生成segement,生成translog),可以讓數據能被索引、被持久化。最後經過commit完成一次的持久化。
file
http://img.blog.itpub.net/blo...

等主分片寫完了之後,會將數據並行發送到副本集節點上,等到全部的節點寫入成功就返回ack給協調節點,協調節點返回ack給客戶端,完成一次的寫入。

Elasticsearch更新和刪除

Elasticsearch的更新和刪除操做流程:
給對應的doc記錄打上.del標識,若是是刪除操做就打上delete狀態,若是是更新操做就把原來的doc標誌爲delete,而後從新新寫入一條數據

前面提到了,每隔1s會生成一個segement 文件,那segement文件會愈來愈多愈來愈多。Elasticsearch會有一個merge任務,會將多個segement文件合併成一個segement文件。

在合併的過程當中,會把帶有delete狀態的doc給物理刪除掉。
file
http://img.blog.itpub.net/blo...

Elasticsearch查詢

查詢咱們最簡單的方式能夠分爲兩種:
一、根據ID查詢doc
二、根據query(搜索詞)去查詢匹配的doc

public TopDocs search(Query query, int n);
public Document doc(int docID);

根據ID去查詢具體的doc的流程是:
一、檢索內存的Translog文件
二、檢索硬盤的Translog文件
三、檢索硬盤的Segement文件

根據query去匹配doc的流程是:
同時去查詢內存和硬盤的Segement文件
file
http://img.blog.itpub.net/blo...

從上面所講的寫入流程,咱們就能夠知道,由於segement文件是每隔一秒才生成一次的,Get(經過ID去查Doc是實時的),Query(經過query去匹配Doc是近實時的)

Elasticsearch查詢又分能夠爲三個階段:
一、QUERY_AND_FETCH(查詢完就返回整個Doc內容)
二、QUERY_THEN_FETCH(先查詢出對應的Doc id ,而後再根據Doc id 匹配去對應的文檔)
三、DFS_QUERY_THEN_FETCH(先算分,再查詢)

「這裏的分指的是 詞頻率和文檔的頻率(Term Frequency、Document Frequency)衆所周知,出現頻率越高,相關性就更強」
file
http://img.blog.itpub.net/blo...

通常咱們用得最多的就是QUERY_THEN_FETCH,第一種查詢完就返回整個Doc內容(QUERY_AND_FETCH)只適合於只須要查一個分片的請求。

QUERY_THEN_FETCH整體的流程流程大概是:
一、客戶端請求發送到集羣的某個節點上。集羣上的每一個節點都是coordinate node(協調節點)
二、而後協調節點將搜索的請求轉發到全部分片上(主分片和副本分片都行)
三、每一個分片將本身搜索出的結果(doc id)返回給協調節點,由協調節點進行數據的合併、排序、分頁等操做,產出最終結果。
四、接着由協調節點根據 doc id 去各個節點上拉取實際的 document 數據,最終返回給客戶端。

Query Phase階段時節點作的事:
一、協調節點向目標分片發送查詢的命令(轉發請求到主分片或者副本分片上)
二、數據節點(在每一個分片內作過濾、排序等等操做),返回doc id給協調節點

Fetch Phase階段時節點作的是:
一、協調節點獲得數據節點返回的doc id,對這些doc id作聚合,而後將目標數據分片發送抓取命令(但願拿到整個Doc記錄)
二、數據節點按協調節點發送的doc id,拉取實際須要的數據返回給協調節點

主流程我相信你們也不會太難理解,說白了就是:因爲Elasticsearch是分佈式的,因此須要從各個節點都拉取對應的數據,而後最終統一合成給客戶端

只是Elasticsearch把這些活都幹了,咱們在使用的時候無感知而已。
file
http://img.blog.itpub.net/blo...

最後
這篇文章主要對Elasticsearch簡單入了個門,實際使用確定還會遇到不少坑,但我目前就到這裏就結束了。
file

轉自:
https://mp.weixin.qq.com/s/tq...
http://blog.itpub.net/6990035...

相關文章
相關標籤/搜索