[toc]
1. 单文档 Update API
update API 根据提供的script更新文档; 从索引中获取document, 执行脚本, 并对新的结果进行索引.
如何确保 get 和 reindex 期间没有发生更新? --> 使用版本控制
;
这种操作仍然意味着对文档进行完整的重新索引, 它只是移除了一些网络往返损耗,并减少了get和索引之间版本冲突的机会.
1. script更新: 数值计算
示例: 新建一个document到 test 索引, 然后修改 counter=counter+4; 然后为tags新增一个 blue的颜色:
#1. 新建一个document到 test 索引
PUT test/_doc/1
{
"counter" : 1,
"tags" : ["red"]
}
将 "counter"的值加上给定的参数:
POST test/_update/1
{
"script" : {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
}
}
查看当前: GET test/_source/1
{
"counter" : 5,
"tags" : [
"red"
]
}
同理: counter=counter*2:
POST test/_update/1
{
"script": {
"source": "ctx._source.counter *= params.val",
"params": {
"val": 2
}
}
}
2. script更新: 数组(集合)增加/删除
2.1 增加一个 yellow:
POST test/_update/1
{
"script": {
"source": "ctx._source.tags.add(params.clr)",
"params": {"clr": "yellow"}
}
}
output:
{
"counter" : 10,
"tags" : [
"red",
"yellow"
]
}
2.2 删除(注意是索引)
实际是ArrayList
的方法!
POST test/_update/1
{
"script": {
"source": "ctx._source.tags.remove(params.val)",
"params": {
"val": 0
}
}
}
{
"counter" : 10,
"tags" : [ "yellow" ]
}
2.3 clear()清空
同理, 可以调用 ArrayList
的其他方法: 比如 :
POST test/_update/1
{
"script": {
"source": "ctx._source.tags.clear()"
}
}
2.4 如何删除匹配的内容
如果现在 tags = ["yello", "red", "blue"], 要删除 "red", 根据内容而非索引:
POST test/_update/1
{
"script": {
"source": "if (ctx._source.tags.contains(params.val)) {ctx._source.tags.remove(ctx._source.tags.indexOf(params.val));}",
"params": {
"val": "red"
}
}
}
GET test/_source/1
output:
{
"counter" : 10,
"tags" : [
"yellow",
"blue"
]
}
注意: script.source 里的";"可以不要的;
2.5 script更新: ctx的其他内置变量
除了 _source
之外,ctx映射还提供了以下变量: _index
、_type
、_id
、_version
、_routing
和 _now
(当前时间戳)。
2.6 script更新: 增加/删除字段entry
我们给 test 索引中的 文档 1 新增一个字段: "addr": "beijing":
# update 增加字段entry
POST test/_update/1
{
"script": {
"source": "ctx._source.addr='beijing'"
}
}
# 再增加一条
POST test/_update/1
{
"script": {
"source": "ctx._source.location='yizhuang'"
}
}
GET test/_source/1
{
"counter" : 10,
"tags" : [
"yellow"
],
"addr" : "beijing",
"location" : "yizhuang"
}
删除:
# update 删除字段
POST test/_update/1
{
"script": {
"source": "ctx._source.remove('location')"
}
}
GET test/_source/1
:
{
"counter" : 10,
"tags" : [
"yellow"
],
"addr" : "beijing"
}
3. doc新增字段:
除了使用 script 外, 也可以使用 doc 来新增字段; 如果二者皆有, 会报错!
POST test/_update/1
{
"doc" : {
"loc" : "yz"
}
}
{
"counter" : 10,
"tags" : [
"yellow"
],
"addr" : "beijing",
"loc" : "yz"
}
如果指定了doc,那么它的值将与现有的_source合并; 如果 doc执行了多次, 数据并没有变化, \_version和 \_seq\_no都不会更新! "result" : "noop"
4. upsert 更新+插入
4.1 script+upsert方式
如果文档还不存在,那么upsert元素的内容将作为新文档插入。如果该文档存在,则执行脚本:
DELETE test/_doc/2
我们先执行此操作删除id=2的document; 然后执行下面 upsert 操作:
POST test/_update/2
{
"script" : {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
},
"upsert" : {
"counter" : 2,
"name": "ifnotexists"
}
}
因为此刻没有 id=2的文档, 所以默认+=操作时是不会有的; 这样的话, upsert中的内容就会作为文档的内容保存;
这是 重复上面的 upsert 操作一次!! 再查结果: GET test/_source/2
{
"counter" : 6,
"name" : "ifnotexists"
}
可以看到, counter就是 2+4了;
4.2 doc方式的upsert
doc方式也可以实现upsert: 如下: 如果单纯是在上面有id=2的document的基础上执行下面:
POST test/_update/2
{
"doc": {
"gender": "male"
},
"doc_as_upsert": true
}
只是增加了一个 gender的字段!
{
"counter" : 6,
"name" : "ifnotexists",
"gender" : "male"
}
现在删掉document: DELETE test/_doc/2
, 就会表现为 upsert的功能了, 此时 GET test/_source/2
:
{"gender" : "male"}
5. update的其他参数
timeout/wait_for_active_shards/version, 以及 if_seq_no + if_primary_term
5.1 if_seq_no+if_primary_term
POST test/_update/2?if_seq_no=31&if_primary_term=1
{
"script": {
"source": "ctx._source.counter=params.val",
"params": {
"val": 3
}
}
}
如果 _seq_no
和 _primary_term
匹配, 才执行更新, 否则报错!