基本语法
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。
注意:本文归作者所有,未经作者允许,不得转载