1. 程式人生 > >Elasticsearch數據處理(三)

Elasticsearch數據處理(三)

新博 reason localhost err edi 負責 阻止 使用 正文

1.處理沖突

當使用 index API更新文檔的時候,我們讀取原始文檔,做修改,然後將整個文檔(whole document)一次性重新索引。

最近的索引請求會生效——Elasticsearch中只存儲最後被索引的任何文檔。如果其他人同時也修改了這個文檔,他們的修改將會丟失。

很多時候,這不是問題。也許我們的主數據存儲是關系數據庫,我們只是將數據復制到Elasticsearch中以使其可搜索。

也許兩個人幾乎不可能同時更改同一個文檔。或者,如果偶爾失去變化,對我們的業務來說也許並不重要。

但有時失去變化非常重要想象一下,我們正在使用Elasticsearch來存儲我們在線商店中庫存的小部件數量。

每次我們出售小部件時,我們都會減少Elasticsearch中的庫存數量。

有一天,管理層決定進行銷售。突然間,我們每秒都在銷售幾個小部件。想象一下,兩個並行運行的Web進程,每個進程都處理一個小部件的銷售,如下圖顯示沒有並發控制的結果

  技術分享圖片

在數據庫領域,通常使用兩種方法來確保在並發更新時不會丟失更改

悲觀的並發控制
這種方法廣泛用於關系數據庫,它假定可能發生沖突的更改,因此阻止對資源的並發訪問以防止沖突。
一個典型的例子是在讀取數據之前鎖定一行,確保只有放置鎖的線程才能對該行中的數據進行更改。
樂觀的並發控制
由Elasticsearch使用, 這種方法假定沖突不太可能發生,並且不會阻止嘗試操作。
但是,如果在讀取和寫入之間修改了基礎數據,則更新將失敗。然後由應用程序決定如何解決沖突。例如,它可以使用新數據重新嘗試更新,或者可以向用戶報告情況。

2.樂觀並發控制

  Elasticsearch是分布式的。

如果要創建,更新或刪除新版本的文檔,則必須將其復制到群集中的其他節點。

Elasticsearch也是異步和並發的,這意味著這些復制請求是並行發送的,並且可能不按順序到達目的地。

Elasticsearch需要一種方法來確保舊版本的文檔永遠不會覆蓋較新的版本。

當我們之前討論過indexgetdelete請求時,我們指出每個文檔都有一個_version數字,只要文檔被更改,該數字就會遞增。

Elasticsearch使用此_version數字來確保以正確的順序應用更改。

如果在新版本之後舊版本文檔到達,則可以簡單地忽略它。

我們可以利用這個_version數字來確保 我們的應用程序所做的沖突的更改不會導致數據丟失。

我們希望通過指定更改的文檔的version編號來完成此操作。如果該版本不再是最新版本,我們的請求將失敗。

讓我們創建一個新的博客文章:

curl -X PUT "localhost:9200/website/blog/1/_create" -H ‘Content-Type: application/json‘ -d{
  "title": "My first blog entry",
  "text":  "Just trying this out..."
}
‘

響應正文告訴我們這個新創建的文檔_version1。現在假設我們要編輯文檔:我們將其數據加載到Web表單中,進行更改,然後保存新版本。

首先我們檢索文檔:

curl -X GET "localhost:9200/website/blog/1"

響應正文包含相同的版本_version 1

{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "1",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry",
      "text":  "Just trying this out..."
  }
}

現在,當我們嘗試通過重新索引文檔來保存更改時,我們指定此次修改對應的版本號version

curl -X PUT "localhost:9200/website/blog/1?version=1" -H ‘Content-Type: application/json‘ -d{
  "title": "My first blog entry",
  "text":  "Starting to get the hang of this..."
}
‘
只有當Elasticsearch中此文檔的版本為1時,我們的更新才會生效。

此請求成功(當前此文檔的版本為1),響應正文告訴我們_version 已增加到2(因為數據更新了)

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "1",
  "_version": 2
  "created":  false
}

但是,如果我們要重新運行相同的索引請求,仍然指定 version=1,Elasticsearch將使用409 ConflictHTTP響應代碼進行響應,響應內容大致如下:

{
   "error": {
      "root_cause": [
         {
            "type": "version_conflict_engine_exception",
            "reason": "[blog][1]: version conflict, current [2], provided [1]",
            "index": "website",
            "shard": "3"
         }
      ],
      "type": "version_conflict_engine_exception",
      "reason": "[blog][1]: version conflict, current [2], provided [1]",
      "index": "website",
      "shard": "3"
   },
   "status": 409
}

這告訴我們Elasticsearch中當前的文檔的_version編號是2,但我們指定更新版本為1

我們現在所做的工作取決於我們的應用要求。我們可以告訴用戶其他人已經對文檔進行了更改,並在嘗試再次保存之前查看更改。或者,與stock_count先前窗口小部件的情況一樣,我們可以檢索最新文檔並嘗試重新應用更改。

更新或刪除文檔的所有修改API都接受一個version參數,該參數允許您將樂觀並發控制應用於代碼中有需要的部分。

3.使用外部系統中的版本

常見的設置是使用其他數據庫作為主數據存儲,使用Elasticsearch使數據可搜索, 這意味著對主數據庫的所有更改都需要在發生時復制到Elasticsearch。

如果多個進程負責此數據同步,則可能會遇到類似於前面描述的並發問題。

如果您的主數據庫已經具有版本號 - 或者諸如 timestamp可以用作版本號的值 - 那麽您可以通過添加version_type=external到查詢字符串來在Elasticsearch中重用這些相同的版本號。

版本號必須是大於零且小於9.2e+18的整數 - 在Java中為正值long

處理外部版本號的方式與我們之前討論的內部版本號略有不同。

Elasticsearch檢查當前是否小於指定版本,而不是檢查當前_version是否請求中指定的當前相同。如果請求成功,則外部版本號將存儲為文檔的新版本。_version

外部版本號不僅可以在索引和刪除請求中指定,還可以在創建新文檔時指定。

例如,要創建一個外部版本號為5的新博客帖子,我們可以執行以下操作:

curl -X PUT "localhost:9200/website/blog/2?version=5&version_type=external" -H ‘Content-Type: application/json‘ -d{
  "title": "My first external blog entry",
  "text":  "Starting to get the hang of this..."
}
‘

在回復中,我們可以看到當前的_version數字是5

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "2",
  "_version": 5,
  "created":  true
}

現在我們更新這個文檔,指定一個新的version數字10

curl -X PUT "localhost:9200/website/blog/2?version=10&version_type=external" -H ‘Content-Type: application/json‘ -d{
  "title": "My first external blog entry",
  "text":  "This is a piece of cake..."
}
‘

請求成功並將當前設置_version10

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "2",
  "_version": 10,
  "created":  false
}

如果您要重新運行此請求,它將產生版本沖突錯誤,因為指定的外部版本號不高於Elasticsearch中的當前版本。  

Elasticsearch數據處理(三)