【Elasticsearch7.0】文档接口之update接口

star2017 1年前 ⋅ 649 阅读

基本语法

update接口支持使用脚本,脚本从索引中获取到文档,接着运行脚本,然后返回运行结果,同时使用版本号来控制,防止修改之前数据已经被修改了,update操作也是先删除文档,在重新创建文档。
来看下例子:

curl -XPUT "http://127.0.0.1:9200/test/_doc/1?pretty" -H "Content-Type:application/json" -d'
{
    "counter" : 1,
    "tags" : ["red"]
}'

返回值:

{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 11,
  "_primary_term" : 7
}

使用脚本执行,让某个属性自增,

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "script" : {
        "source": "ctx._source.counter += params.count",
        "lang": "painless",
        "params" : {
            "count" : 4
        }
    }
}'

返回值:

{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 12,
  "_primary_term" : 7
}

查询结果为:

{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "_seq_no" : 12,
  "_primary_term" : 7,
  "found" : true,
  "_source" : {
    "counter" : 5,
    "tags" : [
      "red"
    ]
  }
}

我们可以使用脚本来添加标签,即使标签已经存在

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "script" : {
        "source": "ctx._source.tags.add(params.tag)",
        "lang": "painless",
        "params" : {
            "tag" : "blue"
        }
    }
}'

查询结果为:

curl -XGET "http://127.0.0.1:9200/test/_doc/1?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 4,
  "_seq_no" : 13,
  "_primary_term" : 7,
  "found" : true,
  "_source" : {
    "counter" : 5,
    "tags" : [
      "red",
      "blue",
      "blue"
    ]
  }
}

我们也可以移除标签,可以使用remove方法,如果列表中存在多个标签,那么只会移除一个。

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "script" : {
        "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
        "lang": "painless",
        "params" : {
            "tag" : "blue"
        }
    }
}'

查询结果为:

curl -XGET "http://127.0.0.1:9200/test/_doc/1?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 6,
  "_seq_no" : 15,
  "_primary_term" : 7,
  "found" : true,
  "_source" : {
    "counter" : 5,
    "tags" : [
      "red",
      "blue"
    ]
  }
}

处理_source之外,ctx还可以使用以下变量:_index_type_id_version_routing, 和_now(当前时间戳)
通过脚本添加新的属性

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "script" : "ctx._source.value_of_new_field = 111"
}'

查询结果为:

curl -XGET "http://127.0.0.1:9200/test/_doc/1?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 7,
  "_seq_no" : 16,
  "_primary_term" : 7,
  "found" : true,
  "_source" : {
    "counter" : 5,
    "tags" : [
      "red",
      "blue"
    ],
    "value_of_new_field" : 111
  }
}

也可以删除某个属性

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "script" : "ctx._source.remove(\"value_of_new_field\")"
}'

查询结果为:

curl -XGET "http://127.0.0.1:9200/test/_doc/1?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 9,
  "_seq_no" : 18,
  "_primary_term" : 7,
  "found" : true,
  "_source" : {
    "counter" : 5,
    "tags" : [
      "red",
      "blue"
    ]
  }
}

还可以根据条件来判断是否执行脚本

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "script" : {
        "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = \"delete\" } else { ctx.op = \"none\" }",
        "lang": "painless",
        "params" : {
            "tag" : "green"
        }
    }
}'

局部文档更新

update接口支持传递部分文档,并把这部分文档合并到原来的文档中,如果需要完全替换文档需要使用index接口,示例给文档新增字段:

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "doc" : {
        "name" : "new_name"
    }
}'

查询结果为:

curl -XGET "http://127.0.0.1:9200/test/_doc/1?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 10,
  "_seq_no" : 19,
  "_primary_term" : 8,
  "found" : true,
  "_source" : {
    "counter" : 5,
    "tags" : [
      "red",
      "blue"
    ],
    "name" : "new_name"
  }
}

