Elasticsearch Document


1.  基本概念回顧

1.1.  Node

節點是一個服務器,它是集群的一部分,存儲數據,並參與集群的索引和搜索功能

節點有一個名稱標識,該名稱在缺省情況下是在啟動時分配給節點的隨機全局惟一標識符(UUID)

這個名稱對於管理非常重要,因為你希望識別網絡中的哪些服務器與Elasticsearch集群中的哪些節點相對應

默認情況下,每個節點都被設置為連接一個名為elasticsearch的集群,這意味着如果您在網絡上啟動多個節點,並且假設它們可以發現彼此,那么它們都會自動形成並連接一個名為elasticsearch的集群。

1.2.  Index

文檔(document)的集合就是索引(Index)

1.3.  Type

當你想要在同一個index中存儲不同類型的documents時,type用作這個index的一個邏輯分類/分區。比如,在一個索引中,用戶數據是一個type,帖子是另一個type。在后續的版本中,一個index將不再允許創建多個types,而且整個types這個概念都將被刪除。

(PS:type是index的一個邏輯分類(或者叫分區),在當前的版本中,它仍然用於在一個索引下區分不同類型的數據。但是,不建議這樣做,因為在后續的版本中type這個概念將會被移除,也不允許一個索引中有多個類型。)

1.4.  Document

一個document就是index中的一條記錄,它是JSON格式的

1.5.  Shards & Replicas (分片與副本)

索引可能存儲大量數據,這些數據可能超過單個節點的硬件限制。例如,一個包含10億個文檔、占用1TB磁盤空間的索引可能不適用於單個節點的磁盤,或者速度太慢,無法單獨處理來自單個節點的搜索請求。為了解決這個問題,Elasticsearch提供了將索引細分為多個碎片的功能,每個碎片稱之為 shard。

創建索引時,您可以簡單地定義所需的分片數量。每個分片本身就是一個功能完整且獨立的“index”,可以駐留在集群中的任何節點上。

分片之所以重要,主要有兩個原因:

  • 允許水平擴容
  • 允許分布式存儲和並行操作,從而提高性能/吞吐量

shard如何分布以及如何將其文檔聚合回搜索請求的機制完全由Elasticsearch管理,對於用戶來說是透明的。

副本指的是分片的副本,是shard的復制

復制之所以重要,主要有兩個原因:

  • 在shard/node失敗的時候,它提供高可用性。正因為如此,復制的shard(簡稱shard的副本)絕不會跟原始shard在同一個節點上
  • 它允許擴展搜索量/吞吐量,因為搜索可以並行地在所有副本上執行

(It provides high availability in case a shard/node fails. For this reason, it is important to note that a replica shard is never allocated on the same node as the original/primary shard that it was copied from.)

總而言之,每個索引可以被分成多個碎片

索引還可以被復制0次(即沒有副本)或更多次

復制之后,每個索引都將擁有主分片(原始分片)和 副本分片(主分片的副本)

1.6.  小結 & 回顧:

  1. node是一台服務器,表示集群中的節點
  2. document表示索引記錄
  3. 一個index中不建議定義多個type
  4. 一個index可以有多個shard,每個shard可以有0個或多個副本
  5. original shard (原始shard,或者叫 primary shard)的復制成為副本shard,簡稱shard
  6. 主分片和副本決不會在同一個節點上
  7. 分片的好處主要有兩個:第一,突破單台服務器的硬件限制;第二,可以並行操作,從而提高性能和吞吐量;(PS:其實跟kafka差不多)
  8. 副本的好處主要在於:第一,提供高可用;第二,並行提升性能和吞吐量
  9. 一個索引包含一個或多個分片,索引記錄(即文檔)數據存儲在這些shard中,且一個文檔只會存在於一個分片中
  10. 每個shard都是一個獨立的功能完善的“index”,意思是它可以獨立處理索引/搜索請求

(注意:本文中提到的分片指的是主分片(primary shard),而不是副本(replica shard))

2.  讀寫文檔

在Elasticsearch中,每個索引都被划分為分片,每個分片可以有多個副本。這些副本稱為復制組,在添加或刪除文檔時必須保持同步。如果我們做不到這一點,從一個副本中讀取的結果將與從另一個副本中讀取的結果非常不同。保持碎片副本同步並提供從中讀取的服務的過程稱為數據復制模型。

Elasticsearch的數據復制模型基於主備份模型,該模型中有一個主分片,以及從主分片那里復制的復制組,這些稱之為復制分片。主(服務器)節點作為所有索引操作的主要入口點,它負責驗證並確保操作是正確的。一旦主服務器接受了索引操作,主服務器還負責將該操作復制到其他副本。

2.1.  Basic write model (基本的寫模型)

