painless语法
painless基础结构
"script": {
"lang": "...",
"source" | "id": "...",
"params": { ... }
}
- lang: 定义脚本使用的语言, 默认painless
- source, id: 脚本的主体, source后面跟着内联的脚本代码, id后面跟着脚本的id, 具体代码存在于脚本id对应的代码中
- params: 定义一些变量的值, 使用params可以减少脚本的编译次数. 因为如果变量的值硬编码到代码中, 每次进行变量值得更改都会对脚本进行重新编译. 使用params则不会重新编译脚本.
script.context.field.max_compilations_rate=75/5m 脚本的默认编译频率, 定义脚本的编译频率为5分钟75个, 当超过75个时会抛出circuit_breaking_exception异常.
脚本代码的存储
// POST _scripts/{id}
POST _scripts/calculate-score
{
"script": {
"lang": "painless",
"source": "Math.log(_score * 2) + params['my_modifier']"
}
}
// 脚本使用
GET my-index-000001/_search
{
"query": {
"script_score": {
"query": {
"match": {
"message": "some message"
}
},
"script": {
"id": "calculate-score",
"params": {
"my_modifier": 2
}
}
}
}
}
使用脚本对文档进行更新
PUT my-index-000001/_doc/1
{
"counter" : 1,
"tags" : ["red"]
}
// 将count加上4
POST my-index-000001/_update/1
{
"script" : {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
}
}
// 增加tags的元素
POST my-index-000001/_update/1
{
"script": {
"source": "ctx._source.tags.add(params['tag'])",
"lang": "painless",
"params": {
"tag": "blue"
}
}
}
// If the list contains duplicates of the tag, this script just removes one occurrence.
// 如果集合中有多个相同的值, 只删除第一个
POST my-index-000001/_update/1
{
"script": {
"source": "if (ctx._source.tags.contains(params['tag'])) { ctx._source.tags.remove(ctx._source.tags.indexOf(params['tag'])) }",
"lang": "painless",
"params": {
"tag": "blue"
}
}
}
// 增加新的字段
POST my-index-000001/_update/1
{
"script" : "ctx._source.new_field = 'value_of_new_field'"
}
// 删除字段
POST my-index-000001/_update/1
{
"script" : "ctx._source.remove('new_field')"
}
// 如果tags字段中包含green, 则删除该文档, 否则不做操作
POST my-index-000001/_update/1
{
"script": {
"source": "if (ctx._source.tags.contains(params['tag'])) { ctx.op = 'delete' } else { ctx.op = 'none' }",
"lang": "painless",
"params": {
"tag": "green"
}
}
}
// doc.containsKey('field')
脚本变量
- ctx._source.field: add, contains, remove, indexOf, length
- ctx.op: The operation that should be applied to the document: index or delete
- ctx._index: Access to document metadata fields
- _score 只在script_score中有效
- doc[‘field’], doc[‘field’].value: add, contains, remove, indexOf, length
脚本缓存
- You can change this behavior by using the
script.cache.expire
setting. Use thescript.cache.max_size
setting to configure the size of the cache.The size of scripts is limited to 65,535 bytes. Set the value ofscript.max_size_in_bytes
to increase that soft limit. - Cache sizing is important. Your script cache should be large enough to hold all of the scripts that users need to be accessed concurrently.
脚本优化
- 使用脚本缓存, 预先缓存可以节省第一次的查询时间
- 使用ingest pipeline进行预先计算
- 相比于_source.field_name使用doc[‘field_name’]语法速度更快, doc语法使用doc value , 列存储
// 根据分数相加结果进行排序
GET /my_test_scores/_search
{
"query": {
"term": {
"grad_year": "2099"
}
},
"sort": [
{
"_script": {
"type": "number",
"script": {
"source": "doc['math_score'].value + doc['verbal_score'].value"
},
"order": "desc"
}
}
]
}
// 在索引中新加一个字段存储计算结果
PUT /my_test_scores/_mapping
{
"properties": {
"total_score": {
"type": "long"
}
}
}
// 使用ingest pipeline先将计算结果作为值存储起来
PUT _ingest/pipeline/my_test_scores_pipeline
{
"description": "Calculates the total test score",
"processors": [
{
"script": {
"source": "ctx.total_score = (ctx.math_score + ctx.verbal_score)"
}
}
]
}
// 重新索引时使用ingest pipeline
POST /_reindex
{
"source": {
"index": "my_test_scores"
},
"dest": {
"index": "my_test_scores_2",
"pipeline": "my_test_scores_pipeline"
}
}
// 索引新文档时使用ingest pipeline
POST /my_test_scores_2/_doc/?pipeline=my_test_scores_pipeline
{
"student": "kimchy",
"grad_year": "2099",
"math_score": 1200,
"verbal_score": 800
}
// 查询
GET /my_test_scores_2/_search
{
"query": {
"term": {
"grad_year": "2099"
}
},
"sort": [
{
"total_score": {
"order": "desc"
}
}
]
}
// stored field 用法
PUT my-index-000001
{
"mappings": {
"properties": {
"full_name": {
"type": "text",
"store": true
},
"title": {
"type": "text",
"store": true
}
}
}
}
PUT my-index-000001/_doc/1?refresh
{
"full_name": "Alice Ball",
"title": "Professor"
}
GET my-index-000001/_search
{
"script_fields": {
"name_with_title": {
"script": {
"lang": "painless",
"source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
}
}
}
}
用到脚本的命令
- function_score
- script_score
- aggregation
- rescore