1、背景

此篇文档仅仅是简略的记录一下painless的一些简略的例子,避免当前遗记,不过多波及painless的语法。

2、筹备数据

2.1 mapping

PUT /index_person{  "mappings": {    "properties": {      "name": {        "type": "keyword"      },      "age": {        "type": "integer"      },      "province": {        "type": "keyword"      }    }  }}

2.2 插入数据

PUT /index_person/_bulk{"index":{"_id":1}}{"name":"张三","age":20,"province":"湖北"}{"index":{"_id":2}}{"name":"李四","age":25,"province":"北京"}{"index":{"_id":3}}{"name":"王五","age":30,"province":"湖南"}

3、例子

3.1 (update)更新文档 id=1 的文档,将 age 加 2岁

POST index_person/_update/1{  "script": {    "lang": "painless",    "source": """      ctx['_source']['age'] += params['incrAge']    """,    "params": {      "incrAge": 2    }  }}

3.2 (update_by_query)如果 province 是北京的话,就将 age 缩小1岁

POST index_person/_update_by_query{  "query": {    "term": {      "province": {        "value": "北京"      }    }  },  "script": {    "lang": "painless",    "source": """      ctx['_source']['age'] -= params['decrAge']    """,    "params": {      "decrAge": 1    }  }}

3.3 (ctx.op)如果张三的年龄小于20岁就不解决,否则就删除这个文档

POST index_person/_update/1{  "script": {    "lang": "painless",    "source": """      // 这是默认值,示意的是更新值,从新索引记录      ctx.op = 'index';      if(ctx._source.age < 20){        // 示意不解决        ctx.op = 'none';      }else{        // 示意删除这个文档       ctx.op = 'delete';       }    """  }}

3.4 (stored script)如果是湖南省则减少地市字段,值为长沙

3.4.1 创立存储脚本
PUT _scripts/add_city{  "script":{    "lang": "painless",    "source": "ctx._source.city = params.city"  }}

add_city为脚本的id

3.4.2 应用存储脚本
POST index_person/_update_by_query{  "query": {    "term": {      "province": {        "value": "湖南"      }    }  },  "script": {    "id": "add_city",    "params": {      "city": "长沙"    }  }}

3.5 (pipeline)通过pipeline如果插入的文档的age<10则放入到index_person_small索引中

3.5.1 创立pipeline
PUT _ingest/pipeline/pipeline_index_person_small{  "description": "如果插入的文档的age<10则放入到index_person_small索引中",  "processors": [    {      "script": {        "source": """            if(ctx.age < 10){              ctx._index = 'index_person_small';            }          """      }    }  ]}
3.5.2 应用pipeline
PUT index_person/_doc/4?pipeline=pipeline_index_person_small{  "name":"赵六",  "age": 8,  "province":"四川"}
3.5.3 运行后果

3.6 function_score中应用script_score算分

3.6.1 需要

如果这个用户是湖南的,则应用 age作为分数

3.6.2 dsl

GET index_person/_search{  "query": {    "function_score": {      "query": {        "match_all": {}      },      "functions": [        {          "script_score": {                        "script": """              if(doc.province.value == 0){                return 0;              }                          if(doc.province.value == '湖南'){                return doc.age.value;              }              return 0;            """          }        }      ],      "boost_mode": "sum",      "score_mode": "sum"    }  }}

3.6.3 运行后果

3.7 script_fields 减少字段

GET index_person/_search{  "query": {"match_all": {}},  "fields": [    "double_age"  ],   "script_fields": {    "double_age": {      "script": {        "lang": "painless",        "source": "doc.age.value * 2"      }    }  }}

3.8 runtime field 减少字段

3.8.1 需要

针对age<25的文档,返回double_age字段,否则不解决。

3.8.2 dsl

GET index_person/_search{  "query": {    "match_all": {}  },  "fields": [    "double_age"  ],  "runtime_mappings": {    "double_age":{       "type": "keyword",      "script": """        if(doc.age.size() == 0){          return;        }        if(doc.age.value < 25){          emit(doc.age.value * 2 + '');        }      """    }  }}

在runtime field 中,须要应用emit来返回数据,然而不是emit(null)

3.9 _reindex 中应用

3.9.1 dsl

POST _reindex{  "source": {    "index": "index_person"  },  "dest": {    "index": "index_person_new"  },  "script": {    "lang": "painless",    "source": """      if(ctx._source.age < 25){        ctx._source.tag = '年轻人';      }else{        ctx._source.tag = '中年人';      }    """  }}

3.9.2 运行后果

3.10 script query 查问age<25

GET index_person/_search{  "query": {    "script": {      "script": {        "lang": "painless",        "source": """          if(doc.age.size() == 0){            return false;          }          return doc.age.value < 25;        """      }    }  }}

3.11 script 聚合

GET index_person/_search{  "size": 0,   "aggs": {    "agg_province": {      "terms": {        "script": {          "lang": "painless",          "source": """            return doc.province          """        },         "size": 10      }    },    "agg_age":{      "avg": {        "script": "params._source.age"      }    }  }}

4、painless脚本调试


能够通过Debug.explain来进行一些简略的调试。

5、脚本中的doc[..]和params._source[..]

doc[..]:应用doc关键字,将导致该字段的术语被加载到内存(缓存),这将导致更快的执行,但更多的内存耗费。此外,doc[…]表示法只容许简略的值字段(您不能从中返回json对象),并且仅对非剖析或基于单个术语的字段有意义。然而,如果可能的话,应用doc依然是拜访文档值的举荐办法。
params_source: 每次应用_source都必须加载和解析, 因而应用_source会相对而言要慢点。

![脚本中的doc[..]和params._source[..]](https://img-blog.csdnimg.cn/1...)

6、painless脚本中的上下文


具体理解,请参考这个文档https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-contexts.html