ElasticSearch底層原理探秘

一、ES基于_version進行樂觀鎖并發(fā)控制
post /index/type/id/_update?retry_on_conflict=5&version=6
①內(nèi)部_version版本號:
第一次創(chuàng)建document的_version版本號為1,以后每次對這個document修改或刪除操作,_version自動加1。
同時帶上數(shù)據(jù)的版本號,確保es中數(shù)據(jù)的版本號,跟客戶端中的數(shù)據(jù)的版本號是相同的,才能修改。
retry_on_conflict,版本沖突時重試次數(shù)。
②external version
可以基于你自己維護的一個版本號來進行并發(fā)控制。舉個列子,加入你的數(shù)據(jù)在mysql里也有一份,然后你的應(yīng)用系統(tǒng)本身就維護了一個版本號,無論是什么自己生成的,程序控制的。這個時候,你進行樂觀鎖并發(fā)控制的時候,可能并不是想要用es內(nèi)部的_version來進行控制,而是用你自己維護的那個version來進行控制。
二、document路由原理
①路由算法:shard = hash(routing) % number_of_primary_shards
②決定一個document在哪個shard上,最重要的一個值就是routing值,默認(rèn)是_id,也可手動指定,相同的routing值,每次過來,從hash函數(shù)中,產(chǎn)出的hash值一定是相同的
例:手動指定一個routing value,比如 put /index/type/id?routing=user_id
③這就是primary shard數(shù)量不可變的原因。
三、寫一致性原理
put /index/type/id?consistency=quorum
①one:要求我們這個寫操作,只要有一個primary shard是active活躍可用的,就可以執(zhí)行
②all:要求我們這個寫操作,必須所有的primary shard和replica shard都是活躍的,才可以執(zhí)行這個寫操作
③quorum(默認(rèn)):默認(rèn)的值,要求所有的shard中,必須是大部分的shard都是活躍的,可用的,才可以執(zhí)行這個寫操作(1個節(jié)點例外)
算法:number_of_replicas = int((primary + number_of_replicas) / 2 ) + 1,當(dāng)number_of_replicas>1時才生效
quorum不齊全時,默認(rèn)等待1分鐘,可設(shè)置timeout=100ms,timeout=30s,timeout=1m
四、增刪改內(nèi)部原理
①客戶端選擇一個節(jié)點發(fā)送請求,這個節(jié)點叫coordinating node(協(xié)調(diào)節(jié)點)
②coordinating node,對document進行路由,將請求轉(zhuǎn)發(fā)給對應(yīng)的node(有primary shard)
③實際的node上的primary shard處理請求,然后將數(shù)據(jù)同步到replica node
④coordinating node,如果發(fā)現(xiàn)primary node和所有replica node都完成操作之后,就返回響應(yīng)結(jié)果給客戶端
五、document寫入機制原理
①數(shù)據(jù)寫入內(nèi)存buffer緩沖和translog日志文件
②每隔一秒鐘,buffer中的數(shù)據(jù)被寫入新的segment file,并進入os cache,此時segment被打開并供search使用
③buffer被清空
④重復(fù)1~3,新的segment不斷添加,buffer不斷被清空,而translog中的數(shù)據(jù)不斷累加
⑤當(dāng)translog長度達(dá)到一定程度的時候,commit操作發(fā)生
(5-1)buffer中的所有數(shù)據(jù)寫入一個新的segment,并寫入os cache,打開供使用
(5-2)buffer被清空
(5-3)一個commit ponit被寫入磁盤,標(biāo)明了所有的index segment
(5-4)filesystem cache中的所有index segment file緩存數(shù)據(jù),被fsync強行刷到磁盤上
(5-5)現(xiàn)有的translog被清空,創(chuàng)建一個新的translog

每秒一個segment file,文件過多,而且每次search都要搜索所有的segment,很耗時
默認(rèn)會在后臺執(zhí)行segment merge操作,在merge的時候,被標(biāo)記為deleted的document也會被徹底物理刪除
每次merge操作的執(zhí)行流程
(1)選擇一些有相似大小的segment,merge成一個大的segment
(2)將新的segment flush到磁盤上去
(3)寫一個新的commit point,包括了新的segment,并且排除舊的那些segment
(4)將新的segment打開供搜索
(5)將舊的segment刪除
POST /my_index/_optimize?max_num_segments=1,盡量不要手動執(zhí)行,讓它自動默認(rèn)執(zhí)行就可以了