在Elasticsearch中,每個索引操作首先會通過路由(通常是基於 document ID)解析到一個復制組(PS:這里解析到復制組的意思是定位到索引的哪個分片)。一旦確定了復制組,該操作將在內部轉發到該組的當前主分片。主分片負責驗證操作並將其轉發到其他副本。由於副本可以是下線狀態(PS:不在線),因此主分片不需要將該操作復制到所有副本。代替的,Elasticsearch維護應該接收操作的分片副本列表,這個列表稱為同步副本,由主節點(PS:master node)維護。顧名思義,這些是一組“良好的”分片副本,它們保證處理了用戶已確認的所有索引和刪除操作。主服務器負責維護這個不變量(PS:指的是同步副本列表),因此必須將所有操作復制到這個集合中的每個副本。

主分片的基本流程如下:

  1. 校驗輸入操作,並且如果結構無效(PS:比如字段類型錯誤等等)時拒絕該操作
  2. 在本地執行操作,即索引或刪除相關文檔。這也將驗證字段的內容,並在需要時拒絕
  3. 將操作轉發到當前同步副本集中的每個副本。如果有多個副本,則並行執行此操作
  4. 一旦所有副本成功地執行了操作並響應了主副本(PS:只的主分片),主副本就向客戶端確認請求已成功完成

2.1.1.  失敗處理

如果主分片失敗的話,那么它所在服務器節點將想主服務器節點(master node)發送一條關於該主分片的消息。索引操作將等待(默認情況下最多1分鍾,具體看 Dynamic index settings)主節點(master)將其中一個副本提升為新的主副本。然后將操作轉發到新的主分片進行處理。注意,主節點(master)還負責監視節點的健康狀況,並可能決定主動降級主副本。當持有主副本的節點因網絡問題與集群隔離時,通常會發生這種情況。

在主分片上成功執行操作之后,主分片在副本分片上執行操作時必須處理潛在的故障。這可能是由於副本上的實際故障,或者由於網絡問題導致操作無法到達副本(或阻止副本響應)。所有這些最終結果是:作為同步復制集的一部分的副本會丟失即將被確認的操作。為了避免違反不變量,主分片的宿主服務器向主服務器發送一條消息,請求從同步副本集中刪除有問題的分片。(PS:跟Kafka的副本同步有點兒像)一旦主服務器確認分片副本的移除后,主分片才會確認這個寫請求操作。

在將操作轉發到副本時,主分片將使用副本驗證它仍然是活的主分片。如果主分片由於網絡分區(或長時間GC)而被隔離,它可能會在意識到它已經降級之前繼續處理輸入的索引操作,然后將操作路由到新的主服務器。

2.2.  Basic read model (基本的讀模型)

Elasticsearch中的讀取可以是非常輕量級的ID查找,也可以是具有復雜聚合(占用大量CPU資源)的大型搜索請求。主備份模型的優點之一是它保持所有分片副本相同,因此,一個同步副本就足以滿足讀取請求。

當一個節點接收到讀請求時,該節點負責將其轉發到持有相關分片的節點、整理響應並響應客戶端。我們將該節點稱為該請求的協調節點

基本流程如下:

  1. 解析這個讀請求到相關的分片
  2. 從這個分片的復制組中選擇一個活的分片,這個活的分片可以是主分片,也可以是復制分片(副本)。默認情況下,Elasticsearch只是簡單地在副本之間進行輪詢。
  3. 發送分片級別的讀請求給選中的副本
  4. 聚合結果並對客戶端作出響應

2.2.1.  失敗處理

當分片未能響應讀取請求時,協調節點將從相同的復制組中選擇另一個副本,並將分片級搜索請求發送到該副本。重復失敗可能導致沒有分片副本可用。在某些情況下,例如_search, Elasticsearch更喜歡快速響應,盡管會得到部分結果,而不是等待問題得到解決(部分結果在響應的_shards頭中表示)。

2.2.2.  高效地讀

在正常操作下,對每個相關復制組執行一次讀操作。只有在失敗的條件下,相同分片的多個副本才能執行相同的搜索。

2.2.3.  讀未確認

由於先在主分片上寫,然后復制請求,因此並發讀取可能在確認更改之前就已經看到更改。

2.2.4.  默認兩個副本

當只維護數據的兩個副本時(number_of_replicas默認是1),該模型可以容錯。

2.3.  小結 & 回顧

1、一個索引(index)有多個分片(shard),每個分片(primary shard)有多個副本(replica shard),主分片和它的副本稱組成該分片的復制組

2、數據復制模型基於主備份模型

1、首先,計算數據在哪個分片上,這個過程稱之為路由,通常是根據文檔ID來計算的

2、將請求轉到相應的節點上,主分片校驗請求,然后在本地執行,隨后將請求轉發到同步副本集中的每個副本上,多個副本是並行執行的,當所有副本都執行完成以后,主副本向客戶端作出響應

