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