如果同时使用了doc和script属性,那么doc将被忽略,可以把部分属性对放到脚本里面。

检查空更新

如果使用doc的时候,值已经存在,那么将不发生任何改变,返回结果为"result": "noop",再次执行以下语句:

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "doc" : {
        "name" : "new_name"
    }
}'

返回值为:

{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 10,
  "result" : "noop",
  "_shards" : {
    "total" : 0,
    "successful" : 0,
    "failed" : 0
  }
}

因为name的值跟之前的一样,那么update接口将被忽略,可以通过"detect_noop": false来禁止空更新,result会返回updated,示例如:

curl -XPOST "http://127.0.0.1:9200/test/_update/1?pretty" -H "Content-Type:application/json" -d'
{
    "doc" : {
        "name" : "new_name"
    },
	"detect_noop":false
}'

返回值为:

{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 11,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 20,
  "_primary_term" : 8
}

更新插入

如果文档不存在,那么upsert元素里面的值会生成一个新的文档,如果文档已经存在了,那么会执行script里面的内容,示例如:

curl -XPOST "http://127.0.0.1:9200/test/_update/222?pretty" -H "Content-Type:application/json" -d'
{
    "script" : {
        "source": "ctx._source.abc += params.count",
        "lang": "painless",
        "params" : {
            "count" : 4
        }
    },
    "upsert" : {
        "abc" : 1
    }
}'

查询结果为:

curl -XGET "http://127.0.0.1:9200/test/_doc/222?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "222",
  "_version" : 1,
  "_seq_no" : 21,
  "_primary_term" : 8,
  "found" : true,
  "_source" : {
    "abc" : 1
  }
}

文档已经存在了,再次执行上面的upsert示例,

curl -XGET "http://127.0.0.1:9200/test/_doc/222?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "222",
  "_version" : 2,
  "_seq_no" : 22,
  "_primary_term" : 8,
  "found" : true,
  "_source" : {
    "abc" : 5
  }
}

属性abc的值为5了,说明执行了script里面的语句。

脚本更新插入

如果不管文档是否存在,你都希望使用脚本来执行,那么可以设置scripted_upsert为true,示例如:

curl -XPOST "http://127.0.0.1:9200/test/_update/1111?pretty" -H "Content-Type:application/json" -d'
{
    "scripted_upsert":true,
    "script" : {
        "source": "ctx._source.counter = \"1111\""
    },
    "upsert" : {}
}'

查询结果为:

curl -XGET "http://127.0.0.1:9200/test/_doc/1111?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1111",
  "_version" : 1,
  "_seq_no" : 25,
  "_primary_term" : 8,
  "found" : true,
  "_source" : {
    "counter" : "1111"
  }
}

doc更新插入

设置doc_as_upsert为true,表示使用doc里面的内容来做更新插入,示例如:

curl -XPOST "http://127.0.0.1:9200/test/_update/1112?pretty" -H "Content-Type:application/json" -d'
{
    "doc" : {
        "name" : "new_name"
    },
    "doc_as_upsert" : true
}'

查询结果为:

curl -XGET "http://127.0.0.1:9200/test/_doc/1112?pretty"
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1112",
  "_version" : 1,
  "_seq_no" : 26,
  "_primary_term" : 8,
  "found" : true,
  "_source" : {
    "name" : "new_name"
  }
}

参数解析

update接口还支持以下参数:
retry_on_conflict:版本冲突的时候重试次数。
routing:更新时路由到哪个分片。
timeout:分片可用的等待超时时间。
wait_for_active_shards:表示多少活跃分片数,如果不符合活跃数量将等待。
refresh:控制什么时候可以被搜索到。
_source:表示需要返回属性值,默认不返回。
version:版本控制,保证在修改的时候文档是最新的。
if_seq_no、if_primary_term:判断更新的时候两个参数的值是否更原数据一致,如果不匹配,那么会返回VersionConflictException,并状态为409。

本文为博主原创文章,未经博主允许不得转载。
更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: