从搜索中检索选定字段
编辑从搜索中检索选定字段编辑
默认情况下,搜索响应中的每个命中项都包含文档 _source
,它是索引文档时提供的整个 JSON 对象。有两种推荐的方法可以从搜索查询中检索选定字段
- 使用
fields
选项 来提取索引映射中存在的字段的值 - 使用
_source
选项,如果您需要访问索引时传递的原始数据
您可以同时使用这两种方法,但 fields
选项更可取,因为它会同时查询文档数据和索引映射。在某些情况下,您可能希望使用 其他方法 来检索数据。
fields
选项编辑
要检索搜索响应中的特定字段,请使用 fields
参数。由于它会查询索引映射,因此 fields
参数比直接引用 _source
提供了几个优势。具体来说,fields
参数
其他映射选项也会被尊重,包括 ignore_above
、ignore_malformed
和 null_value
。
fields
选项以与 Elasticsearch 索引它们的方式匹配的方式返回值。对于标准字段,这意味着 fields
选项会在 _source
中查找值,然后使用映射解析和格式化它们。在 _source
中找不到的选定字段将被跳过。
检索特定字段编辑
以下搜索请求使用 fields
参数来检索 user.id
字段的值、所有以 http.response.
开头的字段以及 @timestamp
字段。
使用对象表示法,您可以传递 format
参数来自定义返回的日期或地理空间值的格式。
response = client.search( index: 'my-index-000001', body: { query: { match: { 'user.id' => 'kimchy' } }, fields: [ 'user.id', 'http.response.*', { field: '@timestamp', format: 'epoch_millis' } ], _source: false } ) puts response
POST my-index-000001/_search { "query": { "match": { "user.id": "kimchy" } }, "fields": [ "user.id", "http.response.*", { "field": "@timestamp", "format": "epoch_millis" } ], "_source": false }
默认情况下,当请求的 fields
选项使用通配符模式(如 *
)时,不会返回文档元数据字段(如 _id
或 _index
)。但是,当使用字段名称显式请求时,可以检索 _id
、_routing
、_ignored
、_index
和 _version
元数据字段。
响应始终返回数组编辑
fields
响应始终为每个字段返回一个值数组,即使 _source
中只有一个值。这是因为 Elasticsearch 没有专门的数组类型,任何字段都可能包含多个值。fields
参数也不保证数组值以特定顺序返回。有关更多背景信息,请参阅有关 数组 的映射文档。
响应在每个命中的 fields
部分中包含值作为扁平列表。由于 fields
参数不会获取整个对象,因此只返回叶子字段。
{ "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "my-index-000001", "_id" : "0", "_score" : 1.0, "fields" : { "user.id" : [ "kimchy" ], "@timestamp" : [ "4098435132000" ], "http.response.bytes": [ 1070000 ], "http.response.status_code": [ 200 ] } } ] } }
检索嵌套字段编辑
详细信息
对于 nested
字段,fields
响应与常规对象字段略有不同。虽然常规 object
字段内的叶子值作为扁平列表返回,但 nested
字段内的值将被分组以保持原始嵌套数组中每个对象的独立性。对于嵌套字段数组中的每个条目,值将再次作为扁平列表返回,除非父嵌套对象中还有其他 nested
字段,在这种情况下,将对更深层的嵌套字段重复相同的过程。
给定以下映射,其中 user
是一个嵌套字段,在索引以下文档并检索 user
字段下的所有字段后
response = client.indices.create( index: 'my-index-000001', body: { mappings: { properties: { group: { type: 'keyword' }, user: { type: 'nested', properties: { first: { type: 'keyword' }, last: { type: 'keyword' } } } } } } ) puts response response = client.index( index: 'my-index-000001', id: 1, refresh: true, body: { group: 'fans', user: [ { first: 'John', last: 'Smith' }, { first: 'Alice', last: 'White' } ] } ) puts response response = client.search( index: 'my-index-000001', body: { fields: [ '*' ], _source: false } ) puts response
PUT my-index-000001 { "mappings": { "properties": { "group" : { "type" : "keyword" }, "user": { "type": "nested", "properties": { "first" : { "type" : "keyword" }, "last" : { "type" : "keyword" } } } } } } PUT my-index-000001/_doc/1?refresh=true { "group" : "fans", "user" : [ { "first" : "John", "last" : "Smith" }, { "first" : "Alice", "last" : "White" } ] } POST my-index-000001/_search { "fields": ["*"], "_source": false }
响应将对 first
和 last
名称进行分组,而不是将它们作为扁平列表返回。
{ "took": 2, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1.0, "hits": [{ "_index": "my-index-000001", "_id": "1", "_score": 1.0, "fields": { "group" : ["fans"], "user": [{ "first": ["John"], "last": ["Smith"] }, { "first": ["Alice"], "last": ["White"] } ] } }] } }
嵌套字段将按其嵌套路径进行分组,无论用于检索它们的模式如何。例如,如果您只查询上一个示例中的 user.first
字段
response = client.search( index: 'my-index-000001', body: { fields: [ 'user.first' ], _source: false } ) puts response
POST my-index-000001/_search { "fields": ["user.first"], "_source": false }
响应只返回用户的第一个名字,但仍然保留嵌套 user
数组的结构
{ "took": 2, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1.0, "hits": [{ "_index": "my-index-000001", "_id": "1", "_score": 1.0, "fields": { "user": [{ "first": ["John"] }, { "first": ["Alice"] } ] } }] } }
但是,当 fields
模式直接针对嵌套的 user
字段时,将不会返回任何值,因为该模式与任何叶子字段都不匹配。
检索未映射的字段编辑
详细信息
默认情况下,fields
参数只返回映射字段的值。但是,Elasticsearch 允许在 _source
中存储未映射的字段,例如将 动态字段映射 设置为 false
或使用具有 enabled: false
的对象字段。这些选项会禁用对对象内容的解析和索引。
要从 _source
中检索对象中的未映射字段,请在 fields
部分中使用 include_unmapped
选项
response = client.indices.create( index: 'my-index-000001', body: { mappings: { enabled: false } } ) puts response response = client.index( index: 'my-index-000001', id: 1, refresh: true, body: { user_id: 'kimchy', session_data: { object: { some_field: 'some_value' } } } ) puts response response = client.search( index: 'my-index-000001', body: { fields: [ 'user_id', { field: 'session_data.object.*', include_unmapped: true } ], _source: false } ) puts response
PUT my-index-000001 { "mappings": { "enabled": false } } PUT my-index-000001/_doc/1?refresh=true { "user_id": "kimchy", "session_data": { "object": { "some_field": "some_value" } } } POST my-index-000001/_search { "fields": [ "user_id", { "field": "session_data.object.*", "include_unmapped" : true } ], "_source": false }
响应将在 session_data.object.*
路径下包含字段结果,即使字段未映射。user_id
字段也未映射,但它不会包含在响应中,因为 include_unmapped
未设置为该字段模式的 true
。
{ "took" : 2, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "my-index-000001", "_id" : "1", "_score" : 1.0, "fields" : { "session_data.object.some_field": [ "some_value" ] } } ] } }
忽略的字段值编辑
详细信息
响应的 fields
部分只返回索引时有效的字段值。如果您的搜索请求要求从一个字段中获取某些值,而这些值由于格式错误或太大而被忽略,那么这些值将分别在 ignored_field_values
部分中返回。
在此示例中,我们索引了一个文档,该文档包含一个被忽略且未添加到索引中的值,因此它在搜索结果中单独显示
response = client.indices.create( index: 'my-index-000001', body: { mappings: { properties: { "my-small": { type: 'keyword', ignore_above: 2 }, "my-large": { type: 'keyword' } } } } ) puts response response = client.index( index: 'my-index-000001', id: 1, refresh: true, body: { "my-small": [ 'ok', 'bad' ], "my-large": 'ok content' } ) puts response response = client.search( index: 'my-index-000001', body: { fields: [ 'my-*' ], _source: false } ) puts response
PUT my-index-000001 { "mappings": { "properties": { "my-small" : { "type" : "keyword", "ignore_above": 2 }, "my-large" : { "type" : "keyword" } } } } PUT my-index-000001/_doc/1?refresh=true { "my-small": ["ok", "bad"], "my-large": "ok content" } POST my-index-000001/_search { "fields": ["my-*"], "_source": false }
响应将在 ignored_field_values
路径下包含忽略的字段值。这些值是从文档的原始 JSON 源中检索的,并且是原始的,因此不会以任何方式进行格式化或处理,这与在 fields
部分中返回的成功索引的字段不同。
{ "took" : 2, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "my-index-000001", "_id" : "1", "_score" : 1.0, "_ignored" : [ "my-small"], "fields" : { "my-large": [ "ok content" ], "my-small": [ "ok" ] }, "ignored_field_values" : { "my-small": [ "bad" ] } } ] } }
_source
选项编辑
您可以使用 _source
参数来选择返回源的哪些字段。这称为源过滤。
以下搜索 API 请求将 _source
请求体参数设置为 false
。文档源不包含在响应中。
response = client.search( body: { _source: false, query: { match: { 'user.id' => 'kimchy' } } } ) puts response
GET /_search { "_source": false, "query": { "match": { "user.id": "kimchy" } } }
要只返回源字段的子集,请在 _source
参数中指定通配符 (*
) 模式。以下搜索 API 请求只返回 obj
字段及其属性的源。
response = client.search( body: { _source: 'obj.*', query: { match: { 'user.id' => 'kimchy' } } } ) puts response
GET /_search { "_source": "obj.*", "query": { "match": { "user.id": "kimchy" } } }
您也可以在 _source
字段中指定通配符模式的数组。以下搜索 API 请求只返回 obj1
和 obj2
字段及其属性的源。
response = client.search( body: { _source: [ 'obj1.*', 'obj2.*' ], query: { match: { 'user.id' => 'kimchy' } } } ) puts response
GET /_search { "_source": [ "obj1.*", "obj2.*" ], "query": { "match": { "user.id": "kimchy" } } }
为了更精细地控制,您可以在 _source
参数中指定一个包含 includes
和 excludes
模式数组的对象。
如果指定了 includes
属性,则只返回与其中一个模式匹配的源字段。您可以使用 excludes
属性从该子集中排除字段。
如果未指定 includes
属性,则返回整个文档源,排除与 excludes
属性中的模式匹配的任何字段。
以下搜索 API 请求仅返回 obj1
和 obj2
字段及其属性的源,排除任何子 description
字段。
response = client.search( body: { _source: { includes: [ 'obj1.*', 'obj2.*' ], excludes: [ '*.description' ] }, query: { term: { 'user.id' => 'kimchy' } } } ) puts response
GET /_search { "_source": { "includes": [ "obj1.*", "obj2.*" ], "excludes": [ "*.description" ] }, "query": { "term": { "user.id": "kimchy" } } }
其他检索数据的方法edit
文档的 _source
存储在 Lucene 中的单个字段中。这种结构意味着即使您只请求一部分,也必须加载和解析整个 _source
对象。为了避免此限制,您可以尝试其他加载字段的选项
- 使用
docvalue_fields
参数获取所选字段的值。当返回支持文档值的少量字段(例如关键字和日期)时,这可能是一个不错的选择。 - 使用
stored_fields
参数获取特定存储字段(使用store
映射选项的字段)的值。
Elasticsearch 始终尝试从 _source
加载值。这种行为与源过滤具有相同的含义,其中 Elasticsearch 需要加载和解析整个 _source
才能检索单个字段。
文档值字段edit
您可以使用 docvalue_fields
参数在搜索响应中返回一个或多个字段的 文档值。
文档值存储与 _source
相同的值,但存储在针对排序和聚合优化的磁盘上基于列的结构中。由于每个字段都是单独存储的,因此 Elasticsearch 只读取请求的字段值,并且可以避免加载整个文档 _source
。
默认情况下,会为支持的字段存储文档值。但是,不支持 text
或 text_annotated
字段的文档值。
以下搜索请求使用 docvalue_fields
参数检索 user.id
字段、所有以 http.response.
开头的字段以及 @timestamp
字段的文档值
response = client.search( index: 'my-index-000001', body: { query: { match: { 'user.id' => 'kimchy' } }, docvalue_fields: [ 'user.id', 'http.response.*', { field: 'date', format: 'epoch_millis' } ] } ) puts response
GET my-index-000001/_search { "query": { "match": { "user.id": "kimchy" } }, "docvalue_fields": [ "user.id", "http.response.*", { "field": "date", "format": "epoch_millis" } ] }
接受完整的字段名称和通配符模式。 |
|
使用对象表示法,您可以传递 |
您不能使用 docvalue_fields
参数检索嵌套对象的文档值。如果您指定嵌套对象,则搜索将为该字段返回一个空数组 ([ ]
)。要访问嵌套字段,请使用 inner_hits
参数的 docvalue_fields
属性。
存储字段edit
也可以通过使用 store
映射选项来存储单个字段的值。您可以使用 stored_fields
参数在搜索响应中包含这些存储的值。
stored_fields
参数适用于在映射中明确标记为存储的字段,默认情况下该参数处于关闭状态,通常不建议使用。请改用 源过滤 来选择要返回的原始源文档的子集。
允许为搜索命中所代表的每个文档选择性地加载特定的存储字段。
response = client.search( body: { stored_fields: [ 'user', 'postDate' ], query: { term: { user: 'kimchy' } } } ) puts response
GET /_search { "stored_fields" : ["user", "postDate"], "query" : { "term" : { "user" : "kimchy" } } }
*
可用于从文档中加载所有存储字段。
空数组将导致仅返回每个命中的 _id
和 _type
,例如
response = client.search( body: { stored_fields: [], query: { term: { user: 'kimchy' } } } ) puts response
GET /_search { "stored_fields" : [], "query" : { "term" : { "user" : "kimchy" } } }
如果请求的字段未存储(store
映射设置为 false
),则会忽略它们。
从文档本身获取的存储字段值始终作为数组返回。相反,_routing
等元数据字段永远不会作为数组返回。
此外,只有叶子字段可以通过 stored_fields
选项返回。如果指定了对象字段,则会忽略它。
stored_fields
本身不能用于加载嵌套对象中的字段——如果字段在其路径中包含嵌套对象,则不会返回该存储字段的任何数据。要访问嵌套字段,stored_fields
必须在 inner_hits
块中使用。
禁用存储字段edit
要完全禁用存储字段(和元数据字段),请使用:_none_
response = client.search( body: { stored_fields: '_none_', query: { term: { user: 'kimchy' } } } ) puts response
GET /_search { "stored_fields": "_none_", "query" : { "term" : { "user" : "kimchy" } } }
脚本字段edit
您可以使用 script_fields
参数检索每个命中的 脚本评估(基于不同的字段)。例如
response = client.search( body: { query: { match_all: {} }, script_fields: { "test1": { script: { lang: 'painless', source: "doc['price'].value * 2" } }, "test2": { script: { lang: 'painless', source: "doc['price'].value * params.factor", params: { factor: 2 } } } } } ) puts response
GET /_search { "query": { "match_all": {} }, "script_fields": { "test1": { "script": { "lang": "painless", "source": "doc['price'].value * 2" } }, "test2": { "script": { "lang": "painless", "source": "doc['price'].value * params.factor", "params": { "factor": 2.0 } } } } }
脚本字段可以在未存储的字段上工作(上面的示例中的 price
),并允许返回要返回的自定义值(脚本的评估值)。
脚本字段还可以访问实际的 _source
文档,并通过使用 params['_source']
从中提取要返回的特定元素。这是一个示例
response = client.search( body: { query: { match_all: {} }, script_fields: { "test1": { script: "params['_source']['message']" } } } ) puts response
GET /_search { "query": { "match_all": {} }, "script_fields": { "test1": { "script": "params['_source']['message']" } } }
请注意此处用于导航类似 json 的模型的 _source
关键字。
了解 doc['my_field'].value
和 params['_source']['my_field']
之间的区别非常重要。第一个使用 doc 关键字,将导致该字段的词条被加载到内存中(缓存),这将导致更快的执行速度,但内存消耗更多。此外,doc[...]
表示法只允许简单值字段(您无法从中返回 json 对象),并且仅对未分析或基于单个词条的字段有意义。但是,如果可能,使用 doc
仍然是访问文档中值的推荐方法,因为每次使用 _source
时都必须加载和解析它。使用 _source
非常慢。