elasticsearch(3) 数据操作-更新

一 更新整个文档

更新整个文档的方法和存放数据的方式是相同的,通过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 

猜你喜欢

转载自www.cnblogs.com/wuzhe1991/p/9933114.html