Elasticsearch 創建、更新、刪除文檔、處理沖突


 ----創建新文檔----

1._index,_type和_id的組合可以唯一標識一個文檔,所以確保一個新文檔的最簡單的辦法就是,使用索引請求的POST形式讓elsticsearch自動生成唯一_id:

POST /website/blog
{  ...  }

2.如果需要指定文檔的_id,那就需要告訴elasticsearch在_index,_type和_id的組合不存在的時候進行新建操作,有兩種方法實現

  • 使用op_type
PUT /website/blog/123?op_type=create
{ ... }
  • 在URL末端使用/_create
PUT /website/blog/123/_create
{ ... }

  注意: 請求執行成功會返回元數據(執行結果)和一個201 Created 的HTTP響應碼。

     如果相同_index,_type和_id的組合的文檔已經存在,elasticsearch將會返回409 Conflict 響應碼以及如下錯誤信息。

{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[blog][124]: version conflict, document already exists (current version [1])",
        "index_uuid": "oCXgGtl9SfmXXD-edmYdfA",
        "shard": "3",
        "index": "website"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[blog][124]: version conflict, document already exists (current version [1])",
    "index_uuid": "oCXgGtl9SfmXXD-edmYdfA",
    "shard": "3",
    "index": "website"
  },
  "status": 409
}

----刪除文檔----

刪除文檔,使用DELETE 方法:

DELETE /website/blog/123

一如果找到該文檔,elasticsearch將返回一個200 ok 的HTTP響應碼,和一個類似以下結構的響應體,字段_version 值會增加。

{
  "found": true,
  "_index": "website",
  "_type": "blog",
  "_id": "123",
  "_version": 6,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  }
}

標如果文檔沒有找到,我們將會得到一個404 not Found 的響應碼和一個類似以下結構的響應體,即便文檔不存在,_version值也會增加,這是 Elasticsearch 內部記錄本的一部分,用來確保這些改變在跨多節點時以正確的順序執行。

{
  "found": false,
  "_index": "website",
  "_type": "blog",
  "_id": "123",
  "_version": 3,
  "result": "not_found",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  }
}

注意:
  正如已經在更新整個文檔中提到的,刪除文檔不會立即將文檔從磁盤中刪除,只是將文檔標記為已刪除狀態。隨着你不斷的索引更多的數據,Elasticsearch 將會在后台清理標記為已刪除的文檔。

----處理沖突----

多個用戶對一份數據進行修改操作時,變更越頻繁,讀數據和更新數據的間隙越長,也就越可能丟失變更。

在數據庫領域中,有兩種方法通常被用來確保並發更新時變更不會丟失:

1.悲觀並發控制(悲觀鎖)

  這種方法被關系型數據庫廣泛使用,它假定有變更沖突可能發生,因此阻塞訪問資源以防止沖突。 一個典型的例子是讀取一行數據之前先將其鎖住,確保只有放置鎖的線程能夠對這行數據進行修改。

2.樂觀並發控制(樂觀鎖)

  Elasticsearch 中使用的這種方法假定沖突是不可能發生的,並且不會阻塞正在嘗試的操作。 然而,如果源數據在讀寫當中被修改,更新將會失敗。應用程序接下來將決定該如何解決沖突。 例如,可以重試更新、使用新的數據、或者將相關情況報告給用戶。

  Elasticsearch 是分布式的,當文檔創建,更新或者刪除時,新版本的文檔必須復制到集群中的其他節點。

  Elasticsearch 也是異步和並發的,這意味着這些復制請求被並行發送,並且到達目的地時順序也許是亂的。Elasticsearch 需要一種方法確保文檔的舊版本不會覆蓋新的版本。

  可以通過_version的遞增來確保變更正確的執行順序,簡單的忽略掉舊版本的文檔在新版本之后到達的操作。

# 創建一個測試的文檔
PUT /website/blog/1/_create
{
  "title": "My first blog entry",
  "text":  "Just trying this out..."
}
# 得到該文檔的version版本號
GET /website/blog/1
# 嘗試通過重建文檔的索引來保存修改,我們指定 version 為我們的修改會被應用的版本,這個操作只有在version=1的時,更新才能成功
PUT /website/blog/1?version=1 
{
  "title": "My first blog entry",
  "text":  "Starting to get the hang of this..."
}
# 更新成功后,_vetsion遞增
# 重新運行相同的索引請求,仍然指定 version=1 , Elasticsearch 返回 409 Conflict HTTP 響應碼
{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[blog][1]: version conflict, current version [2] is different than the one provided [1]",
        "index_uuid": "oCXgGtl9SfmXXD-edmYdfA",
        "shard": "3",
        "index": "website"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[blog][1]: version conflict, current version [2] is different than the one provided [1]",
    "index_uuid": "oCXgGtl9SfmXXD-edmYdfA",
    "shard": "3",
    "index": "website"
  },
  "status": 409
}

  注:所有文檔的更新或刪除 API,都可以接受 version 參數,這允許你在代碼中使用樂觀的並發控制

3.通過外部系統使用版本控制

  一個常見的設置是使用其它數據庫作為主要的數據存儲,使用 Elasticsearch 做數據檢索, 這意味着主數據庫的所有更改發生時都需要被復制到 Elasticsearch ,如果多個進程負責這一數據同步,你可能遇到類似於之前描述的並發問題。

  如果你的主數據庫已經有了版本號 — 或一個能作為版本號的字段值比如 timestamp — 那么你就可以在 Elasticsearch 中通過增加 version_type=external 到查詢字符串的方式重用這些相同的版本號, 版本號必須是大於零的整數, 且小於 9.2E+18 — 一個 Java 中 long 類型的正值。

  外部版本號的處理方式和我們之前討論的內部版本號的處理方式有些不同, Elasticsearch 不是檢查當前 _version 和請求中指定的版本號是否相同, 而是檢查當前 _version 是否 小於 指定的版本號。 如果請求成功,外部的版本號作為文檔的新 _version 進行存儲。

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

要創建一個新的具有外部版本號 5 的博客文章,我們可以按以下方法進行:

PUT /website/blog/2?version=5&version_type=external
{
  "title": "My first external blog entry",
  "text":  "Starting to get the hang of this..."
}

在響應中,我們能看到當前的 _version 版本號是 5 :

{
  "_index": "website",
  "_type": "blog",
  "_id": "2",
  "_version": 5,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  },
  "created": true
}

現在我們更新這個文檔,指定一個新的 version 號是 10 :

PUT /website/blog/2?version=10&version_type=external
{
  "title": "My first external blog entry",
  "text":  "Starting"
}

請求成功並將當前 _version 設為 10 :

{
  "_index": "website",
  "_type": "blog",
  "_id": "2",
  "_version": 10,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  },
  "created": false
}

  注:如果你要重新運行此請求時,它將會失敗,並返回像我們之前看到的同樣的沖突錯誤, 因為指定的外部版本號不大於 Elasticsearch 的當前版本號。


免責聲明!

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



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