访问文档字段和特殊变量
edit访问文档字段和特殊变量
edit根据脚本使用的位置,它将可以访问某些特殊变量和文档字段。
更新脚本
edit在更新、
按查询更新或重新索引
API中使用的脚本将可以访问ctx
变量,该变量暴露了:
|
访问文档的 |
|
应应用于文档的操作: |
|
访问文档元数据字段,其中一些可能是只读的。 |
这些脚本无法访问 doc
变量,必须使用 ctx
来访问它们所操作的文档。
搜索与聚合脚本
edit除了每次搜索命中执行一次的脚本字段之外,搜索和聚合中使用的脚本将为每个可能匹配查询或聚合的文档执行一次。根据您拥有的文档数量,这可能意味着数百万或数十亿次执行:这些脚本需要快速!
字段值可以通过脚本使用
doc-values、
文档的 _source
字段 或
存储字段 来访问,
下面将分别解释每种方式。
在脚本中访问文档的分数
edit在function_score
查询中使用的脚本,
在基于脚本的排序中,或在
聚合中,可以访问_score
变量,
该变量表示文档的当前相关性得分。
这是一个在
function_score
查询中使用脚本的示例,用于改变每个文档的相关性 _score
:
PUT my-index-000001/_doc/1?refresh { "text": "quick brown fox", "popularity": 1 } PUT my-index-000001/_doc/2?refresh { "text": "quick fox", "popularity": 5 } GET my-index-000001/_search { "query": { "function_score": { "query": { "match": { "text": "quick brown fox" } }, "script_score": { "script": { "lang": "expression", "source": "_score * doc['popularity']" } } } } }
文档值
edit到目前为止,从脚本中访问字段值最快、最有效的方法是使用 doc['field_name']
语法,该语法从 doc values 中检索字段值。Doc values 是一种列式字段值存储,默认情况下在除 分析的 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 只能返回“简单”字段值,如数字、日期、地理位置点、术语等,如果字段是多值的,则可以返回这些值的数组。它不能返回 JSON 对象。
缺失字段
如果映射中缺少field
,doc['field']
将抛出错误。
在painless
中,可以首先使用doc.containsKey('field')
进行检查,以保护对doc
映射的访问。不幸的是,在expression
脚本中无法检查映射中字段的存在。
Doc values 和 text
字段
对于启用了fielddata
的分析过的text
字段,也可以使用doc['field']
语法,但注意:在text
字段上启用fielddata需要将所有术语加载到JVM堆中,这在内存和CPU方面都可能非常昂贵。从脚本中访问text
字段通常没有意义。
文档 _source
edit可以使用_source.field_name
语法访问文档_source
。_source
被加载为一个映射的映射,因此对象字段中的属性可以像_source.name.first
这样访问。
优先使用doc-values而非_source
访问 _source
字段比使用 doc-values 要慢得多。_source 字段针对返回每个结果的多个字段进行了优化,而 doc-values 针对访问许多文档中特定字段的值进行了优化。
在从搜索结果中生成前十个命中的脚本字段时,使用_source
是有意义的,但对于其他搜索和聚合用例,始终优先使用文档值。
例如:
PUT my-index-000001 { "mappings": { "properties": { "first_name": { "type": "text" }, "last_name": { "type": "text" } } } } PUT my-index-000001/_doc/1?refresh { "first_name": "Barry", "last_name": "White" } GET my-index-000001/_search { "script_fields": { "full_name": { "script": { "lang": "painless", "source": "params._source.first_name + ' ' + params._source.last_name" } } } }
存储字段
edit存储字段 — 在映射中明确标记为
"store": true
的字段 — 可以使用
_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
The _source
字段只是一个特殊的存储字段,因此其性能与其他存储字段相似。The _source
提供了对索引时原始文档体的访问(包括区分 null
值与空字段、单值数组与普通标量等的能力)。
唯一真正有意义的使用存储字段而不是_source
字段的情况是,当_source
非常大,并且访问几个小的存储字段比访问整个_source
的成本更低。