ES API 之 UPDATE

ES本身是一个倾向于查询检索的框架,对于更新的操作,太过频繁总归不好的。
阅读本篇后,你可以使用Script对所有的文档执行更新操作,也可以使用doc对部分文档执行更新,也可以使用upsert对不存在的文档执行添加操作。
参考:http://www.cnblogs.com/xing901022/p/5330778.html

更新

更新操作允许ES获得某个指定的文档,可以通过脚本等操作对该文档进行更新。
可以把它看成是先删除再索引的原子操作,只是省略了返回的过程,这样即节省了来回传输的网络流量,也避免了中间时间造成的文档修改冲突。
下面例子,查找id为25的文档:

1
curl -XGET localhost:9200/bank/account/25?pretty
APACHE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"_index": "bank",
"_type": "account",
"_id": "25",
"_version": 1,
"found": true,
"_source": {
"account_number": 25,
"balance": 40540,
"firstname": "Virginia",
"lastname": "Ayala",
"age": 39,
"gender": "F",
"address": "171 Putnam Avenue",
"employer": "Filodyne",
"email": "virginiaayala@filodyne.com",
"city": "Nicholson",
"state": "PA"
}
}
JSON

脚本更新

Es支持通过脚本更改文档的信息:

1
2
3
4
5
6
7
8
curl -XPOST 'localhost:9200/bank/account/25/_update' -d '{
"script" : {
"inline": "ctx._source.age += number",
"params" : {
"number" : 5
}
}
}'
ADA

结果报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"error": {
"root_cause": [
{
"type": "remote_transport_exception",
"reason": "[lihao][127.0.0.1:9300][indices:data/write/update[s]]"
}
],
"type": "illegal_argument_exception",
"reason": "failed to execute script",
"caused_by": {
"type": "script_exception",
"reason": "scripts of type [inline], operation [update] and lang [groovy] are disabled"
}
},
"status": 400
}
N1QL

报错原因:在最新版本的Elasticsearch中,基于安全考虑(如果用不到,请保持禁用),默认禁用了动态脚本功能。
完全开启动态脚本功能:
script.inline: on
script.indexed: on
script.file: on
重启ES

1
2
3
4
5
6
7
8
9
10
11
{   
"_index": "bank",
"_type": "account",
"_id": "25",
"_version": 2,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
JSON
1
curl -XGET localhost:9200/bank/account/25?pretty  
APACHE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
  "_index" : "bank",
  "_type" : "account",
  "_id" : "25",
  "_version" : 2,
  "found" : true,
  "_source" : {
    "account_number" : 25,
    "balance" : 40540,
    "firstname" : "Virginia",
    "lastname" : "Ayala",
    "age" : 44,
    "gender" : "F",
    "address" : "171 Putnam Avenue",
    "employer" : "Filodyne",
    "email" : "virginiaayala@filodyne.com",
    "city" : "Nicholson",
    "state" : "PA"
  }
}
JSON

上面就是通过参数来为age加5。

除了_source字段,可以通过ctx来获得_index、_type、_id、_version、_parent、_timestamp、_ttl等字段信息。
也可以添加某个字段:

1
2
3
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"script" : "ctx._source.name_of_new_field = \"value_of_new_field\""
}'
SWIFT

移除字段:

1
2
3
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"script" : "ctx._source.remove(\"name_of_field\")"
}'
SWIFT

也支持稍微复杂点的操作,逻辑判断,比如根据某个标记执行不同的操作。比如如果有blue这个标记,则删除该文档;否则什么也不做:

1
2
3
4
5
6
7
8
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"script" : {
"inline": "ctx._source.tags.contains(tag) ? ctx.op = \"delete\" : ctx.op = \"none\"",
"params" : {
"tag" : "blue"
}
}
}'
SWIFT

只更新部分文档

上面的脚本是对所有的文档都起作用,这里讲解下如何只对部分文档进行修改。使用doc可以实现简单的递归合并、内部合并、替换KV以及数组。

1
2
3
4
5
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"doc" : {
"name" : "new_name"
}
}'
ADA

如果同时使用了doc和script,那么doc的操作会自动忽略。因此最好是把特殊的操作也放在脚本中。

更新检测

如果使用doc,那么会自动合并到现有的文档中。如果doc中定义的部分与现在的文档相同,则默认不会执行任何动作。设置detect_noop=false,就会无视是否修改,强制合并到现有的文档。

1
2
3
4
5
6
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"doc" : {
"name" : "new_name"
},
"detect_noop": false
}'
SWIFT

上面的例子中,如果name字段为new_name,无论当前的文档是否与doc中定义的相同,都会把doc合并到文档中。

upsert插入

这个参数主要用于当文档不存在时,ES的操作。

1
2
3
4
5
6
7
8
9
10
11
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"script" : {
"inline": "ctx._source.counter += count",
"params" : {
"count" : 4
}
},
"upsert" : {
"counter" : 1
}
}'
ADA

在上面的例子中,当文档存在时,执行脚本;当文档不存在时,upsert中的内容就会插入到对应的文档中。
如果你想无论文档是否存在都执行脚本操作,那么可以使用参数scripted_upsert为true。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
curl -XPOST 'localhost:9200/sessions/session/dh3sgudg8gsrgl/_update' -d '{
"scripted_upsert":true,
"script" : {
"id": "my_web_session_summariser",
"params" : {
"pageViewEvent" : {
"url":"foo.com/bar",
"response":404,
"time":"2014-01-01 12:32"
}
}
},
"upsert" : {}
}'
ADA

相对于之前的使用Upsert中的内容添加到不存在的文档,使用doc_as_upsert可以在文档不存在的时候,把doc中的内容插入到文档中。

1
2
3
4
5
6
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"doc" : {
"name" : "new_name"
},
"doc_as_upsert" : true
}'
SWIFT

ES API 之 UPDATE
https://leehoward.cn/2019/10/17/ES API 之 UPDATE/
作者
lihao
发布于
2019年10月17日
许可协议