3、每個分片都有一個同步副本集,它由master節點維護

4、如果主分片操作失敗,則該分片的節點立即向master節點發送一條關於該分片的消息,然后master節點將從它的副本中選出一個作為主分片,並且將請求轉到新的主分片上執行

5、如果主分片操作成功,副本操作失敗時,則改分片的節點會向master節點請求將改副本從同步副本集中移除,待master確認以后主分片就可以想要客戶端了

6、如果主分片操作成功,但是由於網絡分割,導致主分片與集群的連接斷開了,那么在選出新的主分片之前元主分片繼續處理請求,一旦選出新的分片后,原主分片不再試主分片,就不能再接收請求了

1、解析讀請求到相應的分片(PS:路由,即計算數據在哪個分片上)

2、從分片的復制組中選擇一個分片(PS:默認選擇的算法是在副本之間輪詢)

3、給選中的分片發請求

4、獲取分片完成請求后的響應結果,並響應客戶端

5、接收客戶端請求的那個結點負責將請求轉發到相應分片結點上,聚合各節點的響應結果,並響應客戶端,該結點成為本次請求的協調節點

6、如果分片未能正常響應,協調節點將從相同的復制組中選擇另一個副本,並將分片級搜索請求發送到該副本

7、一個讀請求只會在一個副本上執行,只有當執行失敗的時候,才會換另外一個副本上執行

8、並發讀寫可能會讀到臟數據

3.  Index API

下面這個例子,向"twitter"索引中插入一條id為1的文檔,並且是在"_doc"類型下

curl -X PUT "localhost:9200/twitter/_doc/1" -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'

響應結果可能是這樣的:

{
    "_shards" : {
        "total" : 2,
        "failed" : 0,
        "successful" : 2
    },
    "_index" : "twitter",
    "_type" : "_doc",
    "_id" : "1",
    "_version" : 1,
    "_seq_no" : 0,
    "_primary_term" : 1,
    "result" : "created"
}

_shards字段中提供了關於索引操作的復制過程的信息

  • total    表明索引操作應在多少分片(主分片和副本分片)上執行
  • successful    表示成功執行的復制數量(PS:successful至少是1)
  • failed    在索引操作在副本分片上執行失敗的情況下,包含復制相關錯誤的數組

(PS:主分片 primary shard ;副本分片 replica shard )

3.1.  自動創建索引

如果在執行index api之前沒有創建索引的話,那么該操作會自動創建索引,並自動創建一個動態類型映射(mapping)。

映射本身非常靈活,而且沒有模式。新的字段和對象將自動添加到指定類型的映射定義中。

可以通過將 action.auto_create_index 設置為false來禁用自動創建索引,將 index.mapper.dynamic 設置為false來禁用自動映射。

3.2.  版本控制

每個被索引的文檔都有一個版本號。版本號(version)在index API請求的響應中返回。版本號主要用於並發控制。

curl -X PUT "localhost:9200/twitter/_doc/1?version=2" -H 'Content-Type: application/json' -d'
{
    "message" : "elasticsearch now has versioning support, double cool!"
}
'

上面這個例子,如果ID為1的文檔的版本號是2,則更新其message自動為指定的內容,如果版本不是2,則不會執行更新操作,反而會報錯。

現在執行失敗,是因為當前ID為1的文檔版本號是1,因此執行這個請求會失敗。如果我們將該請求后面的版本號改成1,則會成功。

(PS:這其實就是CAS,比較並交換)

(PS:樂觀鎖)

默認情況下,內部版本號從1開始,並且在每次更新和刪除的時候版本號都會遞增。當然,也可以手動指定。為了可以手動指定版本號,應該將version_type指定為external。這個值必須是一個長整型的數值或者為0。

3.2.1.  版本類型

下面是一些不同的版本類型:

  • internal    只索引給定版本號與文檔存儲的版本號相同的文檔。(PS:換言之,只有當給定的版本號與文檔存儲的版本號相同時,才會索引該文檔,這里索引操作指的是更新、刪除)
  • external 或者 external_gt    只索引那些文檔存儲的版本號比給定版本號小或者不存在的文檔,同時給定的版本號會作為文檔的新版本號。(PS:換言之,只有當給定的版本號比文檔存儲的版本號大或者文檔不存在時,才會執行)
  • external_gte    只索引給定版本號大於或等於存儲文檔的版本號的那些文件,如果文檔不存在的話這個操作也會成功。(PS:換言之,只有當給定版本號大於或等於存儲文檔的版本號時,才會執行)

(PS:其實很好理解,無非就是給定的版本號與文檔當前版本號的一個比較,internal是相等的時候才執行,external是大於的時候才執行,external_get是大於或等於的時候才執行)

3.3.  操作類型

索引操作也可以接受一個 op_type 參數用於強制創建操作。例如:

curl -X PUT "localhost:9200/twitter/_doc/1?op_type=create" -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'

