> 總結ES基本原理。
> 學習時長評估:3小時。
[TOC]
# 基本描述
NRT:Near Real Time,準實時,延遲1秒。
刷新間隔:refresh_interval,默認1秒。
分片:設置好了不能改,考慮到后期擴容,所以一般設置N < Shard < 2N。
副本:根據業務自行選擇,一般2~3。
# 分頁查詢
from+size:默認限制不能大于1W。
[分頁查詢From&Size VS scroll](https://www.cnblogs.com/xing901022/p/5284902.html)
[深度分頁scroll使用方式](https://www.jianshu.com/p/32f4d276d433)
**建議**:
預先在業務上探討這么做的必要性,并告知會消耗大量資源,以及可能的查詢速度變慢問題。
# 為什么ES查詢比MySQL快

上圖中的Term,翻譯成詞,是索引的最小單位,是經過詞法分詞和語言處理后的字符串。
上圖中的Term Dictionary->Posting List,可以類比數據庫的B樹,而Term Index是一顆Trie樹(字典樹,單詞查找樹),是經過壓縮放在內存中的,Term Dictionary如果太大,內存放不下,但是Term Index一定放得下。
**索引方面:**
數據庫只有一層B+樹索引(Term Dictionary),檢索一個term需要若干次的磁盤檢索操作;
倒排索引,有在Term Dictionary基礎之上的,內存中的Term Index,Term內存檢索完畢,直接就到數據所在硬盤塊,磁盤訪問少,自然快。
**多個維度檢索的時候:**
數據庫多數情況只能用一個索引,然后內存過濾其他條件;ES是同時利用多個Term Index,找到多個Posting List,然后利用Skip List或者bitset與出來。
**參考:**
[如何快速檢索](https://www.infoq.cn/article/database-timestamp-02)
[索引原理分析](https://www.cnblogs.com/dreamroute/p/8484457.html)
[分布式架構及底層原理](https://segmentfault.com/a/1190000015256970)
# 存儲底層原理
## 寫入底層原理
data->translog(5秒或者一次寫操作之后,fsync到硬盤)->commit到硬盤(30分鐘或者translog過大)
data->buffer(1秒一次refresh)->os cache(可以被檢索)->內存segment file(1秒一次)
tangslog的目的是確保操作記錄不丟失,那么問題就來了,tangslog有多可靠?
默認情況下,translog會每隔5秒或者在一個寫請求(index,delete,update,bulk)完成之后執行一次fsync操作,這個進程會在所有的主shard和副本shard上執行。 這個守護進程的操作在客戶端是不會收到200 ok的請求。
**參考:**
[如何保證數據不丟失](https://blog.csdn.net/u010454030/article/details/79617468)
## 段
核心概念:refresh/flush/translog/merge.
寫入磁盤的倒排索引是不可變的。
下一個需要解決的問題是如何在保持不可變好處的同時更新倒排索引。答案是,使用多個索引。
不是重寫整個倒排索引,而是增加額外的索引反映最近的變化。每個倒排索引都可以按順序查詢,從最老的開始,最后把結果聚合。
Elasticsearch底層依賴的Lucene,引入了per-segment search的概念。一個段(segment)是有完整功能的倒排索引,但是現在Lucene中的索引指的是段的集合,再加上提交點(commit point,包括所有段的文件)。
## 段合并
通過每秒自動刷新創建新的段,用不了多久段的數量就爆炸了。
有太多的段是一個問題。每個段消費文件句柄,內存,cpu資源。
更重要的是,每次搜索請求都需要依次檢查每個段。
段越多,查詢越慢。
ES通過后臺合并段解決這個問題。小段被合并成大段,再合并成更大的段。
這是舊的文檔從文件系統刪除的時候。舊的段不會再復制到更大的新段中。
這個過程你不必做什么。當你在索引和搜索時ES會自動處理。
**參考:**
[深入分片](https://juejin.im/post/5b7e2a2c51882543113d80cc)
## ES分片要求
ES一般要求一個集群最多到1萬個分片,否則對master機器的內存和計算帶來很大壓力。
# 索引優化思考和總結
將磁盤里的東西盡量搬進內存,減少磁盤隨機讀取次數(同時也利用磁盤順序讀特性),結合各種奇技淫巧的壓縮算法,用極其苛刻的態度使用內存。
**對于使用Elasticsearch進行索引時需要注意:**
不需要索引的字段,一定要明確定義出來,因為默認是自動建索引的
同樣的道理,對于String類型的字段,不需要analysis的也需要明確定義出來,因為默認也是會analysis的
選擇有規律的ID很重要,隨機性太大的ID(比如java的UUID)不利于查詢