1. 给脚本传参
GET my-index-000001/_search
{
"script_fields": {
"my_doubled_field": {
"script": {
"source": "doc['my_field'].value * params['multiplier']",
"params": {
"multiplier": 2
} } } } }
2. 访问文档字段和指定变量
根据脚本使用的环境,访问的变量和文档字段也不同
2.1 更新脚本
用于 update, update-by-query, 或 reindex API 的脚本可以访问 ctx 暴露的变量:
ctx._source
:访问文档的_source
字段ctx.op
:应用于文档的操作,index
或delete
ctx._index
等:访问文档元数据字段,某些可能为只读字段
2.2 检索与聚合脚本
脚本可以使用doc-values, the _source field, or stored fields来访问字段值
2.2.1 在脚本中访问文档的分数
在 [function_score query](https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-function-score-query.html)
, script-based sorting, 或 aggregations 中使用脚本可以访问 _score
变量,表示文档的相关度分数
例如在 [function_score query](https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-function-score-query.html)
中修改每个文档的 _score:
PUT my-index-000001/_doc/1?refresh
{
"text": "quick brown fox",
"popularity": 1
}
GET my-index-000001/_search
{
"query": {
"function_score": {
"query": {
"match": {
"text": "quick brown fox"
}
},
"script_score": {
"script": {
"lang": "expression",
"source": "_score * doc['popularity']"
} } } } }
2.2.2 Doc 取值
语法:doc['field_name']
Doc 值是一个列式(columnar)字段值存储,除了 analyzed text字段,默认在全部字段开启。
PUT my-index-000001/_doc/1?refresh
{
"cost_price": 100
}
GET my-index-000001/_search
{
"script_fields": {
"sales_price": {
"script": {
"lang": "expression",
"source": "doc['cost_price'] * markup",
"params": {
"markup": 0.2
} } } } }
Doc-values 只返回简单的字段值,如数字、日期、地理坐标、terms等等,或者这些值的列表。不能返回 json 对象。
缺失字段验证
在
painless
脚本语法中,在访问doc
map 前,会首先检查doc.containsKey('field')
,但在expression
脚本中,没法检查字段在映射中的存在。如果字段不存在于 mapping 中,则 doc['field'] 会抛出错误
Doc 值与 text 字段
在设置了
[fielddata](https://www.elastic.co/guide/en/elasticsearch/reference/7.17/fielddata.html)
的 text 字段上,也可以用 doc['field'] 语法取值,但是要注意:设置了 fielddata 的text 字段需要加载所有的 terms 到 JVM 堆中,这回非常消耗内存和 CPU。很少用脚本来访问 text 字段
2.2.3 访问文档 _source
语法:_source.field_name
_source
会加载为一个映射
优先选择使用 doc-values
访问 _source 字段比 doc-values 方式更慢。_source 字段对每个结果返回多个字段进行了优化,而 doc values 对访问许多文档的指定字段进行了优化
类似从检索结果的前十个 hit 中生成一个 script field可以使用 _source,但对于其他检索、聚合的用例,一般选 doc values 更好
GET my-index-000001/_search
{
"script_fields": {
"full_name": {
"script": {
"lang": "painless",
"source": "params._source.first_name + ' ' + params._source.last_name"
} } } }
2.2.4 存储字段取值
在映射中被标记为 "store": true
的字段成为存储字段(Stroed fields),这种字段可以使用 _fields['field_name'].value
或 _fields['field_name']
语法来访问
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"
} } } }
存储字段 vs _source
_source 字段是特殊的存储字段,因此性能上与其他存储字段接近。 _source 提供到源文档体的访问
只有在 _source 非常大,并且访问一些小的存储字段消耗比整个 _source 小的情况下,才使用存储字段
3. Painless 语言
详见 https://www.elastic.co/guide/en/elasticsearch/reference/7.17/modules-scripting-painless.html
4. Lucene 表达式语言
Lucene 表达式将 javascript 表达式编译成字节码。用于专用的高性能排列排序功能,在 inline
和 stored
脚本中默认启用。其性能是优于手写本地脚本的。
4.1 语法
运算符以及函数参见:expressions module documentation
- Integer, floating point, hex and octal literals
- 算数运算符:
+ - * / %
- 位运算符:
| & ^ ~ << >> >>>
- 布尔运算符 (包含三元运算符):
&& || ! ?:
- 比较运算符:
< <= == >= >
- 常用数学函数:
abs ceil exp floor ln log10 logn max min sqrt pow
- 三角函数库函数:
acosh acos asinh asin atanh atan atan2 cosh cos sinh sin tanh tan
- 距离运算函数:
haversin
- 其他函数:
min, max
- Arbitrary external variables - see
[Bindings](https://lucene.apache.org/core/8_11_1/expressions/org/apache/lucene/expressions/Bindings.html)
expression
脚本可访问的变量有:
文档字段:e.g.
doc['myfield'].value
字段支持的变量和方法:e.g.
doc['myfield'].empty
传入脚本的参数:e.g.
mymodifier
当前的文档分数,
_score
(在script_score
中有效)
表达式脚本可用在script_score
, script_fields
, 排序脚本, 以及数字聚合脚本,需要设置 lang
参数为 expression
4.2 数字字段 API
如果字段缺失,会按照默认值0来计算,也可以使用:
doc['myfield'].empty ? 100 : doc['myfield'].value
当字段是多值的时候,默认返回最小的值,可以选择别的值:
doc['myfield'].sum()
.布尔值字段暴率为数字,
true
映射为1
,false
映射为0
.例如:doc['on_sale'].value ? doc['price'].value * 0.5 : doc['price'].value
4.3 日期字段 API
日期字段被当作自 1970年1月1日开始的毫秒数字,支持上述的数字字段API,还有些其他的日期专用的API:
例如计算日期字段的年差:doc['date1'].date.year - doc['date0'].date.year
4.4 geo_point
字段 API
例如计算从Washington,DC 到此地的直线距离(km):
haversin(38.9072, 77.0369, doc['field_name'].lat, doc['field_name'].lon)
这个例子中,坐标可以替换成参数传给script,例如用户的坐标
4.5 限制
仅支持访问数字、布尔值、日期和地理坐标点字段
不支持存储字段
5. 使用脚本引擎的高级脚本
ScriptEngine
可以作为插件自己编写,如何写插件参见 plugin documentation