由于网上没有找到5.5版本的资料,很多资料都是2.x版本的,更新时语法差异较大,所以我这里翻译一下官方文档的这一部分内容。翻译时,示例代码均替换为我实践中的真实代码,这样确保了本文档的准确性。 - 本文版本:5.5 - 官方文档原文路径:Elasticsearch Reference [5.5] » Document APIs » Update API - 官方文档原文地址:点击跳转
更新API允许根据提供的脚本来更新文档。操作从索引中获取文档(与shard搭配),运行脚本(使用可选的脚本语言和参数),并返回结果(也允许删除或忽略操作)。它使用版本控制来确保在“get”和“reindex”期间没有发生更新。
注意,这个操作仍然意味着文档的全部重索引,它只是删除了一些网络往返,减少了get和索引之间的版本冲突的机会。需要为该特性启用_source字段才能工作。
我们先添加一个文档
PUT test/type1/1
{
"counter" : 1,
"tags" : ["red"]
}
现在,我们可以执行一个增加计数器的脚本:
POST test/type1/1/_update
{
"script" : {
"inline": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
}
}
我们可以在标签列表tags中添加一个标签(注意,如果标签存在,它仍然会添加它,因为它是一个列表):
POST test/type1/1/_update
{
"script" : {
"inline": "ctx._source.tags.add(params.tag)",
"lang": "painless",
"params" : {
"tag" : "blue"
}
}
}
除了_source之外,还可以通过ctx映射获得以下变量:_index、_type、_id、_version、_routing、_parent和_now(当前时间戳)。 我们还可以在文档中添加一个新字段:
POST test/type1/1/_update
{
"script" : "ctx._source.new_field = 'value_of_new_field'"
}
或者移除一个字段
POST test/type1/1/_update
{
"script" : "ctx._source.remove('new_field')"
}
我们甚至可以改变执行的操作。这个例子,如果标签字段包含绿色就删除了doc,否则它什么也不做(noop):
POST test/type1/1/_update
{
"script" : {
"inline": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }",
"lang": "painless",
"params" : {
"tag" : "green"
}
}
}
更新API还支持传递部分文档,该文档将合并到现有文档中(简单的递归合并、对象内部合并、替换核心“键/值”和数组)。例如:
POST test/type1/1/_update
{
"doc" : {
"name" : "new_name"
}
}
如果指定了doc和脚本,则忽略doc。最好是将文档的字段键值对部分都放在脚本中。
如果指定了doc,它的值将与现有的_source合并。默认情况下,不改变任何东西的更新会发现它们不会改变任何东西,并返回“结果”:“noop”:
POST test/type1/1/_update
{
"doc" : {
"name" : "new_name"
}
}
如果在发送请求之前名称为new_name,那么整个更新请求将被忽略。如果忽略请求,响应中的结果元素将返回noop。
{
"_shards": {
"total": 0,
"successful": 0,
"failed": 0
},
"_index": "test",
"_type": "type1",
"_id": "1",
"_version": 6,
"result": noop
}
您可以通过设置“detect_noop”来禁用此行为:
POST test/type1/1/_update
{
"doc" : {
"name" : "new_name"
},
"detect_noop": false
}
如果文档不存在,则将插入upsert元素的内容作为新文档。如果文档确实存在,那么脚本将被执行:
POST test/type1/1/_update
{
"script" : {
"inline": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
},
"upsert" : {
"counter" : 1
}
}
如果您希望您的脚本运行,不管文档是否存在,也就是:脚本处理初始化文档而不是upsert元素,然后将scripted_upsert设置为true:
POST sessions/session/dh3sgudg8gsrgl/_update
{
"scripted_upsert":true,
"script" : {
"id": "my_web_session_summariser",
"params" : {
"pageViewEvent" : {
"url":"foo.com/bar",
"response":404,
"time":"2014-01-01 12:32"
}
}
},
"upsert" : {}
}
将doc_as_upsert设置为true,使用doc的内容作为upsert的值;而不是发送部分doc和upsert doc:
POST test/type1/1/_update
{
"doc" : {
"name" : "new_name"
},
"doc_as_upsert" : true
}
更新操作支持以下查询字符串参数:
在更新的get和索引阶段之间,另一个进程可能已经更新了相同的文档。默认情况下,更新将会失败,并且有一个版本冲突异常。retry_on_conflict参数可以控制在最终抛出异常之前重新尝试更新的次数。
路由被用来将更新请求路由到正确的分片,如果更新的文档不存在,则为upsert请求设置路由。不能用于更新现有文档的路由。
父进程用于将更新请求路由到正确的分片,如果更新的文档不存在,则将父进程设置为upsert请求。不能用于更新现有文档的父路由。如果指定了别名索引路由,那么它将覆盖父路由,并用于路由请求。
等待shard可用的超时时间
在进行更新操作之前,需要激活的shard副本的数量。
控制什么时候可以在搜索时看到这个请求所做的更改。
允许控制是否以及如何在响应中返回更新的数据源。默认情况下,更新后的数据源不会返回。
更新API 在内部使用了弹性搜索的版本支持,以确保在更新期间文档不会发生变化。您可以使用版本参数来指定文档只有在其版本与指定的版本匹配时才会更新。
可以通过设置版本类型来强制设置更新文档后的新版本(小心使用!使用强制方式无法保证文件不会发生改变)。