文本方式批量更新多字段
使用更新
请求最简单的一种用途就是添加新数据。新的数据会被合并到现有数据中,而如果存在相同的字段,就会被新的数据所替换。例如我们可以为我们的博客添加tags
和views
字段:
POST /website/blog/1/_update
{
"doc" : {
"tags" : [ "testing" ],
"views": 0
}
}
如果请求成功,我们就会收到一个类似于索引
时返回的内容
使用脚本进行更新
默认的脚本语言叫做MVEL,但是Elasticsearch也支持JavaScript, Groovy 以及 Python。MVEL是一个简单高效的JAVA基础动态脚本语言,它的语法类似于Javascript。脚本语言可以在更新
API中被用来修改_source
中的内容,而它在脚本中被称为ctx._source
。例如,我们可以使用脚本来增加博文中views
的数字:
POST /website/blog/1/_update
{
"script" : "ctx._source.views+=1"
}
我们同样可以使用脚本在tags
数组中添加新的tag。在这个例子中,我们把新的tag声明为一个变量,而不是将他写死在脚本中。这样Elasticsearch就可以重新使用这个脚本进行tag的添加,而不用再次重新编写脚本了:
POST /website/blog/1/_update
{
"script" : "ctx._source.tags+=new_tag",
"params" : {
"new_tag" : "search"
}
}
获取文档,后两项发生了变化:
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 5,
"found": true,
"_source": {
"title": "My first blog entry",
"text": "Starting to get the hang of this...",
"tags": ["testing", "search"], <1>
"views": 1 <2>
}
}
tags
数组中出现了search
。views
字段增加了。
我们甚至可以使用ctx.op
来根据内容选择是否删除一个文档:
POST /website/blog/1/_update
{
"script" : "ctx.op = ctx._source.views == count ? 'delete' : 'none'",
"params" : {
"count": 1
}
}
更新一篇可能不存在的文档
想象一下,我们可能需要在Elasticsearch中存储一个页面计数器。每次用户访问这个页面,我们就增加一下当前页面的计数器。但是如果这是个新的页面,我们不能确保这个计数器已经存在。如果我们试着去更新一个不存在的文档,更新操作就会失败。
为了防止上述情况的发生,我们可以使用upsert
参数来设定文档不存在时,它应该被创建:
POST /website/pageviews/1/_update
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 1
}
}
首次运行这个请求时,upsert
的内容会被索引成新的文档,它将views
字段初始化为1
。当之后再请求时,文档已经存在,所以脚本
更新就会被执行,views
计数器就会增加。
为了避免丢失数据,更新
API会在获取步骤中获取当前文档中的_version
,然后将其传递给重新索引步骤中的索引
请求。如果其他的进程在这两部之间修改了这个文档,那么_version
就会不同,这样更新就会失败。
对于很多的局部更新来说,文档有没有发生变化实际上是不重要的。例如,两个进程都要增加页面浏览的计数器,谁先谁后其实并不重要 —— 发生冲突时只需要重新来过即可。
你可以通过设定retry_on_conflict
参数来设置自动完成这项请求的次数,它的默认值是0
。
POST /website/pageviews/1/_update?retry_on_conflict=5 <1>
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 0
}
}
- 失败前重新尝试5次