近實時:
數(shù)據(jù)寫入os cache,并被打開供搜索的過程,叫做refresh,默認(rèn)是每隔1秒refresh一次。也就是說,每隔一秒就會將buffer中的數(shù)據(jù)寫入一個新的index segment file,先寫入os cache中。所以,es是近實時的,數(shù)據(jù)寫入到可以被搜索,默認(rèn)是1秒。
手動refresh:
PUT /my_index
{
"settings": {
"refresh_interval": "30s"
}
}
六、查詢內(nèi)部原理
①客戶端發(fā)送請求到任意一個node,成為coordinate node
②coordinate node對document進行路由,將請求轉(zhuǎn)發(fā)到對應(yīng)的node,此時會使用round-robin隨機輪詢算法,在primary shard以及其所有replica中隨機選擇一個,讓讀請求負(fù)載均衡
③接收請求的node返回document給coordinate node
④coordinate node返回document給客戶端
⑤特殊情況:document如果還在建立索引過程中,可能只有primary shard有,任何一個replica shard都沒有,此時可能會導(dǎo)致無法讀取到document,但是document完成索引建立之后,primary shard和replica shard就都有了
七、filter執(zhí)行原理
為每個在倒排索引中搜索到的結(jié)果,構(gòu)建一個bitset,如[0, 0, 0, 1, 0, 1]
遍歷每個過濾條件對應(yīng)的bitset,優(yōu)先從最稀疏的開始搜索,查找滿足所有filter條件的document,直到bitset遍歷完
caching bitset,跟蹤query,在最近256個query中超過一定次數(shù)的過濾條件,緩存其bitset。對于小segment(<1000,或<3%),不緩存bitset。
如果document有新增或修改,那么cached bitset會被自動更新
八、結(jié)果跳躍(Bouncing Results)
preference決定了哪些shard會被用來執(zhí)行搜索操作
兩個document排序,field值相同;不同的shard上,可能排序不同;每次請求輪詢打到不同的replica shard上;
每次頁面上看到的搜索結(jié)果的排序都不一樣,這就是bouncing result,也就是跳躍的結(jié)果。
解決方案就是將preference設(shè)置為一個字符串,比如說user_id,讓每個user每次搜索的時候,都使用同一個replica shard去執(zhí)行,就不會看到bouncing results了
九、倒排索引
1.倒排示例
doc1:I really liked my small dogs, and I think my mom also liked them.
doc2:He never liked any dogs, so I hope that my mom will not expect me to liked him.
倒排索引的建立:
word doc1 doc2

I * *
really *
like * * liked --> like
my * *
little * small --> little
dog * * dogs --> dog
and *
think *
mom * *
also *
them *
He *
never *
any *
so *
hope *
that *
will *
not *
expect *
me *
to *
him *

搜索:mother like little dog
結(jié)果:doc1和doc2,都會搜索出來
2.倒排索引的結(jié)構(gòu)
①包含這個關(guān)鍵詞的document list
②包含這個關(guān)鍵詞的所有document的數(shù)量:IDF(inverse document frequency)
③這個關(guān)鍵詞在每個document中出現(xiàn)的次數(shù):TF(term frequency)
④這個關(guān)鍵詞在這個document中的次序
⑤每個document的長度:length norm
⑥包含這個關(guān)鍵詞的所有document的平均長度
3.倒排索引不可變的好處
①不需要鎖,提升并發(fā)能力,避免鎖的問題
②數(shù)據(jù)不變,一直保存在os cache中,只要cache內(nèi)存足夠
③filter cache一直駐留在內(nèi)存,因為數(shù)據(jù)不變
④可以壓縮,節(jié)省cpu和io開銷
4.倒排索引不可變的壞處
①每次都要重新構(gòu)建整個索引
十、正排索引(待續(xù))

十一、TF/IDF算法
1.TF/IDF
TF: term frequency
一個term在一個doc中,出現(xiàn)的次數(shù)越多,那么最后給的相關(guān)度評分就會越高
IDF:inversed document frequency
一個term在所有的doc中,出現(xiàn)的次數(shù)越多,那么最后給的相關(guān)度評分就會越低
length norm
hello搜索的那個field的長度,field長度越長,給的相關(guān)度評分越低;
最后,會將hello這個term,對doc1的分?jǐn)?shù),綜合TF,IDF,length norm,計算出來一個綜合性的分?jǐn)?shù)
2.vector space model
多個term對一個doc的總分?jǐn)?shù),計算出一個query vector(向量)
每個doc vector計算出對query vector的弧度,最后基于這個弧度給出一個doc相對于query中多個term的總分?jǐn)?shù)
弧度越大,分?jǐn)?shù)月底; 弧度越小,分?jǐn)?shù)越高
如果是多個term,那么就是線性代數(shù)來計算,無法用圖表示

轉(zhuǎn)自:https://blog.csdn.net/zhou870498/article/details/80516692

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。