摘要
先自上而下,後自底向上的介紹ElasticSearch的底層工做原理,試圖回答如下問題:html
爲何個人搜索 *foo-bar* 沒法匹配 foo-bar ?web
爲何增長更多的文件會壓縮索引(Index)?緩存
爲何ElasticSearch佔用不少內存?微信
版本
elasticsearch版本: elasticsearch-2.2.0網絡
內容
圖解ElasticSearch
雲上的集羣
集羣裏的盒子
雲裏面的每一個白色正方形的盒子表明一個節點——Node。數據結構
節點之間
在一個或者多個節點直接,多個綠色小方塊組合在一塊兒造成一個ElasticSearch的索引。app
索引裏的小方塊
在一個索引下,分佈在多個節點裏的綠色小方塊稱爲分片——Shard。elasticsearch
Shard=Lucene Index
一個ElasticSearch的Shard本質上是一個Lucene Index。性能
Lucene是一個Full Text 搜索庫(也有不少其餘形式的搜索庫),ElasticSearch是創建在Lucene之上的。接下來的故事要說的大部份內容其實是ElasticSearch如何基於Lucene工做的。學習
圖解Lucene
Mini索引——segment
在Lucene裏面有不少小的segment,咱們能夠把它們當作Lucene內部的mini-index。
Segment內部
有着許多數據結構
Inverted Index
Stored Fields
Document Values
Cache
最最重要的Inverted Index
Inverted Index主要包括兩部分:
一個有序的數據字典Dictionary(包括單詞Term和它出現的頻率)。
與單詞Term對應的Postings(即存在這個單詞的文件)。
當咱們搜索的時候,首先將搜索的內容分解,而後在字典裏找到對應Term,從而查找到與搜索相關的文件內容。
查詢「the fury」
自動補全(AutoCompletion-Prefix)
若是想要查找以字母「c」開頭的字母,能夠簡單的經過二分查找(Binary Search)在Inverted Index表中找到例如「choice」、「coming」這樣的詞(Term)。
昂貴的查找
若是想要查找全部包含「our」字母的單詞,那麼系統會掃描整個Inverted Index,這是很是昂貴的。
在此種狀況下,若是想要作優化,那麼咱們面對的問題是如何生成合適的Term。
問題的轉化
對於以上諸如此類的問題,咱們可能會有幾種可行的解決方案:
* suffix -> xiffus *
若是咱們想之後綴做爲搜索條件,能夠爲Term作反向處理。
(60.6384, 6.5017) -> u4u8gyykk
對於GEO位置信息,能夠將它轉換爲GEO Hash。
123 -> {1-hundreds, 12-tens, 123}
對於簡單的數字,能夠爲它生成多重形式的Term。
解決拼寫錯誤
一個Python庫 爲單詞生成了一個包含錯誤拼寫信息的樹形狀態機,解決拼寫錯誤的問題。
Stored Field字段查找
當咱們想要查找包含某個特定標題內容的文件時,Inverted Index就不能很好的解決這個問題,因此Lucene提供了另一種數據結構Stored Fields來解決這個問題。本質上,Stored Fields是一個簡單的鍵值對key-value。默認狀況下,ElasticSearch會存儲整個文件的JSON source。
Document Values爲了排序,聚合
即便這樣,咱們發現以上結構仍然沒法解決諸如:排序、聚合、facet,由於咱們可能會要讀取大量不須要的信息。
因此,另外一種數據結構解決了此種問題:Document Values。這種結構本質上就是一個列式的存儲,它高度優化了具備相同類型的數據的存儲結構。
爲了提升效率,ElasticSearch能夠將索引下某一個Document Value所有讀取到內存中進行操做,這大大提高訪問速度,可是也同時會消耗掉大量的內存空間。
總之,這些數據結構Inverted Index、Stored Fields、Document Values及其緩存,都在segment內部。
搜索發生時
搜索時,Lucene會搜索全部的segment而後將每一個segment的搜索結果返回,最後合併呈現給客戶。
Lucene的一些特性使得這個過程很是重要:
Segments是不可變的(immutable)
Delete? 當刪除發生時,Lucene作的只是將其標誌位置爲刪除,可是文件仍是會在它原來的地方,不會發生改變
Update? 因此對於更新來講,本質上它作的工做是:先刪除,而後從新索引(Re-index)
隨處可見的壓縮
Lucene很是擅長壓縮數據,基本上全部教科書上的壓縮方式,都能在Lucene中找到。
緩存全部的全部
Lucene也會將全部的信息作緩存,這大大提升了它的查詢效率。
緩存的故事
當ElasticSearch索引一個文件的時候,會爲文件創建相應的緩存,而且會按期(每秒)刷新這些數據,而後這些文件就能夠被搜索到。
隨着時間的增長,咱們會有不少segments,
因此ElasticSearch會將這些segment合併,在這個過程當中,segment會最終被刪除掉
這就是爲何增長文件可能會使索引所佔空間變小,它會引發merge,從而可能會有更多的壓縮。
舉個栗子
有兩個segment將會merge
這兩個segment最終會被刪除,而後合併成一個新的segment
這時這個新的segment在緩存中處於cold狀態,可是大多數segment仍然保持不變,處於warm狀態。
以上場景常常在Lucene Index內部發生的。
在Shard中搜索
ElasticSearch從Shard中搜索的過程與Lucene Segment中搜索的過程相似。
與在Lucene Segment中搜索不一樣的是,Shard多是分佈在不一樣Node上的,因此在搜索與返回結果時,全部的信息都會經過網絡傳輸。
須要注意的是:
1次搜索查找2個shard = 2次分別搜索shard
對於日誌文件的處理
當咱們想搜索特定日期產生的日誌時,經過根據時間戳對日誌文件進行分塊與索引,會極大提升搜索效率。
當咱們想要刪除舊的數據時也很是方便,只需刪除老的索引便可。
在上種狀況下,每一個index有兩個shards
如何Scale
shard不會進行更進一步的拆分,可是shard可能會被轉移到不一樣節點上
因此,若是當集羣節點壓力增加到必定的程度,咱們可能會考慮增長新的節點,這就會要求咱們對全部數據進行從新索引,這是咱們不太但願看到的,因此咱們須要在規劃的時候就考慮清楚,如何去平衡足夠多的節點與不足節點之間的關係。
節點分配與Shard優化
爲更重要的數據索引節點,分配性能更好的機器
確保每一個shard都有副本信息replica
路由Routing
每一個節點,每一個都存留一份路由表,因此當請求到任何一個節點時,ElasticSearch都有能力將請求轉發到指望節點的shard進一步處理。
一個真實的請求
Query
Query有一個類型filtered,以及一個multi_match的查詢
Aggregation
根據做者進行聚合,獲得top10的hits的top10做者的信息
請求分發
這個請求可能被分發到集羣裏的任意一個節點
上帝節點
這時這個節點就成爲當前請求的協調者(Coordinator),它決定:
根據索引信息,判斷請求會被路由到哪一個核心節點
以及哪一個副本是可用的
等等
路由
在真實搜索以前
ElasticSearch 會將Query轉換成Lucene Query
而後在全部的segment中執行計算
對於Filter條件自己也會有緩存
但queries不會被緩存,因此若是相同的Query重複執行,應用程序本身須要作緩存
因此,
filters能夠在任什麼時候候使用
query只有在須要score的時候才使用
返回
搜索結束以後,結果會沿着下行的路徑向上逐層返回。
添加微信:xinbigdata
獲取精選大數據電子書、學習視頻、入羣交流 、專欄返現
![](http://static.javashuo.com/static/loading.gif)
本文分享自微信公衆號 - 老懞大數據(simon_bigdata)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。