es索引的一點點總結(jié)

一、介紹

Elasticsearch 是一個分布式可擴展的實時搜索和分析引擎,一個建立在全文搜索引擎 Apache Lucene(TM) 基礎(chǔ)上的搜索引擎.當然 Elasticsearch 并不僅僅是 Lucene 那么簡單,它不僅包括了全文搜索功能,還可以進行以下工作:

分布式實時文件存儲,并將每一個字段都編入索引,使其可以被搜索。

實時分析的分布式搜索引擎。

可以擴展到上百臺服務(wù)器,處理PB級別(約1000個TB)的結(jié)構(gòu)化或非結(jié)構(gòu)化數(shù)據(jù)。

二、與關(guān)系數(shù)據(jù)庫的對應(yīng)關(guān)系

關(guān)系數(shù)據(jù)庫? ? ? 數(shù)據(jù)庫 ? 表? ? ? 行? ? ? 列(Columns)

Elasticsearch? ? 索引(Index)? ? 類型(type)? ? 文檔(Docments)? ? 字段(Fields)

三、存儲結(jié)構(gòu)

索引 Index

ES將數(shù)據(jù)存儲于一個或多個索引中,索引是具有類似特性的文檔的集合。

它是個邏輯命名空間,類似于數(shù)據(jù)庫概念中的數(shù)據(jù)庫。

類型 Type

類型是索引內(nèi)部的邏輯分區(qū)(category/partition),然而其意義完全取決于用戶需求。因此,一個索引內(nèi)部可定義一個或多個類型(type)。

類似于數(shù)據(jù)庫概念中的一張表。

文檔 Document

文檔是索引和搜索的原子單位,它是包含了一個或多個域(Field)的容器,基于JSON格式進行表示。文檔由一個或多個域組成,每個域擁有一個名字及一個或多個值,有多個值的域通常稱為“多值域”。

每個文檔可以存儲不同的域集,但同一類型下的文檔至應(yīng)該有某種程度上的相似之處。

它是具體事實數(shù)據(jù)的體現(xiàn),類似于數(shù)據(jù)庫概念中的一條記錄。

SHARD 分片

index包含多個shard,每個shard都是一個最小工作單元,承載部分數(shù)據(jù)

每個shard都是一個lucene實例,有完整的建立索引和處理請求的能力。

增減節(jié)點時,shard會自動在nodes之間負載均衡

shard分為primary shard和replica shard,每個document只存在于某一個primary shard以及其對應(yīng)的replica shard中

replica shard是primary shard的副本,負責容錯,以及承擔讀請求負載提高搜索性能。

primary shard的數(shù)量在創(chuàng)建索引的時候就固定了,replica shard的數(shù)量可以隨時修改,primary shard的默認數(shù)量是5,replica默認是1,默認有10個shard,5個primary shard,5個replica shard

primary shard不能和自己的replica shard放在同一個節(jié)點上(否則節(jié)點宕機,primary shard和副本都丟失,起不到容錯的作用),但是可以和其他primary shard的replica shard放在同一個節(jié)點上

SEGMENT

elasticsearch中每個shard每隔1秒都會refresh一次,每次refresh都會生成一個新的segment,一個segment對應(yīng)著硬盤或者緩存(內(nèi)存充當文件系統(tǒng)的)的一個文件,占用一個文件描述符。

translog

事務(wù)日志,在每一次對 Elasticsearch 進行操作時均進行了日志記錄。作為臨時文件存儲在硬盤上。理想中應(yīng)該是任何一次寫入都刷入磁盤,但是性能考慮不可能。實際上是每幾秒中調(diào)用一次fsync刷到磁盤來提高吞吐量。這當然帶來了丟失數(shù)據(jù)的可能。

四、數(shù)據(jù)寫入過程

第一步,新文檔被寫入內(nèi)存,操作被寫入translog

第二步,refresh操作

ES中默認每1秒中進行一次refresh。

refresh操作會清空buffer中的數(shù)據(jù)(translog數(shù)據(jù)不變),在這1秒時間內(nèi)寫入內(nèi)存的新文檔都會被寫入一個文件系統(tǒng)緩存(filesystem cache)中,并構(gòu)成一個分段(segment)新建segment并式segment可以被檢索的到,但是尚未寫入硬盤。


第三步,不斷累積數(shù)據(jù),重復數(shù)據(jù)寫到buffer和translog,每隔一秒將生成一個新的segment,而translog文件將越來越大。


第四步,一定時間后,執(zhí)行flush操作。清空buffer,translog,所有segment處于commit狀態(tài)。

