ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。設計用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。node
揭面:python
架構圖:web
架構各模塊介紹:算法
Lucence Directory:是lucene的框架服務發現以及選主 ZenDiscovery: 用來實現節點自動發現,還有Master節點選取,假如Master出現故障,其它的這個節點會自動選舉,產生一個新的Master;數據庫
Plugins:插件能夠經過自定的方式擴展增強Elasticsearch的基本功能,好比能夠自定義類型映射,分詞器,本地腳本,自動發現等;緩存
Scripting:使用腳本語言能夠計算自定義表達式的值,好比計算自定義查詢相關度評分。支持的腳本語言有groovy,js,mvel(1.3.0廢棄),python等;安全
Disovery:該模塊主要負責集羣中節點的自動發現和Master節點的選舉。節點之間使用p2p的方式進行直接通訊,不存在單點故障的問題。Elasticsearch中,Master節點維護集羣的全局狀態,好比節點加入和離開時進行shard的從新分配;服務器
River:表明es的一個數據源,也是其它存儲方式(如:數據庫)同步數據到es的一個方法。它是以插件方式存在的一個es服務,經過讀取river中的數據並把它索引到es中;架構
Gateway:模塊用於存儲es集羣的元數據信息;app
Zen Discovery:zen發現機制是elasticsearch默認的內建模塊。它提供了多播和單播兩種發現方式,可以很容易的擴展至雲環境。zen發現機制是和其餘模塊集成的,例如全部節點間通信必須用trasport模塊來完成。
核心概念:
集羣(Cluster):ES集羣是一個或多個節點的集合,它們共同存儲了整個數據集,並提供了聯合索引以及可跨全部節點的搜索能力。多節點組成的集羣擁有冗餘能力,它能夠在一個或幾個節點出現故障時保證服務的總體可用性。
集羣靠其獨有的名稱進行標識,默認名稱爲「elasticsearch」。節點靠其集羣名稱來決定加入哪一個ES集羣,一個節點只能屬一個集羣;
節點(node):一個節點是一個邏輯上獨立的服務,能夠存儲數據,並參與集羣的索引和搜索功能, 一個節點也有惟一的名字,羣集經過節點名稱進行管理和通訊;
主節點:主節點的主要職責是和集羣操做相關的內容,如建立或刪除索引,跟蹤哪些節點是羣集的一部分,並決定哪些分片分配給相關的節點。穩定的主節點對集羣的健康是很是重要的。雖然主節點也能夠協調節點,路由搜索和從客戶端新增數據到數據節點,但最好不要使用這些專用的主節點。一個重要的原則是,儘量作儘可能少的工做。
對於大型的生產集羣來講,推薦使用一個專門的主節點來控制集羣,該節點將不處理任何用戶請求。
數據節點:持有數據和倒排索引。
客戶端節點:它既不能保持數據也不能成爲主節點,該節點能夠響應用戶的狀況,把相關操做發送到其餘節點;客戶端節點會將客戶端請求路由到集羣中合適的分片上。對於讀請求來講,協調節點每次會選擇不一樣的分片處理請求,以實現負載均衡。
部落節點:部落節點能夠跨越多個集羣,它能夠接收每一個集羣的狀態,而後合併成一個全局集羣的狀態,它能夠讀寫全部節點上的數據。
索引(Index): ES將數據存儲於一個或多個索引中,索引是具備相似特性的文檔的集合。類比傳統的關係型數據庫領域來講,索引至關於SQL中的一個數據庫,或者一個數據存儲方案(schema)。索引由其名稱(必須爲全小寫字符)進行標識,並經過引用此名稱完成文檔的建立、搜索、更新及刪除操做。一個ES集羣中能夠按需建立任意數目的索引。
文檔類型(Type):類型是索引內部的邏輯分區(category/partition),然而其意義徹底取決於用戶需求。所以,一個索引內部可定義一個或多個類型(type)。通常來講,類型就是爲那些擁有相同的域的文檔作的預約義。例如,在索引中,能夠定義一個用於存儲用戶數據的類型,一個存儲日誌數據的類型,以及一個存儲評論數據的類型。類比傳統的關係型數據庫領域來講,類型至關於「表」。
文檔(Document) :文檔是Lucene索引和搜索的原子單位,它是包含了一個或多個域的容器,基於JSON格式進行表示。文檔由一個或多個域組成,每一個域擁有一個名字及一個或多個值,有多個值的域一般稱爲「多值域」。每一個文檔能夠存儲不一樣的域集,但同一類型下的文檔至應該有某種程度上的類似之處。至關於數據庫的「記錄」
Mapping: 至關於數據庫中的schema,用來約束字段的類型,不過 Elasticsearch 的 mapping 能夠自動根據數據建立。
ES中,全部的文檔在存儲以前都要首先進行分析。用戶可根據須要定義如何將文本分割成token、哪些token應該被過濾掉,以及哪些文本須要進行額外處理等等。
分片(shard) :ES的「分片(shard)」機制可將一個索引內部的數據分佈地存儲於多個節點,它經過將一個索引切分爲多個底層物理的Lucene索引完成索引數據的分割存儲功能,這每個物理的Lucene索引稱爲一個分片(shard)。
每一個分片其內部都是一個全功能且獨立的索引,所以可由集羣中的任何主機存儲。建立索引時,用戶可指定其分片的數量,默認數量爲5個。
Shard有兩種類型:primary和replica,即主shard及副本shard。
Primary shard用於文檔存儲,每一個新的索引會自動建立5個Primary shard,固然此數量可在索引建立以前經過配置自行定義,不過,一旦建立完成,其Primary shard的數量將不可更改。
Replica shard是Primary Shard的副本,用於冗餘數據及提升搜索性能。
每一個Primary shard默認配置了一個Replica shard,但也能夠配置多個,且其數量可動態更改。ES會根據須要自動增長或減小這些Replica shard的數量。
ES集羣可由多個節點組成,各Shard分佈式地存儲於這些節點上。
ES可自動在節點間按須要移動shard,例如增長節點或節點故障時。簡而言之,分片實現了集羣的分佈式存儲,而副本實現了其分佈式處理及冗餘功能。
建立索引:
過程:當分片所在的節點接收到來自協調節點的請求後,會將該請求寫入translog,並將文檔加入內存緩存。若是請求在主分片上成功處理,該請求會並行發送到該分片的副本上。當translog被同步到所有的主分片及其副本上後,客戶端纔會收到確認通知。
內存緩衝會被週期性刷新(默認是1秒),內容將被寫到文件系統緩存的一個新段(segment)上。雖然這個段並無被同步(fsync),但它是開放的,內容能夠被搜索到。
每30分鐘,或者當translog很大的時候,translog會被清空,文件系統緩存會被同步。這個過程在Elasticsearch中稱爲沖洗(flush)。在沖洗過程當中,內存中的緩衝將被清除,內容被寫入一個新段。段的fsync將建立一個新的提交點,並將內容刷新到磁盤。舊的translog將被刪除並開始一個新的translog。
ES如何作到實時檢索?
因爲在buffer中的索引片先同步到文件系統緩存,再刷寫到磁盤,所以在檢索時能夠直接檢索文件系統緩存,保證了實時性。
這一步刷到文件系統緩存的步驟,在 Elasticsearch 中,是默認設置爲 1 秒間隔的,對於大多數應用來講,幾乎就至關因而實時可搜索了。
不過對於 ELK 的日誌場景來講,並不須要如此高的實時性,而是須要更快的寫入性能。咱們能夠經過 /_settings接口或者定製 template 的方式,加大 refresh_interval 參數。
當segment從文件系統緩存同步到磁盤時發生了錯誤怎麼辦? 數據會不會丟失?
因爲Elasticsearch 在把數據寫入到內存 buffer 的同時,其實還另外記錄了一個 translog日誌,若是在這期間故障發生時,Elasticsearch會從commit位置開始,恢復整個translog文件中的記錄,保證數據的一致性。
等到真正把 segment 刷到磁盤,且 commit 文件進行更新的時候, translog 文件才清空。這一步,叫作flush。一樣,Elasticsearch 也提供了 /_flush 接口。
索引數據的一致性經過 translog 保證,那麼 translog 文件本身呢?
Elasticsearch 2.0 之後爲了保證不丟失數據,每次 index、bulk、delete、update 完成的時候,必定觸發刷新translog 到磁盤上,纔給請求返回 200 OK。這個改變在提升數據安全性的同時固然也下降了一點性能
檢索文檔:
搜索相關性
相關性是由搜索結果中Elasticsearch打給每一個文檔的得分決定的。默認使用的排序算法是tf/idf(詞頻/逆文檔頻率)。詞頻衡量了一個詞項在文檔中出現的次數 (頻率越高 == 相關性越高),逆文檔頻率衡量了詞項在所有索引中出現的頻率,是一個索引中文檔總數的百分比(頻率越高 == 相關性越低)。最後的得分是tf-idf得分與其餘因子好比(短語查詢中的)詞項接近度、(模糊查詢中的)詞項類似度等的組合
更新刪除索引:
刪除和更新也都是寫操做。可是Elasticsearch中的文檔是不可變的,所以不能被刪除或者改動以展現其變動。那麼,該如何刪除和更新文檔呢?
磁盤上的每一個段都有一個相應的.del文件。當刪除請求發送後,文檔並無真的被刪除,而是在.del文件中被標記爲刪除。該文檔依然能匹配查詢,可是會在結果中被過濾掉。當段合併(咱們將在本系列接下來的文章中講到)時,在.del文件中被標記爲刪除的文檔將不會被寫入新段。
接下來咱們看更新是如何工做的。在新的文檔被建立時,Elasticsearch會爲該文檔指定一個版本號。當執行更新時,舊版本的文檔在.del文件中被標記爲刪除,新版本的文檔被索引到一個新段。舊版本的文檔依然能匹配查詢,可是會在結果中被過濾掉。
物理刪除索引:當索引數據不斷增加時,對應的segment也會不斷的增多,查詢性能可能就會降低。所以,Elasticsearch會觸發segment合併的線程,把不少小的segment合併成更大的segment,而後刪除小的segment,當這些標記爲刪除的segment不會被複制到新的索引段中。
Elasticseach查詢:
Elasticseach查詢分爲兩種,結構化查詢和全文查詢;
儘管統一稱之爲query DSL,事實上Elasticsearch中存在兩種DSL:查詢DSL(query DSL)和過濾DSL(filter DSL)。
查詢子句和過濾子句的天然屬性很是相近,但在使用目的上略有區別。
簡單來說,當執行full-text查詢或查詢結果依賴於相關度分值時應該使用查詢DSL,當執行精確值(extac-value)查詢或查詢結果僅有「yes」或「no」兩種結果時應該使用過濾DSL。
Filter DSL計算及過濾速度較快,且適於緩存,所以可有效提高後續查詢請求的執行速度。而query DSL不只要查找匹配的文檔,還須要計算每一個文件的相關度分值,所以爲更重量級的查詢,其查詢結果不會被緩存。
不過,得益於倒排索引,一個僅返回少許文檔的簡單query或許比一個跨數百萬文檔的filter執行起來並得顯得更慢。
Elasticsearch支持許多的query和filter,但最經常使用的也不過幾種。
Filter DSL中常見的有term Filter、terms Filter、range Filter、exists and missing Filters和bool Filter。
而Query DSL中常見的有match_all、match 、multi_match及bool Query。鑑於時間關係,這裏再也不細述,朋友們可參考官方文檔學習。
Queries用於查詢上下文,而filters用於過濾上下文,不過,Elasticsearch的API也支持此兩者合併運行。
組合查詢可用於合併查詢子句,組合過濾用於合併過濾子句,然而,Elasticsearch的使用習慣中,也常會把filter用於query上進行過濾。不過,不多有機會須要把query用於filter上的。
結構化搜索:是指查詢包含內部結構的數據。日期,時間,和數字都是結構化的:它們有明確的格式給你執行邏輯操做。通常包括比較數字或日期的範圍,或肯定兩個值哪一個大。
文本也能夠被結構化。一包蠟筆有不一樣的顏色:紅色,綠色,藍色。一篇博客可能被打上 分佈式 和 搜索的標籤。電子商務產品有商品統一代碼(UPCs) 或其餘有着嚴格格式的標識。
經過結構化搜索,你的查詢結果始終是 是或非;是否應該屬於集合。結構化搜索不關心文檔的相關性或分數,它只是簡單的包含或排除文檔。
這必須是有意義的邏輯,一個數字不能比同一個範圍中的其餘數字更多。它只能包含在一個範圍中,或不在其中。相似的,對於結構化文本,一個值必須相等或不等。這裏沒有 更匹配 的概念。
所謂的全文搜索查詢一般是指在給定的文本域內部搜索指定的關鍵字,但搜索操做該須要真正理解查詢者的目的,例如:
(1) 搜索「UK」應該返回包含「United Kingdom」的相關文檔;
(2) 搜索「jump」應該返回包含「JUMP」、「jumped」、「jumps」、「jumping」甚至是「leap」的文檔;
爲了完成此類全文搜域的搜索,ES必須首先分析文本並將其構建成爲倒排索引(inverted index),倒排索引由各文檔中出現的單詞列表組成,列表中的各單詞不能重複且須要指向其所在的各文檔。
所以,爲了建立倒排索引,須要先將各文檔中域的值切分爲獨立的單詞(也稱爲term或token),然後將之建立爲一個無重複的有序單詞列表。這個過程稱之爲「分詞(tokenization)」。
其次,爲了完成此類full-text域的搜索,倒排索引中的數據還需進行「正規化(normalization)」爲標準格式,才能評估其與用戶搜索請求字符串的類似度。
這裏的「分詞」及「正規化」操做也稱爲「分析(analysis)」。
Analysis過程由兩個步驟的操做組成:首先將文本切分爲terms(詞項)以適合構建倒排索引,其次將各terms正規化爲標準形式以提高其「可搜索度」。這兩個步驟由分析器(analyzers)完成。
一個分析器一般須要由三個組件構成:字符過濾器(Character filters)、分詞器(Tokenizer)和分詞過濾器(Token filters)組成。
字符過濾器:在文本被切割以前進行清理操做,例如移除HTML標籤,將&替換爲字符等;
分詞器:將文本切分爲獨立的詞項;簡單的分詞器一般是根據空白及標點符號進行切分;
分詞過濾器:轉換字符(如將大寫轉爲小寫)、移除詞項(如移除a、an、of及the等)或者添加詞項(例如,添加同義詞);
Elasticsearch內置了許多字符過濾器、分詞器和分詞過濾器,用戶可按需將它們組合成「自定義」的分析器。
與SOLR比對:
三種使用方式: