Elasticsearch 7.x 深入【13】Script

1. 借鑒

極客時(shí)間 阮一鳴老師的Elasticsearch核心技術(shù)與實(shí)戰(zhàn)
官網(wǎng) modules-scripting-using
官網(wǎng) painless-execute-api
官網(wǎng) Painless Scripting Language
Elasticsearch Painless script編程

2. 開(kāi)始

script在很多場(chǎng)景下都有使用到,我們這次來(lái)看下

結(jié)構(gòu)

"script": {
  "lang": "painless" // 腳本語(yǔ)言:painless(默認(rèn)),expression,可省略
  "source": """  // 腳本內(nèi)容(inline腳本)
    這里面是腳本
  """,
  "id": "" // 腳本的ID(stored腳本),source和ID只能存在一個(gè)
  "params": { // source里面需要的參數(shù)
    "key1": value1,
    "key2": value2
  }
}

注意:本篇文章所有腳本,lang為painless

上下文

在不同的上下文中,獲取文檔字段使用的語(yǔ)法是不同的。

上下文 語(yǔ)法 示例:獲取文檔中的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": "測(cè)試hot ctiy的pipeline",
  "processors": [
    {
      "script": {
        "source": """
          ctx.total = ctx.hot + ctx.count
        """,
        "params": {
          // ctx._index = 'hot_city';
          // ctx._type = '_doc';
          
        }
      }
    }
  ]
}

update script

例子:為文檔1的count加上操作數(shù)

POST /hot_city/_update/1
{
   "script" : {
     "source": "ctx._source.count += params.count",
     "params" : {
        "count" : 10
     }
   }
}

update_by_query

例子:通過(guò)腳本增加字段

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

例子:將原字段拼接為一個(gè)新的格式化之后的字段

GET hot_city/_search
{
  "script_fields": {
    "formative": {
      "script": {
        "source": "params._source.city + ( params.markup * params._source.hot )",
        "params": {
          "markup": 0.2
        }
      }
    }
  }
}

sort_script

例子:自定義排序規(guī)則

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,自定義腳本指標(biāo)統(tǒng)計(jì)

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

大部分情況我們會(huì)將腳本保存到節(jié)點(diǎn)中,那要如何操作呢?

  • 語(yǔ)法
POST _scripts/腳本名稱
{
  "script": {
    "lang": "painless",  // 使用的腳本語(yǔ)言,必填
    "source": "" // 腳本內(nèi)容,必填
  }
}

例子:增加熱門(mén)城市的熱度

POST _scripts/hot_city_update_count
{
  "script": {
    "lang": "painless", 
    "source": "ctx._source.count += params.count"
  }
}

使用保存的腳本進(jìn)行更新

POST /hot_city/_update/1
{
  "script": {
    "id": "hot_city_update_count",
    "params": {
      "count": 1
    }
  }
}

注意:上面所有的inline腳本我們都可以保存在節(jié)點(diǎn)中,只是看場(chǎng)景而已。

緩存

es 會(huì)將腳本(inline和stored)緩存起來(lái),可在elasticsearch.yml文件中做出更改

屬性 釋義
script.cache.max_size 設(shè)置可緩存腳本的最大值,默認(rèn)為100
script.cache.expire 設(shè)置緩存腳本的有效期
script.max_compilations_rate 默認(rèn)每5分鐘最多編譯75次
script.max_size_in_bytes 存儲(chǔ)腳本的大小限制為65535字節(jié)

3. 大功告成

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容