第五步 segment合并寫入磁盤,一旦合并,舊的segment和translog將被刪除。

segment合并極為消耗資源,所以一般情況下ES會對段合并消耗的資源加以限制

五、索引

Elasticsearch最關(guān)鍵的就是提供強大的索引能力,一切設(shè)計都是為了提高搜索性能為了提高讀,難免犧牲寫性能。

? ? 前面看到往Elasticsearch里插入一條記錄,其實就是直接PUT一個json的對象,這個對象有多個fields,插入這些數(shù)據(jù)到Elasticsearch的同時,Elasticsearch還默默1的為這些字段建立索引--倒排索引,因為Elasticsearch最核心功能是搜索。

為啥Elasticsearch使用的倒排索引比關(guān)系型數(shù)據(jù)庫的B-Tree索引快?

復習一下mysql索引:

MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。

數(shù)據(jù)庫查詢是數(shù)據(jù)庫的主要功能之一,最基本的查詢算法是順序查找(linear search)時間復雜度為O(n),顯然在數(shù)據(jù)量很大時效率很低。優(yōu)化的查找算法如二分查找(binary search)、二叉樹查找(binary tree search)等,雖然查找效率提高了。但是各自對檢索的數(shù)據(jù)都有要求:二分查找要求被檢索數(shù)據(jù)有序,而二叉樹查找只能應(yīng)用于二叉查找樹上,但是數(shù)據(jù)本身的組織結(jié)構(gòu)不可能完全滿足各種數(shù)據(jù)結(jié)構(gòu)(例如,理論上不可能同時將兩列都按順序進行組織)。所以,在數(shù)據(jù)之外,數(shù)據(jù)庫系統(tǒng)還維護著滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu)。這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù),這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)上實現(xiàn)高級查找算法。這種數(shù)據(jù)結(jié)構(gòu)就是索引。

什么是B-Tree索引?

上大學讀書時老師教過我們,二叉樹查找效率是logN,同時插入新的節(jié)點不必移動全部節(jié)點,所以用樹型結(jié)構(gòu)存儲索引,能同時兼顧插入和查詢的性能。因此在這個基礎(chǔ)上,再結(jié)合磁盤的讀取特性(順序讀/隨機讀),傳統(tǒng)關(guān)系型數(shù)據(jù)庫采用了B-Tree/B+Tree這樣的數(shù)據(jù)結(jié)構(gòu):


為了提高查詢的效率,減少磁盤尋道次數(shù),將多個值作為一個數(shù)組通過連續(xù)區(qū)間存放,一次尋道讀取多個數(shù)據(jù),同時也降低樹的高度。

描述B-Tree:

首先定義一條數(shù)據(jù)記錄為一個二元組[key, data],key為記錄的鍵值,對于不同數(shù)據(jù)記錄,key是互不相同的;data為數(shù)據(jù)記錄除key外的數(shù)據(jù)。那么B-Tree是滿足下列條件的數(shù)據(jù)結(jié)構(gòu):

1.d為大于1的一個正整數(shù),稱為B-Tree的度;

2.h為B-Tree的高;

3.每個非葉子結(jié)點由n-1個key和n個指針組成,其中d<=n<=2d;

4.每個葉子結(jié)點至少包含一個key和兩個指針,最多包含2d-1個key和2d個指針,葉結(jié)點的指針均為NULL;

5.所有葉結(jié)點都在同一層,深度等于樹高h;

6.key和指針相互間隔,結(jié)點兩端是指針;

7.一個結(jié)點中的key從左至右非遞減排列;

8.如果某個指針在結(jié)點node最左邊且不為null,則其指向結(jié)點的所有key小于v(key1),其中v(key1)為node的第一個key的值。

9.如果某個指針在結(jié)點node最右邊且不為null,則其指向結(jié)點的所有key大于v(keym),其中v(keym)為node的最后一個key的值。

10.如果某個指針在結(jié)點node的左右相鄰key分別是keyi和keyi+1且不為null,則其指向結(jié)點的所有key小于v(keyi+1)且大于v(keyi)。

檢索,首先從根節(jié)點進行二分查找,如果找到則返回對應(yīng)節(jié)點的data,否則對相應(yīng)區(qū)間的指針指向的節(jié)點遞歸進行查找,直到找到節(jié)點或找到null指針,前者查找成功,后者查找失敗

BTree_Search(node, key) {

? ? if (node == null) return null;

? ? foreach(node.key) {

? ? ? ? if (node.key[i] == key) return node.data[i];

? ? ? ? if (node.key[i] > key) return BTree_Search(point[i]->node);

? ? } return BTree_Search(point[i + 1]->node);

}

