一 更新整個文檔
更新整個文檔的方法和存放數據的方式是相同的,通過PUT 127.0.0.1/test/test/1 我們可以把test/test/1下的文檔更新為新的文檔
例:
PUT 127.0.0.1:9200/test/test/1
參數
{ "newdata":"yes" }
響應
{ "_index": "test", "_type": "test", "_id": "1", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 1 }
可以看到響應的參數里_version已經變為了2,並且result為updated 說明此操作為更新操作
二 文檔局部更新
如果不想講原有文檔完全更新,只想更新部分文檔,可以使用ES的_update api 參數是一個局部文檔參數doc,它會合並到現有文檔中,存在的字段被覆蓋,有點類似map的putAll操作
示例
POST 127.0.0.1;9200/test/test/1/_update
參數
{ "doc":{ "newdata":"no", "author":"wuzhe" } }
響應
{ "_index": "test", "_type": "test", "_id": "1", "_version": 3, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 2, "_primary_term": 1 }
三 刪除文檔
想要刪除文檔,可以使用DELETE 請求方式
示例:
DELETE 127.0.0.1:9200/test/test/1
響應
{ "_index": "test", "_type": "test", "_id": "1", "_version": 4, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1 }
如果刪除成功,那么狀態碼為200 ,且result 為deleted, 我們可以看到響應中的_version由3變為了4,也就是版本號發生了變化,這是因為對於ES來說,刪除文檔並不是把它從硬盤中物理刪除,而是將其標記為已刪除,實現邏輯上的刪除
那如果沒有刪除成功,響應會是什么樣的呢?
我們嘗試刪除一個不存在的文檔
DELETE 1270.0.01:9200/test/test/100
響應
{ "_index": "test", "_type": "test", "_id": "100", "_version": 1, "result": "not_found", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 }
這時候 響應狀態碼變為了404,並且result變為了not_found
四 創建文檔
之前說到的完整文檔更新和新建文檔的操作是完全一樣的,那我如何確定這次操作一定是創建操作呢,畢竟絕大多數情況,我們並不想一不小心覆蓋了已有文檔的數據
一種方案是,采用ES自動生成的ID,這樣可以保證每次插入操作都是創建操作
那如果我一定要使用自定義的ID呢?
可以通過使用op_type這個參數
示例
PUT 127.0.0.1:9200/test/test/6?op_type=create
請求參數為文檔內容
{ "test":"test", "author":"wuzhe" }
響應
{ "_index": "test", "_type": "test", "_id": "6", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 2, "_primary_term": 1 }
可以看到這里文檔新建成功了,result為created並且version為1
如果我們再次執行相同的操作,即對已有數據進行創建
響應
{ "error": { "root_cause": [ { "type": "version_conflict_engine_exception", "reason": "[test][6]: version conflict, document already exists (current version [1])", "index_uuid": "7i4nU37hQJWCRUm1Hop0Gw", "shard": "2", "index": "test" } ], "type": "version_conflict_engine_exception", "reason": "[test][6]: version conflict, document already exists (current version [1])", "index_uuid": "7i4nU37hQJWCRUm1Hop0Gw", "shard": "2", "index": "test" }, "status": 409 }
可以看到這時候的響應碼為409,說明版本號沖突了,無法創建成功。
五 版本控制
在並發場景下,ES使用樂觀並發控制的方式,ES保證所有的文檔的_version都能被正常排序,當一個舊版本的文檔出現在新版本之后,那么它會被ES簡單的忽略
1、使用指定版本號修改文檔
在修改文檔的時候使用version參數
示例:
PUT 127.0.0.1:9200/test/test/6?version=1 (只有在文檔版本為1的情況下更新成功)
參數:
{ "test":"test1", "author":"wuzhe" }
響應
{ "_index": "test", "_type": "test", "_id": "6", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1 }
可以看到這時候更新成功了,因為/test/test/6 的版本之前為1,現在更新為了2,。
我們再嘗試一次請求,這時候的響應變成了
{ "error": { "root_cause": [ { "type": "version_conflict_engine_exception", "reason": "[test][6]: version conflict, current version [2] is different than the one provided [1]", "index_uuid": "7i4nU37hQJWCRUm1Hop0Gw", "shard": "2", "index": "test" } ], "type": "version_conflict_engine_exception", "reason": "[test][6]: version conflict, current version [2] is different than the one provided [1]", "index_uuid": "7i4nU37hQJWCRUm1Hop0Gw", "shard": "2", "index": "test" }, "status": 409 }
說明更新時遇到了版本號沖突,這時候響應狀態碼為409
2、使用外部版本控制系統
一種常見的結構是使用一些其他的數據庫做為主數據庫,然后使用Elasticsearch搜索數據,這意味着所有主數據庫發生變化,就要將其拷貝到Elasticsearch中。如果有多個進程負責這些數據的同步,就會遇到上面提到的並發問題。
如果主數據庫有版本字段,或一些類似於timestamp
等可以用於版本控制的字段 你就可以在Elasticsearch的查詢字符串后面添加version_type=external
來使用這些版本號。版本號必須是整數,且值大於零小於java正的Long型最大值
外部版本號與之前說的內部版本號在處理的時候有些不同。它不再檢查_version
是否與請求中指定的一致,而是檢查是否小於指定的版本。如果請求成功,外部版本號就會被存儲到_version
中。
示例:
PUT 127.0.0.1:9200/test/test/6?version=10&version_type=external
請求
{ "test":"test10", "author":"wuzhe" }
響應
{ "_index": "test", "_type": "test", "_id": "6", "_version": 10, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 4, "_primary_term": 1 }
可以看到之前test/test/6的版本號為2, 現在已經被更新為了10