Update API
Update API允许基于提供的脚本更新文档。该操作从索引获取文档(与分片并置),运行脚本(使用可选的脚本语言和参数),并对结果进行索引(也允许删除或忽略操作)。它使用版本控制来确保在“get”和“reindex”期间没有发生更新。
注意,此操作仍然意味着文档的完全重新索引,它指示删除了一些网络往返,并减少了get和索引之间版本冲突的可能性。_source需要启用该字段才能使此功能正常工作。
e.g.索引一个简单的文档:
PUT test/_doc/1
{
"counter" : 1,
"tags" : ["red"]
}
脚本更新
现在,执行一个增加计数器的脚本:
POST test/_doc/1/_update
{
"script" : {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
}
}
可以在标签列表中添加一个标签(如果标签存在,它仍会添加它,因为它是一个列表):
POST test/_doc/1/_update
{
"script" : {
"source": "ctx._source.tags.add(params.tag)",
"lang": "painless",
"params" : {
"tag" : "blue"
}
}
}
此外_source以下变量通过提供ctx地图:_index , _type , _id , _version , _routing 和 _now(当前时间戳)。
我们还可以在文档中添加一个新字段:
POST test/_doc/1/_update
{
"script" : "ctx._source.new_field = 'value_of_new_field'"
}
或者从文档中删除字段:
POST test/_doc/1/_update
{
"script" : "ctx._source.remove('new_field')"
}
而且,我们甚至可以改变执行的操作。如果tags字段包含green,此示例将删除doc,否则它不执行任何操作(noop):
POST test/_doc/1/_update
{
"script" : {
"source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }",
"lang": "painless",
"params" : {
"tag" : "green"
}
}
}
响应结果如下:
{
"_index": "test",
"_type": "_doc",
"_id": "1",
"_version": 12,
"result": "noop",
"_shards": {
"total": 0,
"successful": 0,
"failed": 0
}
}
执行删除操作时,返回结果result为deleted。
部分文档更新
Update API还支持传递部分文档,该部分文档将合并到现有文档中(简单的递归合并,对象的内部合并,替换核心“键/值”和数组)。要完全替换现有文档,应使用index API。以下部分更新会向现有文档添加新字段:
POST test/_doc/1/_update
{
"doc" : {
"name" : "new_name"
}
}
如果同时doc和script指定,然后doc被忽略。最好是将部分文档的字段对放在脚本本身中。
但在实际操作中,如果同时指定doc和script,则会报错:
"type": "action_request_validation_exception",
"reason": " can't provide both script and doc;"
官方文档(2018-07-11)有误。
检查noop更新
如果doc指定,则其值与现有值合并_source。默认情况下,不更改任何内容的更新会检测到它们没有更改任何内容并返回“result”:“noop”,
如下所示:
POST test/_doc/1/_update
{
"doc" : {
"name" : "new_name"
}
}
如果name是new_name请求被发送之前那么整个更新请求被忽略。如果忽略请求,则result返回响应中的元素noop。
{
"_shards": {
"total": 0,
"successful": 0,
"failed": 0
},
"_index": "test",
"_type": "_doc",
"_id": "1",
"_version": 6,
"result": "noop"
}
您可以通过设置“detect_noop”来禁用此行为:false,如下所示:
POST test/_doc/1/_update
{
"doc" : {
"name" : "new_name"
},
"detect_noop": false
}
区别:
禁用此行为后,不更改任何内容的更新也会返回updated并且文档版本号加1;
不禁用此行为,不更改任何内容的更新会返回noop并且文档版本号不变。
Upserts
如果文档尚不存在,则upsert元素的内容将作为新文档插入。如果文档存在,那么script将执行:
POST test/_doc/1/_update
{
"script" : {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
},
"upsert" : {
"counter" : 1
}
}
scripted_upsert
如果无论文档是否存在您都希望脚本运行,即脚本处理初始化文档而不是upsert元素,设置scripted_upsert为true:
POST test/_doc/3/_update
{
"scripted_upsert":true,
"script":{
"source":"ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count":4
}
},
"upsert":{
"counter":1
}
}
注意:设置“scripted_upsert”为true后,如果文档3不存在,则会先创建文档3,将upsert元素的内容插入文档3,然后运行脚本script内容,即上述代码响应结果为(文档3起先并不存在):
{
"_index": "test",
"_type": "_doc",
"_id": "3",
"_version": 4,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}
查询文档3:GET test/_doc/3
响应结果为:
{
"_index": "test",
"_type": "_doc",
"_id": "3",
"_version": 1,
"found": true,
"_source": {
"counter": 5
}
}
doc_as_upsert
同scripted_upsert,如果无论文档是否存在您都希望脚本运行,即脚本处理初始化文档而不是upsert元素,设置doc_as_upsert为true(文档4不存在):
POST test/_doc/4/_update
{
"doc":{
"name":"doc_name"
},
"doc_as_upsert":true,
"upsert":{
"name":"upsert_name"
}
}
上述代码响应结果为:
{
"_index": "test",
"_type": "_doc",
"_id": "4",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 42,
"_primary_term": 1
}
查看文档4:GET test/_doc/4
响应结果:
{
"_index": "test",
"_type": "_doc",
"_id": "4",
"_version": 1,
"found": true,
"_source": {
"name": "doc_name"
}
}
如果没有doc_as_upsert为true这个设置,则文档4的内容为“upsert_name”。
参数编辑
更新操作支持以下查询字符串参数:
retry_on_conflict
在更新的get和indexing阶段之间,另一个进程可能已经更新了同一文档。默认情况下,更新将因版本冲突异常而失败。该retry_on_conflict 参数控制在最终抛出异常之前重试更新的次数。
routing
路由用于将更新请求路由到正确的分片,并在更新的文档不存在时为upsert请求设置路由。不能用于更新现有文档的路由。
timeout
超时等待碎片变为可用。
wait_for_active_shards
在继续更新操作之前需要处于活动状态的分片副本数。详情请见此处。
refresh
控制何时此请求所做的更改对搜索可见。见 ?refresh。
_source
允许控制是否以及如何在响应中返回更新的源。默认情况下,不会返回更新的源。详情source filtering请见。
version
更新API在内部使用Elasticsearch的版本控制支持,以确保在更新期间文档不会更改。您可以使用该version 参数指定仅在文档版本与指定版本匹配时才更新文档。
注意:更新API不支持内部版本以外的版本控制
更新API不支持外部(版本类型external&external_gte)或强制(版本类型force)版本控制,因为它会导致Elasticsearch版本号与外部系统不同步。请改用 indexAPI。