data =BTree_Search(root, my_key);

關(guān)于B-Tree有一系列有趣的性質(zhì),例如一個度為d的B-Tree,設(shè)其索引N個key,則其樹高h的上限為logd((N+1)/2),檢索一個key,其查找結(jié)點個數(shù)的漸進復雜度為O(logdN)。從這點可以看出,B-Tree是一個非常有效率的索引數(shù)據(jù)結(jié)構(gòu)。

B+Tree有以下不同點:

1.每個結(jié)點的指針上限為2d而不是2d+1。

2.內(nèi)結(jié)點不存儲data,只存儲key;葉子結(jié)點不存儲指針


優(yōu)化:帶有順序訪問指針的B+Tree

磁盤讀取

磁盤示意圖:

文件形式存儲在磁盤上,索引檢索需要磁盤I/O操作。與主存不同,磁盤I/O存在機械運動耗費,因此磁盤I/O的時間消耗是巨大的


同心環(huán)叫做磁道,半徑劃分一段叫扇區(qū),每個扇區(qū)是磁盤的最小存儲單元

確定要讀的數(shù)據(jù)在哪個磁道,哪個扇區(qū)。需要將磁頭放到這個扇區(qū)上方,為了實現(xiàn)這一點,磁頭需要移動對準相應(yīng)磁道,這個過程叫做尋道,所耗費時間叫做尋道時間,然后磁盤旋轉(zhuǎn)將目標扇區(qū)旋轉(zhuǎn)到磁頭下,這個過程耗費的時間叫做旋轉(zhuǎn)時間

磁盤預讀,局部性原理

為了提高效率,要盡量減少磁盤I/O。想要達到這個目的,磁盤往往不是嚴格按需讀取,而是每次都會預讀,即使只需要一個字節(jié),磁盤也會從這個位置開始,順序向后讀取一定長度的數(shù)據(jù)放入內(nèi)存,既局部性原理

當一個數(shù)據(jù)被用到時,其附近的數(shù)據(jù)也通常會馬上被使用。

程序運行期間所需要的數(shù)據(jù)通常比較集中。

預讀的長度一般為頁(page)的整倍數(shù)。頁是計算機管理存儲器的邏輯塊,硬件及操作系統(tǒng)往往將主存和磁盤存儲區(qū)分割為連續(xù)的大小相等的塊,每個存儲塊稱為一頁(在許多操作系統(tǒng)中,頁得大小通常為4k),主存和磁盤以頁為單位交換數(shù)據(jù)。當程序要讀取的數(shù)據(jù)不在主存中時,會觸發(fā)一個缺頁異常,此時系統(tǒng)會向磁盤發(fā)出讀盤信號,磁盤會找到數(shù)據(jù)的起始位置并向后連續(xù)讀取一頁或幾頁載入內(nèi)存中,然后異常返回,程序繼續(xù)運行。

從使用磁盤I/O次數(shù)評價索引結(jié)構(gòu)的優(yōu)劣性:根據(jù)B-Tree的定義,可知檢索一次最多需要訪問h個結(jié)點。數(shù)據(jù)庫系統(tǒng)的設(shè)計者巧妙的利用了磁盤預讀原理,將一個結(jié)點的大小設(shè)為等于一個頁面,這樣每個結(jié)點只需要一次I/O就可以完全載入。為了達到這個目的,在實際實現(xiàn)B-Tree還需要使用如下技巧:

每次新建結(jié)點時,直接申請一個頁面的空間,這樣可以保證一個結(jié)點的大小等于一個頁面,加之計算機存儲分配都是按頁對齊的,就實現(xiàn)了一個node只需一次I/O。

二叉查找樹紅黑樹為啥不行?太高了,物理地址離太遠,沒法預讀。

es索引對應(yīng)表:

| ID | Name | Age? |? Sex? ? |

| -- |:------------:| -----:| -----:|

| 1? | Kate? ? ? ? | 24 | Female

| 2? | John? ? ? ? | 24 | Male

| 3? | Bill? ? ? ? | 29 | Male

ID是Elasticsearch自建的文檔id,那么Elasticsearch建立的索引如下:

Name:

| Term | Posting List |

| -- |:----:|

| Kate | 1 |

| John | 2 |

| Bill | 3 |

Age:

| Term | Posting List |

| -- |:----:|

| 24 | [1,2] |

| 29 | 3 |

Sex:

| Term | Posting List |

| -- |:----:|

| Female | 1 |

| Male | [2,3] |

倒排索引:


