為什麼使用 ES?
在傳統的資料庫中,如果使用某列記錄某件商品的標題或簡介。在檢索時要想使用關鍵詞來查詢某個記錄,那麼是很困難的,假設搜尋關鍵詞 "小米",那麼 sql 語句就是
select * from product where title like concat("%","小米","%")
這樣即使 title 列上包含索引,索引也會失效。而如果使用全文索引,因為 B+ 樹不支援全文索引,所以選擇了全文索引就失去了 B+ 遍歷高效的優點。所以 ES 就登場了,ES 之所以能高效檢索,主要原因就是其倒排索引的特點。常規的索引,也就是正向索引,查詢的過程是獲取整條資料,然後從整條資料中來匹配關鍵詞,如果包含就返回。而倒排索引是將資料拆分成多個關鍵詞,每個關鍵詞都作為一個倒排索引,然後查詢時直接判斷匹配,如果存在就返回該資料。這樣因為使用了索引效率就極大的提高了。
概念
索引:相當於 MySQL 的庫概念。
型別:相當於 MySQL 的表概念,在 ES7被移除。
文件:相當於 MySQL 的行記錄概念。
欄位:相當於 MySQL 的列概念。
分片:將某一類欄位的文件拆分出來作為一個分片,查詢時如果是這個欄位的,直接去這個分片裡查,可以提高系統整體的吞吐量。
副本:分片的複製,可以提高吞吐量(查詢請求可以直接走副本)和分割槽容錯性(分片所在的節點當機後包含該分片副本的節點可以代替分片作用)
語法結構
query條件
Match:匹配查詢
Balance:用於匹配的欄位(相當於列名),如果是一個字串就是部分匹配,如果是一個數字型別,就是短語查詢。比如address:”a b c”那麼只要包含a,b,c三個中任意一個就算匹配(如果abc連在一起那麼就是包含完整的abc)。短語匹配就相當於Match_phrase,完整匹配
Match_phrase:短語匹配
無論是數字還是字串都是完整匹配,以 address:"abc" 為例,address 包含 "abc" 這個字串就算匹配。
欄位後面加一個“.keyword”表示查詢完全匹配的欄位。以address:”abc”為例,address必須為abc才算匹配。
Match_all:所有欄位
Multi_match:多欄位匹配
多個欄位只要有一個包含就滿足,返回,同時也支援分詞匹配
Address、city列只要有一個包含 mill和movico其中一個就滿足
Bool:複合查詢(多條件複雜查詢)
Must:必須滿足的
Match:匹配查詢,字串模糊查詢,數字精確查詢
Must_not:必須不滿足
Should:可以滿足可以不滿足,滿足的得分更高,排在前面。
Filter:與must一樣,但是不會貢獻得分
Term:檢索數字型別
作用與match一樣,但是它只能檢索數字型別,字串型別不起作用。一般約定term用來檢索數字,其他用match
這裡的 balance 是數字型別,雙引號不需要加。
Terms:類似於 term,匹配多個值
其他
分頁,指定返回的欄位
結果分析
聚合
聚合就是在查詢結果的基礎上,進行分組統計,聚合可以迭代。
AVG:平均值聚合
Terms:型別聚合
...等等
Aggs:表示是聚合,與query一樣
ageAgg:聚合名,
Terms:型別聚合
Field:欄位名
Size:取多少種
結果分析
Key:年齡
Doc_count:結果數
ageAvg:子聚合
Value:子聚合的值
Mapping 對映
對映主要指的是 ES 欄位的單位。主要包括 Integer、long、keyword、text、nested(嵌入式,防止扁平化處理)。
檢視某個索引下的對映
Get /bank/_mapping
新增索引並指定其欄位對映
為某個索引新增新的欄位並指定對映
修改欄位對映
不支援對已存在的索引進行對映修改。可以使用資料遷移來完成。
1、建立臨時索引
2、將之前的索引資料遷移到建立的臨時索引中。
Source:原來的索引, index 來指定索引名也可以在index後面指定type,但是因為7開始移除了型別(相當於資料庫表),所以不需要指定了。
Dest:要轉移的索引名, index 來指定索引名。以當前例子來看就是 newbank
3、將原索引刪除,再建立新的索引,指定對映。
DELETE bank
4、最後將臨時索引資料遷移到新建立的索引中。
扁平化
由於扁平化的佔用,在檢索 first 為 John,last 為 white 的文件時,也會檢索到。所以對於子類中包含兩個或以上屬性的,應該將父類欄位對映設為 nested 型別來防止 ES 的扁平化處理。(預設空間的不會進行扁平化,也就是properties下第一層的不會)
例子如下:
對映:
查詢:
聚合:
對映結果分析
分詞
分詞是 ES 的倒排索引,所以分詞器就決定了 ES 的倒排索引是什麼,預設的分詞器是選擇空格隔開的英文作為一個分詞,中文的話每一個字都會是一個分詞。測試分詞效果:
如果想使用常用的中文分詞,可以使用 ik 分詞器,可以滿足絕大多數的中文分詞,而對於一些特殊的分詞,可以使用配置自定義的分詞,然後將儲存自定義分詞的檔案配置到 ik 分詞器中。
原理
ES架構
ES 是一個開源的高擴充的分散式全文搜尋引擎,這句話表現出 ES 的兩個重要特點,全文搜尋和高擴充分散式。其中全文搜尋可以通過倒排索引體現出,而高擴充的分散式則可以通過其架構體現出。上面就是一個 ES 叢集的架構圖,Node1、Node2、Node3 是三個節點伺服器,其中 Node1 是主節點。在 ES 中配置了三個分片(P0、P1、P2,這三個分片儲存著 ES 整個資料),同時,為了保證 ES 的分割槽容錯性以及查詢效率,每個分片還配置了一個副本(分別是 R0、R1、R2),原分片處理讀和寫操作,副本處理讀操作。在分佈中將副本與原分片拆開放置,避免某個節點當機該分片的資料無法使用。並且在增加節點後,叢集會自動分配分片和副本,保證均勻分佈在不同的節點上。比如:
單節點:
二節點:
三節點:
操作過程
儲存:根據儲存資料的 hash 取餘計算分配的節點位置,選擇分片進行儲存,隨後再將儲存資料更新到所有副本中。預設情況下當大多數副本都同步完成時,就返回儲存完成的通知。這個可以通過 consistency 引數配置,all 表示必須所有的 副本都同步完成才返回儲存完成的通知,one 表示只要主分片同步完成就返回儲存完成的通知(檢索結果可能會被還未同步的副本處理,造成未檢索到),預設值是 quornum。
查詢:輪詢資料所在的分片和副本,傳送請求。
更新:和儲存一樣,取餘得到節點位置,找到分片後更新,再同步到其他副本,等到所有副本都同步完成後再返回更新成功的提示。
倒排索引的結構:倒排索引是無法修改的,好處是不用擔心讀寫不一致的問題,但是缺點也非常明顯,會大量的佔用空間。為了減少空間佔用,引入了段的概念,每個倒排索引都擁有一個段,在每次更新時都會將補充索引寫入段中,然後檢索時就會結合段中的資料和補充索引返回資料。
刪除:每個段中都有一個 .del 檔案,當該倒排索引被下達刪除請求後,就會在 .del 檔案進行標記,隨後檢索就會跳過當前段,也就是邏輯刪除。當倒排索引特別多時,會進行合併,此時會將那些邏輯刪除的段徹底刪除。
持久化:ES 資料的儲存和檢索都在記憶體中,這也是它檢索速度快的原因之一,而其也會定期持久化到磁碟。
在分片執行更新、儲存資料時,底層還伴隨著定期持久化,在寫入時,會先更新記憶體,隨後寫入記憶體中的 translog 裡(避免斷電導致記憶體資料丟失,類似於 mysql 中的 redo log)。然後進行 refresh(預設1s執行一次)到檔案系統快取,更新到系統快取後資料才能被檢索到。並且後臺還會定期 flush(預設30min執行一次) ,將資料持久化到磁碟上。
本文主要參考某谷的ES視訊