整理:ES索引存儲原理

ES索引存儲原理


不變性


寫到磁盤的倒序索引是不變的:自從寫到磁盤就再也不變。 這會有很多好處:

不需要添加鎖。不存在寫操作,因此不存在多線程更改數據。
提高讀性能。一旦索引被內核的文件系統做了Cache,絕大多數的讀操作會直接從內存而不需要經過磁盤。
提升其他緩存(例如fiter cache)的性能。其他的緩存在該索引的生命週期內保持有效,減少磁盤I/O和計算消耗。


當然,索引的不變性也有缺點。如果你想讓新修改過的文檔可以被搜索到,你必須重新構建整個索引。這在一個index可以容納的數據量和一個索引可以更新的頻率上都是一個限制。

如何在不丟失不變形的好處下讓倒序索引可以更改?答案是:使用不只一個的索引。 新添額外的索引來反映新的更改來替代重寫所有倒序索引的方案。 Lucene引進了per-segment搜索的概念。一個segment是一個完整的倒序索引的子集,所以現在index在Lucene中的含義就是一個segments的集合,每個segment都包含一些提交點(commit point)。

segment工作流程

1.新的文檔在內存中組織。
2.每隔一段時間,buffer將會被提交: 生成一個新的segment(一個額外的新的倒序索引)並被寫到磁盤,同時一個
  新的提交點(commit point)被寫入磁盤,包含新的segment的名稱。 磁盤fsync,所有在內核文件系統中的數據等待被寫入到磁盤,來保障它們被物理寫入。
3.新的segment被打開,使它包含的文檔可以被索引。
4.內存中的buffer將被清理,準備接收新的文檔。


當一個新的請求來時,會遍歷所有的segments。詞條分析程序會聚合所有的segments來保障每個文檔和詞條相關性的準確。通過這種方式,新的文檔輕量的可以被添加到對應的索引中。

刪除和更新


segments是不變的,所以文檔不能從舊的segments中刪除,也不能在舊的segments中更新來映射一個新的文檔版本。取之的是,每一個提交點都會包含一個.del文件,列舉了哪一個segmen的哪一個文檔已經被刪除了。 當一個文檔被”刪除”了,它僅僅是在.del文件裏被標記了一下。被”刪除”的文檔依舊可以被索引到,但是它將會在最終結果返回時被移除掉。

文檔的更新同理:當文檔更新時,舊版本的文檔將會被標記爲刪除,新版本的文檔在新的segment中建立索引。也許新舊版本的文檔都會本檢索到,但是舊版本的文檔會在最終結果返回時被移除。

實時索引


在上述的per-segment搜索的機制下,新的文檔會在分鐘級內被索引,但是還不夠快。 瓶頸在磁盤。將新的segment提交到磁盤需要fsync來保障物理寫入。但是fsync是很耗時的。它不能在每次文檔更新時就被調用,否則性能會很低。 現在需要一種輕便的方式能使新的文檔可以被索引,這就意味着不能使用fsync來保障。 在ES和物理磁盤之間是內核的文件系統緩存。之前的描述中,在內存中索引的文檔會被寫入到一個新的segment。但是現在我們將segment首先寫入到內核的文件系統緩存,這個過程很輕量,然後再flush到磁盤,這個過程很耗時。但是一旦一個segment文件在內核的緩存中,它可以被打開被讀取

更新持久化


不使用fsync將數據flush到磁盤,我們不能保障在斷電後或者進程死掉後數據不丟失。ES是可靠的,它可以保障數據被持久化到磁盤。一個完全的提交會將segments寫入到磁盤,並且寫一個提交點,列出所有已知的segments。當ES啓動或者重新打開一個index時,它會利用這個提交點來決定哪些segments屬於當前的shard。 如果在提交點時,文檔被修改會怎麼樣?

translog日誌提供了一個所有還未被flush到磁盤的操作的持久化記錄。當ES啓動的時候,它會使用最新的commit point從磁盤恢復所有已有的segments,然後將重現所有在translog裏面的操作來添加更新,這些更新發生在最新的一次commit的記錄之後還未被fsync。

translog日誌也可以用來提供實時的CRUD。當你試圖通過文檔ID來讀取、更新、刪除一個文檔時,它會首先檢查translog日誌看看有沒有最新的更新,然後再從響應的segment中獲得文檔。這意味着它每次都會對最新版本的文檔做操作,並且是實時的。

