这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
有时候在使用_update_by_query接口进行更新数据感觉没有那么自由,这时候可以考虑使用painless脚本去进行自由的更新数据。
Painless是一种简单、安全的脚本语言,专为与 Elasticsearch 一起使用而设计。它是 Elasticsearch 的默认脚本语言,可以安全地用于内联和存储脚本。
- 快速的性能:painless运行速度是其他替代脚本的数倍
- 安全性:具有方法调用/字段粒度的细粒度白名单
- 可选类型:变量和参数可以使用显式类型或动态
def
类型 - 语法:扩展 Java 语法的一个子集以提供额外的脚本语言功能
- 优化:专为 Elasticsearch 脚本编写
假设有一个关于用户的头像(icon)和经常访问的链接(links)两个属性,由于网站进行国际化发展,cn的域名已经不适合,需要使用com域名,那么我们使用painless可以怎样进行更新数据呢?
PUT /user
{
"mappings": {
"properties": {
"icon": {
"type": "keyword"
},
"links": {
"type": "keyword"
}
}
}
}
POST /user/_doc/1
{
"icon": "http://cdn.ace.cn/img/98c1d2b3-b1bf-4135-810f-53211aa432fe.png",
"links": ["http://www.ace.cn"]
}
更新数据:
访问文档的数据使用链式访问,ctx._source指向原文档内容。那么访问头像的话,这样访问即可:ctx._source.icon。后面的链式语法就和java的语法一样(Elasticsearch底层使用的就是java),比如判断字符串是否含有某子串:String.indexOf('subString')
字符串子串替换函数:String.replace('old_string', 'new_string')
判断一个列表的元素个数: Array.size()
POST /user/_update/1
{
"script": {"source":
"if(ctx._source.icon.indexOf('ace.cn')!=-1){ctx._source.icon=ctx._source.icon.replace('ace.cn', 'ace.com');}if(ctx._source.links.size()>0){ctx._source.links[0]=ctx._source.links[0].replace('ace.cn', 'ace.com')}"
}
}
执行后效果:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "student",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"icon" : "http://cdn.ace.com/img/98c1d2b3-b1bf-4135-810f-53211aa432fe.png",
"links" : [
"http://www.ace.com"
]
}
}
]
}
}
上面是对单一文档数据的更新, 如果要对整个索引里面的所有文档进行更新,那么可以直接使用_update_by_query:
POST /user/_update_by_query
{
"script": {"source":
"if(ctx._source.icon.indexOf('ace.cn')!=-1){ctx._source.icon=ctx._source.icon.replace('ace.cn', 'ace.com');}if(ctx._source.links.size()>0){ctx._source.links[0]=ctx._source.links[0].replace('ace.cn', 'ace.com')}"
}
}