Elasticsearch 6.5.1学习笔记(四)document更新

全局更新

在 Elasticsearch 中document是不可改变 的,不能修改它们。所以当我们使用更新API时,其实是经历了:

  1. 查询旧数据
  2. 标记旧数据为删除状态
  3. 插入新数据
    这里并不是将旧文档直接删除,而是打上删除标记,是为了提升ES的性能。但是如果一直不删除旧文档则会越堆越多,所以当旧文档到达一定数量时,ES会做一次清理,物理删除掉这些被标记删除的文档。
    全局更新的API其实就是PUT新增的API:
PUT /employee/_doc/1
{
  "name":"xiaozhangsan",
  "age":2,
  "signature":"I'm a baby",
  "hobby":["sugar","milk"]
}

这里将员工 zhangsan 全局更新为他的儿子 xiaozhangsan,返回结果:

{
  "_index" : "employee",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 5,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 9,
  "_primary_term" : 2
}
  • _index 修改文档所属的索引
  • _type 修改文档所属的类型,7.x版本中只允许为 _doc
  • _id 修改文档的id
  • _version 当前版本号,可用于实现乐观锁机制
  • _result 当前属于什么操作,这里是做的是全局更新所以是 updated
  • _shards 对于分片的操作结果

部分更新

前面有说过,ES中的文档是无法修改的,所以局部更新的实现步骤和全局更新类似:

  1. 查询出旧文档的 _source 部分
  2. 将更新内容写入旧的 _source
  3. 删除旧文档(标记删除)
  4. 使用修改后的 _source 来新增一个文档

API如下:

POST /employee/_doc/1/_update
{
  "doc":{
    "age":3
  }
}

这里由于 xiaozhangsan 长大了,所以只将其 age 字段加一,返回结果如下:

{
  "_index" : "employee",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 6,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 10,
  "_primary_term" : 2
}

与全局更新的返回结果基本一样。
当然局部更新不仅限于更新字段值,也可以做字段新增

脚本局部更新

简单类型更新

在ES脚本中可以使用ctx._source来访问文档的 _source,这里使用脚本再讲 xiaozhangsan 的年龄加一:

POST /employee/_doc/1/_update
{
  "script":"ctx._source.age+=1"
}

对象类型更新

也可以在脚本中调用对象的方法,比如 hobby 就是一个数组对象,可以像这样给它添加数据:

POST /employee/_doc/1/_update
{
  "script":"ctx._source.hobby.add('sleep')"
}

使用参数更新

也可以使用参数代替硬编码,像这样:

POST /employee/_doc/1/_update
{
  "script": {
    "source": "ctx._source.hobby.add(params.hobby)",
    "params": {
      "hobby": "sleep"
    }
  }
}

新增字段

注意字符串的值需要加单引号:

POST /employee/_doc/1/_update
{
  "script": "ctx._source.sex='male'"
}

删除字段

POST /employee/_doc/1/_update
{
  "script": "ctx._source.remove('sex')"
}

根据条件更新

使用 if ,如果文档hobby中包含 milk 则删除文档,否则不做任何操作:

POST /employee/_doc/2/_update
{
  "script": {
    "source":"if(ctx._source.hobby.contains('milk')){ctx.op='delete'}else{ctx.op='none'}"
  }
}

更新默认值

使用 upsert 设值字段默认值,当 age 不存在时会新增它并设置为1:

POST /employee/_doc/1/_update
{
  "script":"ctx._source.age+=1",
  "upsert": {
    "age":1 
  }
}

冲突和重试

由于ES会在更新数据时自动使用 _version 字段来做乐观锁,所以更新操作可能由于并发冲突导致失败,ES也为我们提供了 retry_on_conflict 实现重试机制,可用于计数器增加、年龄增加这样的对于并发顺序无要求的并发冲突问题:

POST /employee/_doc/1/_update?retry_on_conflict=5
{
  "script":"ctx._source.age+=1",
  "upsert": {
    "age":1 
  }
}
发布了23 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_22606825/article/details/84636001