1. 借鉴
极客时间 阮一鸣老师的Elasticsearch核心技术与实战
官网 modules-scripting-using
官网 painless-execute-api
官网 Painless Scripting Language
Elasticsearch Painless script编程
2. 开始
script在很多场景下都有使用到,我们这次来看下
结构
"script": {
"lang": "painless" // 脚本语言:painless(默认),expression,可省略
"source": """ // 脚本内容(inline脚本)
这里面是脚本
""",
"id": "" // 脚本的ID(stored脚本),source和ID只能存在一个
"params": { // source里面需要的参数
"key1": value1,
"key2": value2
}
}
注意:本篇文章所有脚本,lang为painless
上下文
在不同的上下文中,获取文档字段使用的语法是不同的。
上下文 | 语法 | 示例:获取文档中的name属性 |
---|---|---|
pipeline | ctx.field_name | ctx.name |
update | ctx._source.field_name | ctx._source.name |
update_by_query | ↑ | ↑ |
reindex | ↑ | ↑ |
search | doc["field_name"].value | doc["name"].value |
script_score | ↑ | ↑ |
script_fields | params._source.field_name | params._source.name |
sort_script | ↑ | ↑ |
scripted_metric | ↑ | ↑ |
注:↑表示这一行跟上一行是一样的
inline Script
pipeline
例子:自定义processor脚本
PUT /_ingest/pipeline/hot_city_pipeline_script
{
"description": "测试hot ctiy的pipeline",
"processors": [
{
"script": {
"source": """
ctx.total = ctx.hot + ctx.count
""",
"params": {
// ctx._index = 'hot_city';
// ctx._type = '_doc';
}
}
}
]
}
update script
例子:为文档1的count加上操作数
POST /hot_city/_update/1
{
"script" : {
"source": "ctx._source.count += params.count",
"params" : {
"count" : 10
}
}
}
update_by_query
例子:通过脚本增加字段
POST /hot_city/_update_by_query?conflicts=proceed
{
"script": {
"source": """
try
{
Integer total = ctx._source.hot + ctx._source.count;
ctx._source.total = total;
}
catch(NullPointerException npe)
{
}
""",
"lang": "painless"
}
}
reindex
POST _reindex
{
"source": {
"index": "hot_city"
},
"dest": {
"index": "hot_city_v1"
},
"script": {
"source": "ctx._source.total = ctx._source.hot + ctx._source.count"
}
}
query script
例子:查询城市是北京的
GET /hot_city/_search
{
"query": {
"script": {
// "script": "doc['hot'].value > 18"
"script": "doc['city'].value == '北京'"
}
}
}
script_score
例子:自定义算分
GET hot_city/_search
{
"query": {
"function_score": {
"query": {
"match_all": {}
},
"script_score": {
"script": {
"lang": "expression",
"source": "_score * doc['hot']"
}
}
}
}
}
script_fields
例子:将原字段拼接为一个新的格式化之后的字段
GET hot_city/_search
{
"script_fields": {
"formative": {
"script": {
"source": "params._source.city + ( params.markup * params._source.hot )",
"params": {
"markup": 0.2
}
}
}
}
}
sort_script
例子:自定义排序规则
GET hot_city/_search
{
"sort": [
{
"_script": {
"type": "number",
"script": {
"source": """
return params._source.hot + (params._source.count / params.base * params.markup)
""",
"params": {
"markup": 0.1,
"base": 10000
}
},
"order": "desc"
}
}
]
}
scripted_metric
例子:scripted_metric,自定义脚本指标统计
GET /hot_city/_search
{
"size": 0,
"aggs": {
"group_by_ctiy": {
"terms": {
"field": "city",
"size": 10
},
"aggs": {
"profile": {
"scripted_metric": {
"init_script": "state.datas = []",
"map_script": """
Map map = new HashMap();
map.put("name", params._source.city);
map.put("num", params._source.hot + params._source.count);
state.datas.add(map);
""",
"combine_script": """
double profit = 0; for (t in state.datas) { profit += t.num } return profit;
""",
"reduce_script": "double profit = 0; for (a in states) { profit += a } return profit;"
}
}
}
}
}
}
stored script
保存及使用script
大部分情况我们会将脚本保存到节点中,那要如何操作呢?
- 语法
POST _scripts/脚本名称
{
"script": {
"lang": "painless", // 使用的脚本语言,必填
"source": "" // 脚本内容,必填
}
}
例子:增加热门城市的热度
POST _scripts/hot_city_update_count
{
"script": {
"lang": "painless",
"source": "ctx._source.count += params.count"
}
}
使用保存的脚本进行更新
POST /hot_city/_update/1
{
"script": {
"id": "hot_city_update_count",
"params": {
"count": 1
}
}
}
注意:上面所有的inline脚本我们都可以保存在节点中,只是看场景而已。
缓存
es 会将脚本(inline和stored)缓存起来,可在elasticsearch.yml文件中做出更改
属性 | 释义 |
---|---|
script.cache.max_size | 设置可缓存脚本的最大值,默认为100 |
script.cache.expire | 设置缓存脚本的有效期 |
script.max_compilations_rate | 默认每5分钟最多编译75次 |
script.max_size_in_bytes | 存储脚本的大小限制为65535字节 |
网友评论