? ? ? ? 當(dāng)我們發(fā)起一個查詢請求之后,ES是怎么處理這個請求然后返回數(shù)據(jù)的呢?今天就來詳細(xì)說一下。
首先看一下整體結(jié)構(gòu):
?
? ? ? ? 在集群模式下一個索引有多個分片,在上圖中有三個節(jié)點(diǎn)(一個主節(jié)點(diǎn)兩個從節(jié)點(diǎn)),一個索引被分為兩個分片(P0、P1),每個主分片有兩個副本分片(R0,R1),每個主分片底層都是對應(yīng)一個Lucene Index(Lucenne索引在前面文章已經(jīng)解釋過,可以往回翻翻),Lucene 索引由多個Segment組成(就是段文件),每個段存儲的就是文檔了。
?當(dāng)我們想要添加一個文檔的流程是怎樣的呢?
? ? ? ? 首先ES在接受到這個請求之后,會通過路由策略來確定需要把文檔存儲在哪一個shard中去,然后節(jié)點(diǎn)接受到請求后就會交由底層的Lucene來處理了。
? ? ? ? Lucene Index會準(zhǔn)備待索引的原文檔,然后對原文檔進(jìn)行分詞處理,形成一系列的term(詞條),然后索引組件對文檔和term處理,形成字典和倒排表。這樣一個文檔基本就被創(chuàng)建好了。
如果是搜索文檔的話又是怎樣處理的呢?
? ? ? ? Lucene首先會對語句進(jìn)行分詞處理,形成一系列的term。然后根據(jù)倒排索引表查找出包含term的文檔,并進(jìn)行合并形成返回結(jié)果。最后對查詢語句與各個文檔的相關(guān)性進(jìn)行評分,最后按分的高低順序返回結(jié)果。
?
?ElasticSearch語法分析器:
? ? ? ? 我們在進(jìn)行搜索的時候,ES是怎么進(jìn)行分詞的?分析過程是:
- 將文本分成適合倒排索引的獨(dú)立詞條
- 將詞條統(tǒng)一化為標(biāo)準(zhǔn)格式提高他們的可搜索性。
完成上面的功能主要靠三個東西:
- 字符過濾器:字符串按順序一個個通過字符過濾器,主要是為了處理一些特殊字符,比如說將&轉(zhuǎn)為and。
- 分詞器:分詞器將字符串分為單個的詞條。
- Token過濾器:將分詞器分析出來的詞條挨個處理,可能會改變詞條(大小寫轉(zhuǎn)換),刪除無用的詞條處理等等...
ES寫入文檔的詳細(xì)流程:?
1.當(dāng)用戶發(fā)起請求后,首先請求會來到master節(jié)點(diǎn),然后通過文檔的id來計算對應(yīng)的分片,然后再發(fā)由相應(yīng)的節(jié)點(diǎn)來處理。
2.當(dāng)分片所在節(jié)點(diǎn)接收到請求后,會把請求先寫入Memory Buffer(這個時候數(shù)據(jù)還沒到segment,還搜不到這個文檔)。然后每隔1s寫入倒File Cache。這個過程叫Refresh。
3.Refresh過程:默認(rèn)是每隔1s將Memory Buffer的數(shù)據(jù)寫入到File Cache。Segment是存儲在文件系統(tǒng)的緩存中的。所以此時文檔是可以被搜到的了。refresh后文檔存儲在文件系統(tǒng)緩存中,這樣就避免了性能IO又可以被搜到,refresh默認(rèn)一秒,為了提高性能可以稍微延長這個時間間隔,比如5s,所以es是準(zhǔn)實(shí)時,達(dá)不到真正的實(shí)時。
4.為了防止數(shù)據(jù)丟失,ES通過Translog來保證數(shù)據(jù)不會丟失。就是在接收到請求后,數(shù)據(jù)同時也會寫入translog中,當(dāng)Filesystem Cache中的數(shù)據(jù)寫入到磁盤中之后,這里面的數(shù)據(jù)才會被清除。這個過程叫flush。
5.文檔在文件系統(tǒng)緩存中可能會有意外情況導(dǎo)致文檔丟失,需要將文檔寫入磁盤,將文檔從文件緩存系統(tǒng)寫入磁盤的過程就叫flush,寫入磁盤后translog就會被清空。
flush過程如下:
(1)緩沖區(qū)的文檔都被寫入到一個新的段,然后緩沖區(qū)會被清空。
(2)一個commit point被寫入硬盤。
(3)文件系統(tǒng)緩存通過fsync被刷新。
(4)老的translog被刪除。
?
merge段
每個文檔到FileCache都會創(chuàng)建一個新的段,段太多了怎么辦?merge過程:
前面說過,在Lucene Index中每次刷新都會產(chǎn)生一個新的段,那么段會越來越多。每一個段都會文件句柄、內(nèi)存和CPU運(yùn)行周期,所以段越多那么搜索也會越慢。所以ES會在后臺通過Merge Segment來解決這個問題。
當(dāng)索引的時候Refresh操作會創(chuàng)建一個新的段并且將段打開以供搜索使用。這時候后臺的合并進(jìn)程選擇一部分大小相似的段,然后將它合并到更大的段當(dāng)中,這并不會中斷索引和搜索。當(dāng)合并結(jié)束之后,老的段就會被刪除:新的段(指合并之后的段)就會被刷新到磁盤,新的段被打開用來搜索,老的段被刪除。
注意:合并大的段需要消耗大量的i/o和CPU資源,如果仍其發(fā)展會影響搜索性能。ES默認(rèn)情況下會對合并流程進(jìn)行資源控制,所以搜索仍然有足夠的資源很好的執(zhí)行。
分布式的寫入流程?
在ES中一般一個索引都會被設(shè)置為多個shard,通過路由規(guī)則將數(shù)據(jù)分為多個數(shù)據(jù)子集,每個數(shù)據(jù)子集提供獨(dú)立的索引和搜索功能。在寫入文檔的時候也會根據(jù)路由規(guī)則(默認(rèn)通過id),將文檔發(fā)給特定的shard進(jìn)行處理,這樣就實(shí)現(xiàn)了分布式。
通過前面介紹我們知道了,當(dāng)數(shù)據(jù)寫入之后一般不會立即寫入磁盤而是在File Cache的Lucene Index中,這時候數(shù)據(jù)還沒有寫入磁盤中,那么有個問題就是這時候機(jī)器宕機(jī)內(nèi)存中的數(shù)據(jù)就會丟失。這時候如何保證?我們前面也就知道是通過trans log。
- 在每個shard中,寫入就被分為兩步,就是先寫Lucene 在寫translog。
- 意思就是寫入請求到達(dá)shard后,先寫Lucene文件,再寫translog文件,然后刷新translog到磁盤上,磁盤寫入成功之后請求返回給用戶。
- 這里為什么會先寫lucene文件再寫translog文件?原因可能就是Lucen的內(nèi)存寫入會有很復(fù)雜的邏輯容易失敗,比如超時分詞等,為了避免translog中有大量的無效記錄,所以就放在前面了。寫入Lucene內(nèi)存后并不是馬上就可以被搜索到了,需要refresh把內(nèi)存中的對象轉(zhuǎn)換為segment后,才可以被搜索到。
- 每隔一段較長的時間,Lucene會把內(nèi)存中的新Segment刷到磁盤,然后索引文件就把持久化了,translog就沒用了,就會被刪掉。
更新文檔
ES的不支持部分字段的更新,更新都是將整個文檔更新,流程如下:
- 收到更新請求后會先從Segment或者translog中讀取出完整的文檔,記錄版本號為V1。
- 然后將請求中的部分要更新的字段和讀取出來的文檔組合成新的完整的文檔,同時更新內(nèi)存中的Version Map。
- 然后再從version Map中讀取該id的最大版本號V2,如果version map中沒有,則從segment或者translog中讀取一下,這里基本都會從versionMap中讀取出來。
- 檢查版本是否沖突,如果沖突了就會回退重新執(zhí)行,如果不沖突就會執(zhí)行新的add請求。
- 然后將文檔doc寫入到Lucene中嗎,回刪除相同id的文檔,然后再將這個文檔寫入進(jìn)去。
- 釋放鎖
?
讀取文檔流程
? ? ? ? 搜索一般都是分兩階段的,首先是匹配文檔id,第二步是在根據(jù)文檔id查找對應(yīng)的文檔id,有點(diǎn)類似mysql的索引回表過程。
1.在初始化查詢階段,查詢會廣播到索引中的每一個分片拷貝。每個分片在本地執(zhí)行搜索并構(gòu)建一個匹配文檔的大小為from+size的優(yōu)先級隊列。
2.每個分片返回各自的優(yōu)先級隊列中 所有文檔的id和排序值 給協(xié)調(diào)節(jié)點(diǎn),它合并這些值到自己的優(yōu)先級隊列中來產(chǎn)生一個全局排序后的結(jié)果列表。
3.接下來協(xié)調(diào)節(jié)點(diǎn)辨別出那些文檔需要被取回并且向相關(guān)的分片提交多個GET請求,每個分片加載文檔一旦所有文檔都被取回,協(xié)調(diào)節(jié)點(diǎn)返回結(jié)果給客戶端。
? ? ? ? 我們知道在Es集群中一般一個索引會被分為多個shard,每個shard在不同的node中,而且每個shard一般還會有副本,增加數(shù)據(jù)的可靠性。那么在查詢的時候會從主節(jié)點(diǎn)或者副本節(jié)點(diǎn)任意選一個來進(jìn)行查詢。在處理一個查詢請求的時候首先需要查詢所有的shard(同一個shard的primary和replica任選一個即可)。每一個shrad都是一個獨(dú)立的搜索引擎,然后返回最匹配的TOP10的結(jié)果。然后返回給協(xié)調(diào)節(jié)點(diǎn),協(xié)調(diào)節(jié)點(diǎn)收集所有的shard的返回結(jié)果,然后通過優(yōu)先級隊列二次排序,選擇top10的結(jié)果,然后再通過id去取完整的文檔,然后返回給用戶。文章來源:http://www.zghlxwxcb.cn/news/detail-430164.html
? ? ? ? 上面所說的先根據(jù)查詢請求取找到合適的id,然后在通過id去取完成的文檔這中兩階段的查詢在ES中稱為query_then_fetch,還有一種一階段就返回完整doc的稱為query_and_fetch,但是一般一階段就返回文檔的適用于只需查詢一個shard的請求。文章來源地址http://www.zghlxwxcb.cn/news/detail-430164.html
到了這里,關(guān)于ElasticSearch創(chuàng)建文檔以及索引文檔的詳細(xì)流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!