1 关于脚本

ES提供了脚本支持 —— 可以通过Groovy外置脚本(已过时)、内置painless脚本实现各种复杂操作.

—— painless有轻便之意, 使用时直接在语法中调用即可, 无需外置, 也就是不支持通过外部文件存储painless脚本并调用的方法.

// 向ES中插入一条数据:
PUT employee/developer/1
{
    "name": "shou feng",
    "age": 20,
    "salary": 10000
}

// 通过GET发送脚本, 允许为每个匹配的文档返回脚本评估(script evaluation)内容:
GET employee/_search
{
    "script_fields": {
        "change_age_field": {   // 该字段不存在 - script fields可以处理未存储的字段
            "script": {
                "lang":   "expression",
                "source": "doc['age'] * multiplier",  // 获取age字段的值进行计算
                "params": {
                    "multiplier": 2
                }
            }
        }
    }
}

// 响应结果为:
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "employee",
        "_type" : "developer",
        "_id" : "1",
        "_score" : 1.0,
        "fields" : {
          "change_age_field" : [
            40.0
          ]
        }
      }
    ]
  }
}

2 脚本使用的最佳实践

Elasticsearch第一次加载一个新脚本时, 会将新脚本编译并存储在缓存中.

编译可能是一个繁重的过程, 如果需要将变量传递给脚本, 建议: 将它们作为命名参数传递给脚本本身(方式①), 而不是硬编码在脚本中(方式②).

(1) 方式① 参数传递:

"source": "doc['age'] * multiplier",
"params": {
    "multiplier": 2
}

(2) 方式② 硬编码:

"source": "doc['age'] * 2"

(3) 优劣对比:

  • 每次乘数改变时都必须重新编译第②个版本, 而第①个版本只编译一次.

  • 如果短时间内编译过多的脚本, ES将拒绝带有circuit_breaking_exception错误的新脚本.

  • Elasticsearch默认情况下, 每分钟最多编译15个内联脚本, 可以通过修改 script.max_compilations_rate 的值来更改此设置.

2.1 创建脚本并存储

可以使用_scripts API 将脚本存储在集群状态中, 并从集群状态中检索脚本.

使用_scripts/{id}的方式操作脚本, 具体步骤如下:

(1) 首先在集群状态中创建名为calculate-score的脚本:

POST _scripts/calculate-score
{
    "script": {
        "lang": "painless",
        "source": "Math.log(_score * 2) + params.my_modifier"
    }
}

(2) 检索存储的脚本:

GET _scripts/calculate-score

(3) 通过脚本id使用已创建的脚本:

GET _search
{
    "query": {
        "script": {
            "script": {
                "id": "calculate-score",
                "params": {
                    "my_modifier": 2    // 传递脚本所需的参数
                }
            }
        }
    }
}

(4) 删除脚本:

DELETE _scripts/calculate-score

2.2 脚本的缓存

默认情况下, 所有的脚本都会被缓存到ES集群中, 因此只有当脚本被更新之后, ES才会重新编译它们.

同样, 脚本没有过期时间的说法, 但可以使用script.cache.expire设置更改过期时间.

也可以使用script.cache.max_size配置此脚本缓存的大小, 默认缓存大小为100.

存储脚本的大小限制为65535字节, 可以通过 script.max_size_in_bytes来更改, 但是如果脚本非常大, 就应该考虑相关脚本的实现引擎是否足够优秀.

2.3 Script Field - 脚本字段

脚本字段还可以通过访问_source字段来提取文档的其他字段 —— 使用params ['_source']提取要从中获取的内容.

另外: 理解doc['my_field'].valueparams['_source']['my_field']之间的区别非常重要:


08-16 01:09