Segment合併


通過每隔一秒的自動刷新機制會創建一個新的segment,用不了多久就會有很多的segment。segment會消耗系統的文件句柄,內存,CPU時鐘。最重要的是,每一次請求都會依次檢查所有的segment。segment越多,檢索就會越慢。

ES通過在後臺merge這些segment的方式解決這個問題。小的segment merge到大的,大的merge到更大的。。。

這個過程也是那些被”刪除”的文檔真正被清除出文件系統的過程,因爲被標記爲刪除的文檔不會被拷貝到大的segment中。

Segment:

Inverted Index

Inverted Index主要包括兩部分:

  1. 一個有序的數據字典Dictionary(包括單詞Term和它出現的頻率)。
  2. 與單詞Term對應的Postings(即存在這個單詞的文件)。        

Stored Fields:

當我們想要查找包含某個特定標題內容的文件時,Inverted Index就不能很好的解決這個問題,所以Lucene提供了另外一種數據結構Stored Fields來解決這個問題。本質上,Stored Fields是一個簡單的鍵值對key-value。默認情況下,ElasticSearch會存儲整個文件的JSON source。

Document Values

官網:https://www.elastic.co/guide/cn/elasticsearch/guide/current/docvalues.html#docvalues

即使這樣,我們發現以上結構仍然無法解決諸如:排序、聚合、facet,因爲我們可能會要讀取大量不需要的信息。
所以,另一種數據結構解決了此種問題:Document Values。這種結構本質上就是一個列式的存儲,它高度優化了具有相同類型的數據的存儲結構。

爲了提高效率,ElasticSearch可以將索引下某一個Document Value全部讀取到內存中進行操作,這大大提升訪問速度,但是也同時會消耗掉大量的內存空間。

總之,這些數據結構Inverted Index、Stored Fields、Document Values及其緩存,都在segment內部。

Cache

當一個真實請求來的時候,如下所示:


存儲索引的流程
從數據到索引,數據的流向如下:

數據生成索引存入內存Buffer,同時存入TranSlog
內存中的數據每隔一秒以segment的形式寫入系統文件緩存
每隔一段時間,文件緩存中的數據存入硬盤,同時清除對應的translog


Lucene 工作流程


如何創建索引
找出文檔

文件一:Students should be allowed to Go out with their friends, but not allowed to drink beer.

文件二:My friend Jerry went to school to see his students but found them drunk which is not allowed.

將原文檔傳給分次組件(Tokenizer)

分詞組件(Tokenizer)會做以下幾件事情( 此過程稱爲Tokenize) :

將文檔分成一個一個單獨的單詞。
去除標點符號。
去除停詞(Stop word) 。
所謂停詞(Stop word)就是一種語言中最普通的一些單詞,由於沒有特別的意義,因而大多數情況下不能成爲搜索的關鍵詞,因而創建索引時,這種詞會被去掉而減少索引的大小。經過分詞(Tokenizer) 後得到的結果稱爲詞元(Token) 。
在我們的例子中,便得到以下詞元(Token):
“Students”,“allowed”,“go”,“their”,“friends”,“allowed”,“drink”,“beer”,“My”,“friend”,“Jerry”,“went”,“school”,“see”,

將得到的詞元(Token)傳給語言處理組件(Linguistic Processor)

語言處理組件(linguistic processor)主要是對得到的詞元(Token)做一些同語言相關的處理。
對於英語,語言處理組件(Linguistic Processor) 一般做以下幾點:

變爲小寫(Lowercase) 。
將單詞縮減爲詞根形式,如“cars ”到“car ”等。這種操作稱爲:stemming 。
將單詞轉變爲詞根形式,如“drove ”到“drive ”等。這種操作稱爲:lemmatization 。
在我們的例子中,經過語言處理,得到的詞(Term)如下:
“student”,“allow”,“go”,“their”,“friend”,“allow”,“drink”,“beer”,“my”,“friend”,“jerry”,“go”,“school”,“see”,“his”,“student”,“find”,“them

將得到的詞(Term)傳給索引組件(Indexer)

索引 組件(Indexer)主要做以下幾件事情:

  1. 利用得到的詞(Term)創建一個字典。
  2. 對字典按字母順序進行排序。
  3. 合併相同的詞(Term) 成爲文檔倒排(Posting List) 鏈表。
  4. 到此爲止索引已經建好。