或者,另一種寫法也可以

curl -X PUT "localhost:9200/twitter/_doc/1/_create" -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'

上面的例子,如果文檔已經存在,則操作失敗

3.4.  自動ID生成

索引操作可以在不指定id的情況下執行。在這種情況下,將自動生成id。此外,op_type將自動設置為create。下面是一個例子(注意這里用POST代替PUT):

curl -X POST "localhost:9200/twitter/_doc/" -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'

返回結果如下:

{
    "_shards":{
        "total":2,
        "failed":0,
        "successful":2
    },
    "_index":"twitter",
    "_type":"_doc",
    "_id":"W0tpsmIBdwcYyG50zbta",
    "_version":1,
    "_seq_no":0,
    "_primary_term":1,
    "result":"created"
}

3.5.  路由

默認情況下,路由(routing)控制是通過文檔ID的哈希值來做的。對於顯式的控制,可以使用路由參數直接在每個操作的基礎上指定輸入到路由器使用的哈希函數中的值。例如:

curl -X POST "localhost:9200/twitter/_doc?routing=kimchy" -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'

上面的例子中,_doc類型下的文檔究竟被路由到哪個分片(shard)上是基於路由參數提供的值kimchy

3.6.  分布

索引操作根據它的路由定向到主分片,並在包含該分片的實際節點上執行。在主分片完成操作之后,如果需要,更新將被分發到適用的副本。

3.7.  超時

默認情況下,索引操作在主分片上最多等待1分鍾,然后失敗並以錯誤進行響應。可以使用timeout參數顯式指定它等待的時間。

下面這個例子,設置超時時間是5分鍾:

curl -X PUT "localhost:9200/twitter/_doc/1?timeout=5m" -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'

4.  Get API

下面這個例子從一個名字叫“twitter”的索引中,類型為“_doc”之下,獲取id為0的JSON文檔:

curl -X GET "localhost:9200/twitter/_doc/0"

其返回的結果可能是這樣的:

{
    "_index" : "twitter",
    "_type" : "_doc",
    "_id" : "0",
    "_version" : 1,
    "found": true,
    "_source" : {
        "user" : "kimchy",
        "date" : "2009-11-15T14:12:12",
        "likes": 0,
        "message" : "trying out Elasticsearch"
    }
}

你還可以用HEAD操作單純的只是檢查某個文檔是否存在,例如:

curl -X HEAD "localhost:9200/twitter/_doc/0"

默認情況下,Get 操作是實時的。也就是說,如果文檔已經被更新,但是索引還沒刷新,那么get操作會調用刷新

4.1.  Source字段過濾

默認情況下,get操作的返回中包含 _source 字段,你可以手動關閉它。例如:

curl -X GET "localhost:9200/twitter/_doc/0?_source=false"

如果只想顯示_source中的某些字段,可以這樣簡短的表示:

curl -X GET "localhost:9200/twitter/_doc/0?_source=*.id,retweeted"

4.2.  路由

curl -X GET "localhost:9200/twitter/_doc/2?routing=user1"

注意,如果你帶了routing參數,而且還路由值還帶錯了,那么將找不到文檔

5.  ?refresh

IndexUpdateDelete等操作支持設置 refresh 參數來控制什么時候改變對搜索可見。(PS:意思了,對文檔做了更新以后,什么時候這個更新可以被檢索的時候看到)

refresh參數的值可以是下列之一:

  • 空字符串 或者 true    :  操作發生后立即刷新相關的主分片和副本分片(不是整個索引),以便更新后的文檔立即出現在搜索結果中。
  • wait_for    :  在回復之前,等待請求所做的更改被刷新。這並不強制立即刷新,而是等待刷新發生。Elasticsearch自動刷新已更改每個索引的分片。refresh_interval,默認為1秒。
  • false(默認)    :  不要執行刷新相關操作。此請求所做的更改將在請求返回后的某個時點可見。

下面是一些例子:

curl -X PUT "localhost:9200/test/_doc/1?refresh" -H 'Content-Type: application/json' -d'
{"test": "test"}
'
curl -X PUT "localhost:9200/test/_doc/2?refresh=true" -H 'Content-Type: application/json' -d'
{"test": "test"}
'

創建一個文檔,並立即刷新

curl -X PUT "localhost:9200/test/_doc/3" -H 'Content-Type: application/json' -d'
{"test": "test"}
'
curl -X PUT "localhost:9200/test/_doc/4?refresh=false" -H 'Content-Type: application/json' -d'
{"test": "test"}
'

只是創建一個文檔,其它的什么也不做

curl -X PUT "localhost:9200/test/_doc/4?refresh=wait_for" -H 'Content-Type: application/json' -d'
{"test": "test"}
'

創建一個文檔,並等待刷新

6.  參考

https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-replication.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM