一、基礎理論知識
介紹
ElasticSearch 是一個近實時的搜尋平臺。也就是說當你索引一個文件時可能出現輕微的延遲(一般都是秒級別),公司的logcenter出現的延時是出現在Kafka2ES層,而非索引層。
ElasticSearch 是一個分散式可擴充套件的實時搜尋和分析引擎,一個建立在全文搜尋引擎 Apache Lucene(TM) 基礎上的搜尋引擎。當然 ElasticSearch 並不僅僅是 Lucene 那麼簡單,它不僅包括了全文搜尋功能,還可以進行以下工作:
一個分散式的實時文件儲存,每個欄位都可以被索引與搜尋
一個分散式實時分析搜尋引擎
能勝任上百個服務節點的擴充套件,並支援 PB 級別的結構化或者非結構化資料
ElasticSearch英文翻譯:彈性搜尋。
基本概念
可以這樣理解:ElasticSearch是一個面向文件型的資料庫,一條資料在裡面就是一個文件,用JSON作為文件序列化格式。下面是一份ElasticSearch和關係型資料庫術語的對比關係表:
MySQL
ElasticSearch
Database(資料庫)
對應的術語
含義
索引(Index)
一系列文件的集合,類似於mysql中資料庫的概念
Table(表)
型別(type)
在Index裡面可以定義不同的type,type的概念類似於mysql中表的概念,是一系列具有相同特徵資料的結合。
Row (行)
文件(Document)
文件的概念類似於mysql中的一條儲存記錄,並且為json格式,在Index下的不同type下,可以有許多document。
Column (列)
欄位(Fields)
Index (索引)
Everything Indexed by default (所有欄位預設都被索引)
SQL (結構化查詢語言)
Query DSL (查詢專用語言)
Shards
在資料量很大的時候,進行水平的擴充套件,提高搜尋效能。
分片只儲存了索引中所有資料的一部分。
我們的文件儲存在分片中,並且在分片中被索引,但是我們的應用程式不會直接與它們通訊,取而代之的是,直接與索引通訊。
文件儲存在分片中,然後分片分配到你叢集中的節點上。當你的叢集擴容或縮小,Elasticsearch將會自動在你的節點間遷移分片,以使叢集保持平衡。
Replicas
防止某個分片的資料丟失,可以並行得在備份資料裡及搜尋提高效能。
優勢
優勢
含義
橫向可擴充套件性
增加伺服器可直接配置在叢集中,只需要保證cluster.name一致即可。
分片機制
能夠提供更好的分佈性,分而治之的方式來提升處理效率。
高可用
提供複製備份(replica)機制。
實時性
通過將磁碟上的檔案放入檔案快取系統來提高查詢速度。
關於資料庫的水平擴充套件和豎直擴充套件:對於大多數資料庫而言,橫向擴充套件意味著你的程式將做非常大的改動才能利用這些新新增的裝置。對比來說,Elasticsearch天生就是分散式的,它知道如何管理節點來提供高擴充套件和高可用。這意味著你的程式不需要關心這些。 只要在建立叢集(cluster)、節點(node)和分片(shards)的時候,按照一定的規則,則能按照你的需求進行擴充套件,並保證在硬體故障的時候資料依然安全。
為說明分片和複製分片的含義,以及如何擴充套件,這裡舉一個栗子:
(1)、啟動一個空節點,這時它沒有索引也沒有文件資料。
(2)、我們新增了一個名為log的索引,設定它有三個主分片。(ES預設是5個主分片)。
(3)、單一節點執行很容易出現單點故障--資料丟失,這時我們擴充套件第二個節點,設定相同的cluster.name就可以加入同個叢集,設定log索引每個主分片有一個複製分片,這時任意一個節點故障都能依然支援客戶端的查詢需求。
(4)、這時我們繼續擴充套件,擴充套件第三個節點,ES叢集會重新組織自己,分片會重新被分配以達到平衡負載,這時每個節點只有兩個分片,與之前相比少了一個,意味著每個節點的分片有更多的資源,比如CPU、I/O等。
(5)、如果一個節點只有一個分片的話,那麼該分片就可獨享當前節點的所有資源。如果我們需要擴充套件到6個節點以上?主分片的數量在建立索引時已經確定,那麼我們可以增加複製分片的數量,可以設定每個分片有一個複製分片為兩個。
(6)、ES可以應對單點故障,這時我們殺掉一個節點程式,且是主節點,ES會在瞬間選舉出一個新的主節點,且能夠支援所有資料的查詢訪問。
索引
關係型資料庫的B-/B+Tree,ES採用倒排索引,ES索引的一切設計都是為了提高搜尋的效能。
B-/B+Tree索引:
是為優化寫入的索引結構,特點是二叉查詢效率為logN,同時插入新的節點不必移動全部節點,所以用樹型結構儲存索引,能同時兼顧插入和查詢的效能。
倒排索引:
倒排索引的結構:
舉個例子:
ID
Name
Age
Sex
1
Kate
24
女
2
John
24
男
3
Bill
29
男
那麼ES建立的索引如下:
Name:
Term
Posting List
Kate
[1]
John
[2]
Bill
[3]
Age:
Term
Posting List
24
[1,2]
29
[3]
Sex:
Term
Posting List
男
[2,3]
女
[1]
如上,Elasticsearch分別為每個field都建立了一個倒排索引,Kate, John, 24, Female這些叫term,而1,2就是Posting List。Posting list就是一個int的陣列,儲存了所有符合某個term的文件id。在ES的每一部分中都採用了一些優化及壓縮技術,例如Term Index採用類似字典的索引頁的方式,可以理解為一棵樹,Term Dictionary儲存block,從Term Index找到對應的節點後再去Term Dictionary中尋找對應的block,從而磁碟去尋找Term。
這樣簡化儲存後,ES仍然沒有滿足,為了將Term Index、Term Dictionary及Posting List儲存入記憶體,Term Index使用了FST的壓縮,Posting List採用:增量編碼壓縮,將大數變小數,按位元組儲存的方式進行壓縮。
Posting List的壓縮:
二、查詢
和ES的互動方式取決於你是否使用JAVA。以下我們是以JAVA為例對ES的查詢進行說明。
JAVA API
如果你正在使用 Java,在程式碼中你可以使用 ElasticSearch 內建的兩個客戶端:節點客戶端(Node client)、傳輸客戶端(Transport client)。Java客戶端預設埠是9300,並且使用ES的原生傳輸協議和叢集進行互動。
RESTful API with JSON over HTTP
簡介
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'複製程式碼
被 < > 標記的部件 | 含義 |
VERB | 適當的 HTTP 方法 或 謂詞 : GET`、 `POST`、 `PUT`、 `HEAD 或者 `DELETE`。 |
PROTOCOL | http 或者 https`(如果你在 ElasticSearch 前面有一個 `https 代理) |
HOST | ElasticSearch 叢集中任意節點的主機名,或者用 localhost 代表本地機器上的節點。 |
PORT | 執行 ElasticSearch HTTP 服務的埠號,預設是 9200 。 |
PATH | API 的終端路徑(例如 _count 將返回叢集中文件數量)。Path 可能包含多個元件,例如:_cluster/stats 和 _nodes/stats/jvm 。 |
QUERY_STRING | 任意可選的查詢字串引數 (例如 pretty 將格式化地輸出 JSON 返回值,使其更容易閱讀) |
BODY | 一個 JSON 格式的請求體 (如果請求需要的話) |
舉兩個栗子:
(1)、計算叢集中文件的數量,我們可以用這個:
curl -XGET 'http://localhost:9200/_count?pretty' -d '
{
"query": {
"match_all": {}
}
}複製程式碼
ES將返回一個HTTP狀態碼(例如:200 OK`)和(除`HEAD`請求)一個JSON 格式的返回值。JSON 體如下:
{
"count" : 0,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
}
}複製程式碼
(2)、以新美大日誌中心的查詢為例:
curl -XPOST 'http://es.data.sankuai.com/log.mapi-log-service.userbehaviours_all/_search?pretty' -d'
{
"query": {
//TODO:查詢語句
},
"size":"100"
}'複製程式碼
檢索
兩種方式:傳送HTTP GET請求進行檢索、使用ES查詢表示式 (DSL) 檢索。
第一種方式即構造HTTP GET請求:(以下為縮寫格式,即省略了請求中所有的相同部分,例如主機名、埠號以及curl命令本身,非完整請求)
參考:www.elastic.co/guide/cn/el…
curl -XGET /megacorp/employee/1複製程式碼
返回資訊包含一些基本資訊以及搜尋的JSON後設資料:
{
"_index" : "megacorp",
"_type" : "employee",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
}複製程式碼
第二種方式即使用使用ES查詢表示式 (DSL) 檢索:將請求引數按照ES約定的格式構造為一個JSON進行請求。
參考:www.elastic.co/guide/cn/el…
常用的查詢:
查詢方式 | 含義 | 使用方法 | 備註 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
term過濾 | term主要用於精確匹配哪些值,比如數字,日期,布林值或 not_analyzed 的字串。 not_analyzed 的字串:未經切詞的文字資料型別。 |
| |||||||||||
terms過濾 | terms 跟 term 有點類似,但 terms 允許指定多個匹配條件。 如果某個欄位指定了多個值,那麼document需要一起去做匹配。 |
| |||||||||||
range | range過濾允許我們按照指定範圍查詢一批資料。 |
| 範圍操作符包含:
| ||||||||||
exists和missing | exists 和 missing 過濾可以用於查詢文件中是否包含指定欄位或沒有某個欄位,類似於SQL語句中的IS_NULL條件。 這兩個過濾只是針對已經查出一批資料來,但是想區分出某個欄位是否存在的時候使用。 |
| |||||||||||
bool過濾 | bool 過濾可以用來合併多個過濾條件查詢結果的布林邏輯,它包含一下操作符: must :: 多個查詢條件的完全匹配,相當於 and。 must_not :: 多個查詢條件的相反匹配,相當於 not。 should :: 至少有一個查詢條件匹配, 相當於 or。 這些引數可以分別繼承一個過濾條件或者一個過濾條件的陣列 |
|