# /

# Scripting

Scripting模块下的文档
How to use scripts
Scripts and search speed
Accessing document fields and special variables
Scripting and security
Painless scripting language
Lucene expressions language
Advanced scripts using script engines
1
2
3
4
5
6
7
8

使用脚本,您可以在Elasticsearch中评估自定义表达式。例如,您可以使用脚本作为搜索请求的一部分返回“脚本字段”,或者评估查询的自定义分数。
默认的脚本语言是Painless。额外的lang插件可用于运行用其他语言编写的脚本。您可以在脚本运行的任何位置指定脚本的语言。

# Painless scripting language

Painless是一种专门为Elasticsearch设计的高性能、安全的脚本语言。您可以使用Painless在Elasticsearch支持的任何地方安全地编写内联和存储脚本。
首先,用一个字段为文档编制索引,这样我们就可以使用一些数据:

PUT my-index-000001/_doc/1
{
  "my_field": 5
}
1
2
3
4

然后,我们可以构造一个对该字段进行操作的脚本,并将该脚本作为查询的一部分运行评估。以下查询使用搜索API的script_fields参数来检索脚本估价。这里发生了很多事情,但我们将把它分解为各个组件,以单独理解它们。现在,您只需要理解这个脚本接受my_field并对其进行操作。

GET my-index-000001/_search
{
  "script_fields": {
    "my_doubled_field": {
      "script": { 
        "source": "doc['my_field'].value * params['multiplier']", 
        "params": {
          "multiplier": 2
        }
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

该脚本是一个标准的JSON对象,用于定义Elasticsearch中大多数API下的脚本。此对象需要source来定义脚本本身。脚本没有指定语言,因此它默认为Painless。

# 存储脚本(Store and retrieve scripts)

您可以使用_scripts端点从集群状态存储和检索脚本。使用存储的脚本可以帮助减少编译时间并加快搜索速度。使用_scripts/{id}中的{id}path元素引用存储的脚本。
注意:与常规脚本不同,存储脚本要求您使用lang参数指定脚本语言。

POST _scripts/calculate-score
{
  "script": {
    "lang": "painless",
    "source": "Math.log(_score * 2) + params['my_modifier']"
  }
}
1
2
3
4
5
6
7

您可以使用_scripts端点来检索该脚本:

GET _scripts/calculate-score

#返回
{
  "_id" : "calculate-score",
  "found" : true,
  "script" : {
    "lang" : "painless",
    "source" : "Math.log(_score * 2) + params['my_modifier']"
  }
}
1
2
3
4
5
6
7
8
9
10
11

要在查询中使用存储的脚本,请在脚本声明中包含脚本id:

GET my-index-000001/_search
{
  "query": {
    "script_score": {
      "query": {
        "match":{ "my_field": 5 }
      },
      "script": {
        "id": "calculate-score", 
        "params": {
          "my_modifier": 3//参数按需传入。
        }
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用脚本更新文档(Update documents with scripts)

首先,让我们为一个简单的文档编制索引:

PUT my-index-000001/_doc/1
{
  "counter" : 1,
  "tags" : ["red"]
}
1
2
3
4
5

要增加计数器,可以使用以下脚本提交更新请求:

POST my-index-000001/_update/1
{
  "script" : {
    "source": "ctx._source.counter += params.count",
    "lang": "painless",
    "params" : {
      "count" : 4
    }
  }
}
1
2
3
4
5
6
7
8
9
10

类似地,您可以使用更新脚本将标记添加到标记列表中。因为这只是一个列表,所以即使标签存在,也会添加它:

POST my-index-000001/_update/1
{
  "script": {
    "source": "ctx._source.tags.add(params['tag'])",
    "lang": "painless",
    "params": {
      "tag": "blue"
    }
  }
}
1
2
3
4
5
6
7
8
9
10

也可以从标记列表中删除标记。Java列表的remove方法在Painless中可用。它获取要删除的元素的索引。为了避免可能的运行时错误,您首先需要确保标记存在。如果列表中包含重复的标记,则此脚本只删除一个出现的标记。

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"
    }
  }
}
1
2
3
4
5
6
7
8
9
10

您还可以在文档中添加和删除字段。例如,此脚本添加字段new_field:

POST my-index-000001/_update/1
{
  "script" : "ctx._source.new_field = 'value_of_new_field'"
}
1
2
3
4

相反,此脚本会删除字段new_field:

POST my-index-000001/_update/1
{
  "script" : "ctx._source.remove('new_field')"
}
1
2
3
4

您也可以更改从脚本中执行的操作,而不是更新文档。例如,如果标记字段包含绿色,则此请求将删除文档。否则它什么也不做:

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"
    }
  }
}
1
2
3
4
5
6
7
8
9
10
# Painless examples for transforms

init_script 在state对象中创建一个long 类型的timestamp_latest和一个string 类型的last_doc。
map_script 根据文档的时间戳定义current_date,然后将current_date与state.timestamp_latest进行比较,最后返回state.last_doc。
combine_script 返回每个shard的state。
reduce_script 迭代每个shard,返回latest_doc。

"aggregations": {
  "latest_doc": {
    "scripted_metric": {
      "init_script": "state.timestamp_latest = 0L; state.last_doc = ''", 
      "map_script": """ 
        def current_date = doc['@timestamp'].getValue().toInstant().toEpochMilli();
        if (current_date > state.timestamp_latest)
        {state.timestamp_latest = current_date;
        state.last_doc = new HashMap(params['_source']);}
      """,
      "combine_script": "return state", 
      "reduce_script": """ 
        def last_doc = '';
        def timestamp_latest = 0L;
        for (s in states) {if (s.timestamp_latest > (timestamp_latest))
        {timestamp_latest = s.timestamp_latest; last_doc = s.last_doc;}}
        return last_doc
      """
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# mustache language

允许您使用mustache语言预先呈现搜索请求。
注意:当使用mustache语言存储脚本时,则这个脚本称为“搜索模板”。

# Store a search template

若要存储搜索模板,请使用创建存储脚本API。指定mustache 作为语言。

POST _scripts/templateid_1
{
  "script": {
    "lang": "mustache",
    "source": {
      "query": {
        "match": {
          "title": "{{query_string}}"
        }
      }
    }
  }
}

PUT my-index-000001/_doc/1
{
  "title": "标题1"
}
PUT my-index-000001/_doc/2
{
  "title": "标题2"
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

要在搜索时使用存储的模板,请发送以下请求:

GET my-index-000001/_search/template
{
  "id": "templateid_1", 
  "params": {
    "query_string": "标题"
  }
}
1
2
3
4
5
6
7
# 验证搜索模板(Validating a search template)

通过使用以下请求,可以在具有给定参数的响应中呈现模板:

GET _render/template
{
  "source": {
    "query": {
      "match": {
        "title": "{{query_string}}"
      }
    }
  },
  "params": {
    "query_string": "标题"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
# Using the explain parameter

运行模板时可以使用explain参数:

GET my-index-000001/_search/template
{
  "id": "templateid_1", 
  "params": {
    "query_string": "标题"
  },
  "explain": true
}
1
2
3
4
5
6
7
8
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.36464313,
    "hits" : [
      {
        "_shard" : "[my-index-000001][0]",
        "_node" : "Dw_g-_NuTAa4hh_BBwpZ1g",
        "_index" : "my-index-000001",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "标题1"
        },
        "_explanation" : {
          "value" : 0.36464313,
          "description" : "sum of:",
          "details" : [
            {
              "value" : 0.18232156,
              "description" : "weight(title:标 in 0) [PerFieldSimilarity], result of:",
              "details" : [
                {
                  "value" : 0.18232156,
                  "description" : "score(freq=1.0), computed as boost * idf * tf from:",
                  "details" : [
                    {
                      "value" : 2.2,
                      "description" : "boost",
                      "details" : [ ]
                    },
                    {
                      "value" : 0.18232156,
                      "description" : "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                      "details" : [
                        {
                          "value" : 2,
                          "description" : "n, number of documents containing term",
                          "details" : [ ]
                        },
                        {
                          "value" : 2,
                          "description" : "N, total number of documents with field",
                          "details" : [ ]
                        }
                      ]
                    },
                    {
                      "value" : 0.45454544,
                      "description" : "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                      "details" : [
                        {
                          "value" : 1.0,
                          "description" : "freq, occurrences of term within document",
                          "details" : [ ]
                        },
                        {
                          "value" : 1.2,
                          "description" : "k1, term saturation parameter",
                          "details" : [ ]
                        },
                        {
                          "value" : 0.75,
                          "description" : "b, length normalization parameter",
                          "details" : [ ]
                        },
                        {
                          "value" : 3.0,
                          "description" : "dl, length of field",
                          "details" : [ ]
                        },
                        {
                          "value" : 3.0,
                          "description" : "avgdl, average length of field",
                          "details" : [ ]
                        }
                      ]
                    }
                  ]
                }
              ]
            },
            {
              "value" : 0.18232156,
              "description" : "weight(title:题 in 0) [PerFieldSimilarity], result of:",
              "details" : [
                {
                  "value" : 0.18232156,
                  "description" : "score(freq=1.0), computed as boost * idf * tf from:",
                  "details" : [
                    {
                      "value" : 2.2,
                      "description" : "boost",
                      "details" : [ ]
                    },
                    {
                      "value" : 0.18232156,
                      "description" : "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                      "details" : [
                        {
                          "value" : 2,
                          "description" : "n, number of documents containing term",
                          "details" : [ ]
                        },
                        {
                          "value" : 2,
                          "description" : "N, total number of documents with field",
                          "details" : [ ]
                        }
                      ]
                    },
                    {
                      "value" : 0.45454544,
                      "description" : "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                      "details" : [
                        {
                          "value" : 1.0,
                          "description" : "freq, occurrences of term within document",
                          "details" : [ ]
                        },
                        {
                          "value" : 1.2,
                          "description" : "k1, term saturation parameter",
                          "details" : [ ]
                        },
                        {
                          "value" : 0.75,
                          "description" : "b, length normalization parameter",
                          "details" : [ ]
                        },
                        {
                          "value" : 3.0,
                          "description" : "dl, length of field",
                          "details" : [ ]
                        },
                        {
                          "value" : 3.0,
                          "description" : "avgdl, average length of field",
                          "details" : [ ]
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      },
      {
        "_shard" : "[my-index-000001][0]",
        "_node" : "Dw_g-_NuTAa4hh_BBwpZ1g",
        "_index" : "my-index-000001",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "标题2"
        },
        "_explanation" : {
          "value" : 0.36464313,
          "description" : "sum of:",
          "details" : [
            {
              "value" : 0.18232156,
              "description" : "weight(title:标 in 1) [PerFieldSimilarity], result of:",
              "details" : [
                {
                  "value" : 0.18232156,
                  "description" : "score(freq=1.0), computed as boost * idf * tf from:",
                  "details" : [
                    {
                      "value" : 2.2,
                      "description" : "boost",
                      "details" : [ ]
                    },
                    {
                      "value" : 0.18232156,
                      "description" : "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                      "details" : [
                        {
                          "value" : 2,
                          "description" : "n, number of documents containing term",
                          "details" : [ ]
                        },
                        {
                          "value" : 2,
                          "description" : "N, total number of documents with field",
                          "details" : [ ]
                        }
                      ]
                    },
                    {
                      "value" : 0.45454544,
                      "description" : "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                      "details" : [
                        {
                          "value" : 1.0,
                          "description" : "freq, occurrences of term within document",
                          "details" : [ ]
                        },
                        {
                          "value" : 1.2,
                          "description" : "k1, term saturation parameter",
                          "details" : [ ]
                        },
                        {
                          "value" : 0.75,
                          "description" : "b, length normalization parameter",
                          "details" : [ ]
                        },
                        {
                          "value" : 3.0,
                          "description" : "dl, length of field",
                          "details" : [ ]
                        },
                        {
                          "value" : 3.0,
                          "description" : "avgdl, average length of field",
                          "details" : [ ]
                        }
                      ]
                    }
                  ]
                }
              ]
            },
            {
              "value" : 0.18232156,
              "description" : "weight(title:题 in 1) [PerFieldSimilarity], result of:",
              "details" : [
                {
                  "value" : 0.18232156,
                  "description" : "score(freq=1.0), computed as boost * idf * tf from:",
                  "details" : [
                    {
                      "value" : 2.2,
                      "description" : "boost",
                      "details" : [ ]
                    },
                    {
                      "value" : 0.18232156,
                      "description" : "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                      "details" : [
                        {
                          "value" : 2,
                          "description" : "n, number of documents containing term",
                          "details" : [ ]
                        },
                        {
                          "value" : 2,
                          "description" : "N, total number of documents with field",
                          "details" : [ ]
                        }
                      ]
                    },
                    {
                      "value" : 0.45454544,
                      "description" : "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                      "details" : [
                        {
                          "value" : 1.0,
                          "description" : "freq, occurrences of term within document",
                          "details" : [ ]
                        },
                        {
                          "value" : 1.2,
                          "description" : "k1, term saturation parameter",
                          "details" : [ ]
                        },
                        {
                          "value" : 0.75,
                          "description" : "b, length normalization parameter",
                          "details" : [ ]
                        },
                        {
                          "value" : 3.0,
                          "description" : "dl, length of field",
                          "details" : [ ]
                        },
                        {
                          "value" : 3.0,
                          "description" : "avgdl, average length of field",
                          "details" : [ ]
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# Using the profile parameter

运行模板时,可以使用配置文件参数:

GET my-index-000001/_search/template
{
  "id": "templateid_1", 
  "params": {
    "query_string": "标题"
  },
  "profile": true
}
1
2
3
4
5
6
7
8
{
  "took" : 15,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.36464313,
    "hits" : [
      {
        "_index" : "my-index-000001",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "标题1"
        }
      },
      {
        "_index" : "my-index-000001",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.36464313,
        "_source" : {
          "title" : "标题2"
        }
      }
    ]
  },
  "profile" : {
    "shards" : [
      {
        "id" : "[Dw_g-_NuTAa4hh_BBwpZ1g][my-index-000001][0]",
        "searches" : [
          {
            "query" : [
              {
                "type" : "BooleanQuery",
                "description" : "title:标 title:题",
                "time_in_nanos" : 1896800,
                "breakdown" : {
                  "set_min_competitive_score_count" : 0,
                  "match_count" : 2,
                  "shallow_advance_count" : 0,
                  "set_min_competitive_score" : 0,
                  "next_doc" : 8600,
                  "match" : 2400,
                  "next_doc_count" : 2,
                  "score_count" : 2,
                  "compute_max_score_count" : 0,
                  "compute_max_score" : 0,
                  "advance" : 46200,
                  "advance_count" : 1,
                  "score" : 11300,
                  "build_scorer_count" : 4,
                  "create_weight" : 613300,
                  "shallow_advance" : 0,
                  "create_weight_count" : 1,
                  "build_scorer" : 1215000
                },
                "children" : [
                  {
                    "type" : "TermQuery",
                    "description" : "title:标",
                    "time_in_nanos" : 275200,
                    "breakdown" : {
                      "set_min_competitive_score_count" : 0,
                      "match_count" : 0,
                      "shallow_advance_count" : 3,
                      "set_min_competitive_score" : 0,
                      "next_doc" : 0,
                      "match" : 0,
                      "next_doc_count" : 0,
                      "score_count" : 2,
                      "compute_max_score_count" : 3,
                      "compute_max_score" : 33400,
                      "advance" : 2000,
                      "advance_count" : 3,
                      "score" : 6800,
                      "build_scorer_count" : 5,
                      "create_weight" : 126700,
                      "shallow_advance" : 9500,
                      "create_weight_count" : 1,
                      "build_scorer" : 96800
                    }
                  },
                  {
                    "type" : "TermQuery",
                    "description" : "title:题",
                    "time_in_nanos" : 82500,
                    "breakdown" : {
                      "set_min_competitive_score_count" : 0,
                      "match_count" : 0,
                      "shallow_advance_count" : 3,
                      "set_min_competitive_score" : 0,
                      "next_doc" : 0,
                      "match" : 0,
                      "next_doc_count" : 0,
                      "score_count" : 2,
                      "compute_max_score_count" : 3,
                      "compute_max_score" : 4500,
                      "advance" : 6800,
                      "advance_count" : 3,
                      "score" : 900,
                      "build_scorer_count" : 5,
                      "create_weight" : 39500,
                      "shallow_advance" : 1200,
                      "create_weight_count" : 1,
                      "build_scorer" : 29600
                    }
                  }
                ]
              }
            ],
            "rewrite_time" : 24200,
            "collector" : [
              {
                "name" : "SimpleTopScoreDocCollector",
                "reason" : "search_top_hits",
                "time_in_nanos" : 46300
              }
            ]
          }
        ],
        "aggregations" : [ ]
      }
    ]
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137