本地英文版地址: ../en/modules-scripting-fields.html
根据脚本的使用场合,它可以访问某些特殊变量和文档字段。
更新(update)脚本
在更新(update)、按查询更新(update-by-query) 或 重新索引(reindex)中使用的脚本可以访问变量ctx
,该变量公开了以下属性:
搜索和聚合脚本
除了每个搜索命中执行一次的脚本字段(script fields)之外,搜索和聚合中使用的脚本将对每个可能匹配查询或聚合的文档执行一次。 取决于你有多少文档,这可能意味着数百万或数十亿次执行:这些脚本需要运行得很快!
可以使用文档值(doc-values)、 源(_source
)字段或存储的字段(stored fields)从脚本中访问字段值,下面会对他们进行一一说明。
在脚本内获取文档的得分
function_score
查询、基于脚本的排序或聚合中使用的脚本可以访问代表文档当前相关性分数的_score
变量。
下面是一个在function_score
查询中使用脚本来改变每个文档的相关性评分(_score
)的示例:
PUT my_index/_doc/1?refresh { "text": "quick brown fox", "popularity": 1 } PUT my_index/_doc/2?refresh { "text": "quick fox", "popularity": 5 } GET my_index/_search { "query": { "function_score": { "query": { "match": { "text": "quick brown fox" } }, "script_score": { "script": { "lang": "expression", "source": "_score * doc['popularity']" } } } } }
文档值(doc values)
到目前为止,从脚本中访问字段值最快最有效的方法是使用doc['field_name']
语法,该语法从文档值(doc values)中检索字段值。
文档值是按列式字段值存储的,默认情况下,除了analyzed text
字段(会被分析的字段)之外,所有字段都启用该存储方式。
PUT my_index/_doc/1?refresh { "cost_price": 100 } GET my_index/_search { "script_fields": { "sales_price": { "script": { "lang": "expression", "source": "doc['cost_price'] * markup", "params": { "markup": 0.2 } } } } }
文档值只能返回“简单”的字段值,如numbers、dates、geo-points、terms等,如果字段是多值的,则返回这些值的数组。它不能返回JSON对象。
缺失的字段
如果映射中缺少field
,doc['field']
将会引发错误。
在painless
下,可以首先使用doc.containsKey('field')
进行检查,以防止访问doc
的映射。
不幸的是,没有办法在expression
脚本中检查映射中是否存在该字段。
文档值和text
字段
如果启用了fielddata
,则doc['field']
语法也可以用于分析的(analyzed)text
字段,但是请注意:在text
字段上启用 fielddata 需要将所有的词项加载到JVM堆中,这在内存和CPU方面的开销都很大。
在脚本中访问text
字段没有什么意义。
文档的源(_source
)
可以使用_source.field_name
语法访问文档的源(_source
)。
_source
作为映射的映射加载,因此对象字段中的属性可以像_source.name.first
这样来访问。
首选文档值(doc-values)而非_source
访问_source
字段比使用文档值(doc-values)要慢得多。
_source
字段针对每个结果返回几个字段进行了优化,而文档值(doc values)针对访问许多文档中特定字段的值进行了优化。
当从搜索结果中为前10个命中生成脚本字段(script field)时,使用_source
是有意义的,但是对于其他搜索和聚合用例,总是首选使用文档值(doc values)。
例如:
PUT my_index { "mappings": { "properties": { "first_name": { "type": "text" }, "last_name": { "type": "text" } } } } PUT my_index/_doc/1?refresh { "first_name": "Barry", "last_name": "White" } GET my_index/_search { "script_fields": { "full_name": { "script": { "lang": "painless", "source": "params._source.first_name + ' ' + params._source.last_name" } } } }
存储的字段(stored fields)
存储字段(Stored fields)-在映射中明确标记为"store": true
的字段-可以使用_fields['field_name'].value
或_fields['field_name']
语法进行访问:
PUT my_index { "mappings": { "properties": { "full_name": { "type": "text", "store": true }, "title": { "type": "text", "store": true } } } } PUT my_index/_doc/1?refresh { "full_name": "Alice Ball", "title": "Professor" } GET my_index/_search { "script_fields": { "name_with_title": { "script": { "lang": "painless", "source": "params._fields['title'].value + ' ' + params._fields['full_name'].value" } } } }
存储的(stored)与源(_source
)
_source
字段只是一个特殊的存储的字段,所以性能和其他存储字段差不多。
_source
提供了对被索引的原始文档主体的访问(包括区分null
值与空字段、单值数组与普通标量等的能力)。
只有当_source
非常大,并且访问一些小的存储字段比访问整个_source
成本更低时,使用存储字段而不是_source
字段才有意义。