Elasticsearch分別為每個field都建立了一個倒排索引,Kate, John, 24, Female這些叫term,而[1,2]就是Posting List。Posting list就是一個int的數(shù)組,存儲了所有符合某個term的文檔id。

看到這里,不要認為就結(jié)束了,精彩的部分才剛開始...

通過posting list這種索引方式似乎可以很快進行查找,如果這里有上千萬的記錄呢?如果是想通過name來查找呢?

Term Dictionary

Elasticsearch為了能快速找到某個term,將所有的term排個序,二分法查找term,logN的查找效率,就像通過字典查找一樣,這就是Term Dictionary。現(xiàn)在再看起來,似乎和傳統(tǒng)數(shù)據(jù)庫通過B-Tree的方式類似啊,為什么說比B-Tree的查詢快呢?

Term Index

B-Tree通過減少磁盤尋道次數(shù)來提高查詢性能,Elasticsearch也是采用同樣的思路,直接通過內(nèi)存查找term,不讀磁盤,但是如果term太多,term dictionary也會很大,放內(nèi)存不現(xiàn)實,于是有了Term Index,就像字典里的索引頁一樣,A開頭的有哪些term,分別在哪頁,可以理解term index是一顆樹:

這棵樹不會包含所有的term,它包含的是term的一些前綴。通過term index可以快速地定位到term dictionary的某個offset,然后從這個位置再往后順序查找。

所以term index不需要存下所有的term,而僅僅是他們的一些前綴與Term Dictionary的block之間的映射關(guān)系,再結(jié)合FST(Finite State Transducers)的壓縮技術(shù),可以使term index緩存到內(nèi)存中。從term index查到對應(yīng)的term dictionary的block位置之后,再去磁盤上找term,大大減少了磁盤隨機讀的次數(shù)。

六、壓縮

1.壓縮term index

FST(Finite State Transducers)

FSTs are finite-state machines that map a term (byte sequence) to an arbitrary output.

FST以字節(jié)的方式存儲所有的term,這種壓縮方式可以有效的縮減存儲空間,使得term index足以放進內(nèi)存,但這種方式也會導致查找時需要更多的CPU資源

2.壓縮 Posting List

Frame Of Reference

增量編碼壓縮,將大數(shù)變小數(shù),按字節(jié)存儲

問題:

1.落數(shù)據(jù),主分片,復制分片

交互過程:https://www.cnblogs.com/niutao/p/10909071.html

在ES5.0以前,按照ES的主副同步策略,主分片本地索引完成后,會將請求forward到副本分片,默認情況下超過半數(shù)副本回復后,主分片才響應(yīng)client端操作成功。

在5.0以后,這個參數(shù)已經(jīng)被wait_for_active_shards參數(shù)(默認值1)取代,即默認情況下只要主分片就可以完成寫操作,否則阻塞至超時或者滿足條件。

在主完成本地索引后,會forward所有 被稱作in-sync copies 的列表里的分片,直到列表所有分片響應(yīng)成功,才響應(yīng)client。如果部分失敗,則會通知master,將故障分片從in-sync copies 列表里剔除,主分片響應(yīng)client,與此同時,master會分配一個新的分片來接替故障的分片。

in-sync copies 的內(nèi)容可以通過API

ET /_cluster/state?filter_path=metadata.indices.your-indexname.in_sync_allocations.*,routing_table.indices.your-indexname.*

2.translog 文件提交

過程:https://blog.csdn.net/lijingjingchn/article/details/107673900

Translog 設(shè)置:http://www.itdecent.cn/p/ffef3be04fd3

官方:https://www.elastic.co/guide/en/elasticsearch/reference/7.2/index-modules-translog.html

3,term index,term Dictionary 怎么創(chuàng)建的

數(shù)據(jù)先寫入內(nèi)存 buffer,然后每隔 1s,將數(shù)據(jù) refresh 到 os cache,到了 os cache 數(shù)據(jù)就能被搜索到(所以我們才說 es 從寫入到能被搜索到,中間有 1s 的延遲)。每隔 5s,將數(shù)據(jù)寫入 translog 文件(這樣如果機器宕機,內(nèi)存數(shù)據(jù)全沒,最多會有 5s 的數(shù)據(jù)丟失),translog 大到一定程度,或者默認每隔 30mins,會觸發(fā) commit 操作,將緩沖區(qū)的數(shù)據(jù)都 flush 到 segment file 磁盤文件中。數(shù)據(jù)寫入 segment file 之后,同時就建立好了倒排索引。

過程+壓縮https://liuyanzhao.com/1330870781428764672.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容