如何檢索數據:

  1. 用戶輸入查詢語句
  2. 對查詢語句進行詞法分析,語法分析,及語言處理
  3. 詞法分析主要用來識別單詞和關鍵字。
  4. 語法分析主要是根據查詢語句的語法規則來形成一棵語法樹。
  5. 語言處理同索引過程中的語言處理幾乎相同。
  6. 如learned變成learn,tables 變成table等。
  7. 搜索索引,得到符合語法樹的文檔。

此步驟有分幾小步:

  1. 首先,在反向索引表中,分別找出包含lucene,learn,hadoop的文檔鏈表。
  2. 其次,對包含lucene,learn的鏈表進行合併操作,得到既包含lucene又包含learn的文檔鏈表。
  3. 然後,將此鏈表與hadoop的文檔鏈表進行差操作,去除包含hadoop的文檔,從而得到既包含lucene又包含learn而且不包含hadoop的文檔鏈表。

此文檔鏈表就是我們要找的文檔。

根據得到的文檔和查詢語句的相關性,對結果進行排序

  1. 首先,一個文檔有很多詞(Term)組成
  2. 其次對於文檔之間的關係,不同的Term重要性不同
  3. 找出詞(Term) 對文檔的重要性的過程稱爲計算詞的權重(Term weight) 的過程。
  4. 判斷詞(Term) 之間的關係從而得到文檔相關性的過程應用一種叫做向量空間模型的算法

計算權重的過程:
影響一個詞(Term)在一篇文檔中的重要性主要有兩個因素:

  1. Term Frequency (tf):即此Term在此文檔中出現了多少次。tf 越大說明越重要。
  2. Document Frequency (df):即有多少文檔包含次Term。df 越大說明越不重要。
     


這僅僅只term weight計算公式的簡單典型實現。實現全文檢索系統的人會有自己的實現,Lucene就與此稍有不同。

判斷Term之間的關係從而得到文檔相關性的過程,也即向量空間模型的算法(VSM)
我們把文檔看作一系列詞(Term),每一個詞(Term)都有一個權重(Term weight),不同的詞(Term)根據自己在文檔中的權重來影響文檔相關性的打分計算。

於是我們把所有此文檔中詞(term)的權重(term weight) 看作一個向量。

Document = {term1, term2, …… ,term N}

Document Vector = {weight1, weight2, …… ,weight N}

同樣我們把查詢語句看作一個簡單的文檔,也用向量來表示。

Query = {term1, term 2, …… , term N}

Query Vector = {weight1, weight2, …… , weight N}

我們把所有搜索出的文檔向量及查詢向量放到一個N維空間中,每個詞(term)是一維。


我們認爲兩個向量之間的夾角越小,相關性越大。

所以我們計算夾角的餘弦值作爲相關性的打分,夾角越小,餘弦值越大,打分越高,相關性越大。

有人可能會問,查詢語句一般是很短的,包含的詞(Term)是很少的,因而查詢向量的維數很小,而文檔很長,包含詞(Term)很多,文檔向量維數很大。你的圖中兩者維數怎麼都是N呢?

在這裏,既然要放到相同的向量空間,自然維數是相同的,不同時,取二者的並集,如果不含某個詞(Term)時,則權重(Term Weight)爲0。


舉個例子,查詢語句有11個Term,共有三篇文檔搜索出來。其中各自的權重(Term weight),如下.

於是文檔二相關性最高,先返回,其次是文檔一,最後是文檔三。

到此爲止,我們可以找到我們最想要的文檔了。

總結


索引過程:

1) 有一系列被索引文件

2) 被索引文件經過語法分析和語言處理形成一系列詞(Term) 。

3) 經過索引創建形成詞典和反向索引表。

4) 通過索引存儲將索引寫入硬盤。

搜索過程:

a) 用戶輸入查詢語句。

b) 對查詢語句經過語法分析和語言分析得到一系列詞(Term) 。

c) 通過語法分析得到一個查詢樹。

d) 通過索引存儲將索引讀入到內存。

e) 利用查詢樹搜索索引,從而得到每個詞(Term) 的文檔鏈表,對文檔鏈表進行交,差,並得到結果文檔。

f) 將搜索到的結果文檔對查詢的相關性進行排序

g) 返回查詢結果給用戶。
————————————————
版權聲明:本文爲CSDN博主「guoyuguang0」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/guoyuguang0/article/details/76769184

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章