Elasticsearch 基于脚本进行 partial update
发布于: 2021 年 01 月 27 日

文字内容整理自 B 站中华石杉的 Elasticsearch 顶尖高手系列课程核心知识篇,教程原本是基于 Groovy 脚本,现在的 Elasticsearch 似乎已经不怎么支持了,我把脚本改为了 painless 的,过程一点都不 painless。
Elasticsearch 有个内置的脚本支持,可以基于 groovy painless 脚本实现各种各样的复杂操作。
先生成一条测试数据。
PUT test_index/_doc/12{ "num": 0, "tags": []}
{ "_index" : "test_index", "_type" : "_doc", "_id" : "12", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 4, "_primary_term" : 1}复制代码
内置脚本 inline script
POST test_index/_update/11{ "script": "ctx._source.num+=1"}
{ "error" : { "root_cause" : [ { "type" : "illegal_argument_exception", "reason" : "failed to execute script" } ], "type" : "illegal_argument_exception", "reason" : "failed to execute script", "caused_by" : { "type" : "script_exception", "reason" : "runtime error", "script_stack" : [ "ctx._source.num+=1", " ^---- HERE" ], "script" : "ctx._source.num+=1", "lang" : "painless", "position" : { "offset" : 17, "start" : 0, "end" : 18 }, "caused_by" : { "type" : "null_pointer_exception", "reason" : null } } }, "status" : 400}
POST test_index/_update/11{ "script": "ctx._source.num+=1", "lang": "groovy"}
{ "error" : { "root_cause" : [ { "type" : "x_content_parse_exception", "reason" : "[3:3] [UpdateRequest] unknown field [lang]" } ], "type" : "x_content_parse_exception", "reason" : "[3:3] [UpdateRequest] unknown field [lang]" }, "status" : 400}复制代码
Elasticsearch 似乎已经不支持 groovy 了, 从官方文档看大概是从 5.6 版本,默认的脚本语言从 groovy 改为了 painless。
POST test_index/_update/11{ "script": { "lang": "painless", "source": "ctx._source.num+=1" }}
{ "_index" : "test_index", "_type" : "_doc", "_id" : "11", "_version" : 7, "result" : "updated", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 8, "_primary_term" : 1}复制代码
外部脚本
POST _scripts/test-add-tags{ "script": { "lang": "groovy", "source": "ctx._source.tags+=new_tag" }}
{ "error" : { "root_cause" : [ { "type" : "illegal_argument_exception", "reason" : "unable to put stored script with unsupported lang [groovy]" } ], "type" : "illegal_argument_exception", "reason" : "unable to put stored script with unsupported lang [groovy]" }, "status" : 400}
POST _scripts/test-add-tags{ "script": { "lang": "painless", "source": "ctx._source.tags+=new_tag" }}
{ "acknowledged" : true}复制代码
虽然 painless 的脚本写进去了,但是后来执行的时候却发生了编译错误,似乎是不支持"+=" 操作。于是我把脚本改的简单了一点。
POST _scripts/test-add-tags{ "script": { "lang": "painless", "source": "ctx._source.num += params.my_val" }}
POST test_index/_update/12{ "script": { "id": "test-add-tags", "params": { "my_val": 100 } }}复制代码
用脚本删除文档
PUT test_index/_doc/1{ "num": 1}
POST _scripts/test-delete-document{ "script": { "lang": "painless", "source": "ctx.op = ctx._source.num == params.count ? 'delete':'none'" }}
POST test_index/_update/1{ "script": { "id": "test-delete-document", "params": { "count": 12 } }}
{ "_index" : "test_index", "_type" : "_doc", "_id" : "1", "_version" : 3, "result" : "updated", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 24, "_primary_term" : 1}
POST test_index/_update/1{ "script": { "id": "test-delete-document", "params": { "count": 1 } }}
{ "_index" : "test_index", "_type" : "_doc", "_id" : "1", "_version" : 4, "result" : "updated", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 25, "_primary_term" : 1}
# Elasticsearch 5.2# groovy# ctx.op = ctx._source.num == count ? 'delete' : 'none'
POST /test_index/test_type/11/_update{ct "script": { "lang": "groovy", "file": "test-delete-document", "params": { "count": 1 } }}复制代码
upsert 操作
POST test_index/_update/13{ "doc": { "num": 13 }}
{ "error" : { "root_cause" : [ { "type" : "document_missing_exception", "reason" : "[_doc][13]: document missing", "index_uuid" : "itFrdXbPQ-ukBl1sp5EbOA", "shard" : "0", "index" : "test_index" } ], "type" : "document_missing_exception", "reason" : "[_doc][13]: document missing", "index_uuid" : "itFrdXbPQ-ukBl1sp5EbOA", "shard" : "0", "index" : "test_index" }, "status" : 404}复制代码
如果指定的 document 不存在,就执行 upsert 中的初始化操作;如果指定的 document 存在,就执行 doc 或者 script 指定的 partial update 操作。
POST test_index/_update/13{ "script": "ctx._source.num+=1", "upsert": { "num": 13, "tags": [] }}
{ "_index" : "test_index", "_type" : "_doc", "_id" : "13", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 35, "_primary_term" : 1}复制代码
如果再次执行,就可以看到执行了内置脚本中的 +=1 操作。
划线
评论
复制
发布于: 2021 年 01 月 27 日阅读数: 26
版权声明: 本文为 InfoQ 作者【escray】的原创文章。
原文链接:【http://xie.infoq.cn/article/2be3e3ff62def0bfe58760649】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
escray
关注
Let's Go 2017.11.19 加入
在学 Elasticsearch 的项目经理











评论