从搜索中检索选定字段
编辑从搜索中检索选定字段
编辑默认情况下,搜索响应中的每个命中都包含文档的 _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
参数来自定义返回的日期或地理空间值的格式。
resp = client.search( index="my-index-000001", query={ "match": { "user.id": "kimchy" } }, fields=[ "user.id", "http.response.*", { "field": "@timestamp", "format": "epoch_millis" } ], source=False, ) print(resp)
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
const response = await client.search({ index: "my-index-000001", query: { match: { "user.id": "kimchy", }, }, fields: [ "user.id", "http.response.*", { field: "@timestamp", format: "epoch_millis", }, ], _source: false, }); console.log(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
字段下的所有字段之后
resp = client.indices.create( index="my-index-000001", mappings={ "properties": { "group": { "type": "keyword" }, "user": { "type": "nested", "properties": { "first": { "type": "keyword" }, "last": { "type": "keyword" } } } } }, ) print(resp) resp1 = client.index( index="my-index-000001", id="1", refresh=True, document={ "group": "fans", "user": [ { "first": "John", "last": "Smith" }, { "first": "Alice", "last": "White" } ] }, ) print(resp1) resp2 = client.search( index="my-index-000001", fields=[ "*" ], source=False, ) print(resp2)
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
const response = await client.indices.create({ index: "my-index-000001", mappings: { properties: { group: { type: "keyword", }, user: { type: "nested", properties: { first: { type: "keyword", }, last: { type: "keyword", }, }, }, }, }, }); console.log(response); const response1 = await client.index({ index: "my-index-000001", id: 1, refresh: "true", document: { group: "fans", user: [ { first: "John", last: "Smith", }, { first: "Alice", last: "White", }, ], }, }); console.log(response1); const response2 = await client.search({ index: "my-index-000001", fields: ["*"], _source: false, }); console.log(response2);
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
字段
resp = client.search( index="my-index-000001", fields=[ "user.first" ], source=False, ) print(resp)
response = client.search( index: 'my-index-000001', body: { fields: [ 'user.first' ], _source: false } ) puts response
const response = await client.search({ index: "my-index-000001", fields: ["user.first"], _source: false, }); console.log(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
选项
resp = client.indices.create( index="my-index-000001", mappings={ "enabled": False }, ) print(resp) resp1 = client.index( index="my-index-000001", id="1", refresh=True, document={ "user_id": "kimchy", "session_data": { "object": { "some_field": "some_value" } } }, ) print(resp1) resp2 = client.search( index="my-index-000001", fields=[ "user_id", { "field": "session_data.object.*", "include_unmapped": True } ], source=False, ) print(resp2)
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
const response = await client.indices.create({ index: "my-index-000001", mappings: { enabled: false, }, }); console.log(response); const response1 = await client.index({ index: "my-index-000001", id: 1, refresh: "true", document: { user_id: "kimchy", session_data: { object: { some_field: "some_value", }, }, }, }); console.log(response1); const response2 = await client.search({ index: "my-index-000001", fields: [ "user_id", { field: "session_data.object.*", include_unmapped: true, }, ], _source: false, }); console.log(response2);
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
部分中返回。
在此示例中,我们索引一个具有被忽略的值的文档,该值未添加到索引中,因此在搜索结果中单独显示
resp = client.indices.create( index="my-index-000001", mappings={ "properties": { "my-small": { "type": "keyword", "ignore_above": 2 }, "my-large": { "type": "keyword" } } }, ) print(resp) resp1 = client.index( index="my-index-000001", id="1", refresh=True, document={ "my-small": [ "ok", "bad" ], "my-large": "ok content" }, ) print(resp1) resp2 = client.search( index="my-index-000001", fields=[ "my-*" ], source=False, ) print(resp2)
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
const response = await client.indices.create({ index: "my-index-000001", mappings: { properties: { "my-small": { type: "keyword", ignore_above: 2, }, "my-large": { type: "keyword", }, }, }, }); console.log(response); const response1 = await client.index({ index: "my-index-000001", id: 1, refresh: "true", document: { "my-small": ["ok", "bad"], "my-large": "ok content", }, }); console.log(response1); const response2 = await client.search({ index: "my-index-000001", fields: ["my-*"], _source: false, }); console.log(response2);
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
。文档源未包含在响应中。
resp = client.search( source=False, query={ "match": { "user.id": "kimchy" } }, ) print(resp)
response = client.search( body: { _source: false, query: { match: { 'user.id' => 'kimchy' } } } ) puts response
const response = await client.search({ _source: false, query: { match: { "user.id": "kimchy", }, }, }); console.log(response);
GET /_search { "_source": false, "query": { "match": { "user.id": "kimchy" } } }
要仅返回源字段的子集,请在 _source
参数中指定通配符 (*
) 模式。以下搜索 API 请求仅返回 obj
字段及其属性的源。
resp = client.search( source="obj.*", query={ "match": { "user.id": "kimchy" } }, ) print(resp)
response = client.search( body: { _source: 'obj.*', query: { match: { 'user.id' => 'kimchy' } } } ) puts response
const response = await client.search({ _source: "obj.*", query: { match: { "user.id": "kimchy", }, }, }); console.log(response);
GET /_search { "_source": "obj.*", "query": { "match": { "user.id": "kimchy" } } }
您还可以在 _source
字段中指定通配符模式的数组。以下搜索 API 请求仅返回 obj1
和 obj2
字段及其属性的源。
resp = client.search( source=[ "obj1.*", "obj2.*" ], query={ "match": { "user.id": "kimchy" } }, ) print(resp)
response = client.search( body: { _source: [ 'obj1.*', 'obj2.*' ], query: { match: { 'user.id' => 'kimchy' } } } ) puts response
const response = await client.search({ _source: ["obj1.*", "obj2.*"], query: { match: { "user.id": "kimchy", }, }, }); console.log(response);
GET /_search { "_source": [ "obj1.*", "obj2.*" ], "query": { "match": { "user.id": "kimchy" } } }
为了更好地控制,您可以在 _source
参数中指定一个包含 includes
和 excludes
模式数组的对象。
如果指定了 includes
属性,则仅返回与其中一个模式匹配的源字段。您可以使用 excludes
属性从该子集中排除字段。
如果未指定 includes
属性,则返回整个文档源,排除与 excludes
属性中的模式匹配的任何字段。
以下搜索 API 请求仅返回 obj1
和 obj2
字段及其属性的源,排除任何子 description
字段。
resp = client.search( source={ "includes": [ "obj1.*", "obj2.*" ], "excludes": [ "*.description" ] }, query={ "term": { "user.id": "kimchy" } }, ) print(resp)
response = client.search( body: { _source: { includes: [ 'obj1.*', 'obj2.*' ], excludes: [ '*.description' ] }, query: { term: { 'user.id' => 'kimchy' } } } ) puts response
const response = await client.search({ _source: { includes: ["obj1.*", "obj2.*"], excludes: ["*.description"], }, query: { term: { "user.id": "kimchy", }, }, }); console.log(response);
GET /_search { "_source": { "includes": [ "obj1.*", "obj2.*" ], "excludes": [ "*.description" ] }, "query": { "term": { "user.id": "kimchy" } } }
检索数据的其他方法
编辑一个文档的 _source
在 Lucene 中存储为单个字段。这种结构意味着即使您只请求其中的一部分,也必须加载和解析整个 _source
对象。为了避免这种限制,您可以尝试其他加载字段的选项。
- 使用
docvalue_fields
参数来获取所选字段的值。当返回少量支持 doc values 的字段(例如关键字和日期)时,这可能是一个不错的选择。 - 使用
stored_fields
参数来获取特定存储字段的值(使用store
映射选项的字段)。
Elasticsearch 始终尝试从 _source
加载值。此行为与源过滤具有相同的含义,即 Elasticsearch 需要加载和解析整个 _source
才能仅检索一个字段。
Doc value 字段
编辑您可以使用 docvalue_fields
参数在搜索响应中返回一个或多个字段的 doc values。
Doc values 存储与 _source
相同的值,但存储在基于磁盘的、面向列的结构中,该结构针对排序和聚合进行了优化。由于每个字段都是单独存储的,因此 Elasticsearch 只读取请求的字段值,并且可以避免加载整个文档的 _source
。
默认情况下,为受支持的字段存储 Doc values。但是,text
或 text_annotated
字段不支持 doc values。
以下搜索请求使用 docvalue_fields
参数检索 user.id
字段、所有以 http.response.
开头的字段以及 @timestamp
字段的 doc values
resp = client.search( index="my-index-000001", query={ "match": { "user.id": "kimchy" } }, docvalue_fields=[ "user.id", "http.response.*", { "field": "date", "format": "epoch_millis" } ], ) print(resp)
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
const response = await client.search({ index: "my-index-000001", query: { match: { "user.id": "kimchy", }, }, docvalue_fields: [ "user.id", "http.response.*", { field: "date", format: "epoch_millis", }, ], }); console.log(response);
GET my-index-000001/_search { "query": { "match": { "user.id": "kimchy" } }, "docvalue_fields": [ "user.id", "http.response.*", { "field": "date", "format": "epoch_millis" } ] }
接受完整字段名称和通配符模式。 |
|
使用对象表示法,您可以传递 |
您不能使用 docvalue_fields
参数检索嵌套对象的 doc values。如果您指定一个嵌套对象,则搜索将返回该字段的空数组 ([ ]
)。要访问嵌套字段,请使用 inner_hits
参数的 docvalue_fields
属性。
存储字段
编辑还可以使用 store
映射选项来存储单个字段的值。您可以使用 stored_fields
参数在搜索响应中包含这些存储的值。
stored_fields
参数用于在映射中显式标记为存储的字段,默认情况下该字段处于关闭状态,通常不建议使用。请使用 源过滤 来选择要返回的原始源文档的子集。
允许为搜索命中表示的每个文档选择性地加载特定的存储字段。
resp = client.search( stored_fields=[ "user", "postDate" ], query={ "term": { "user": "kimchy" } }, ) print(resp)
response = client.search( body: { stored_fields: [ 'user', 'postDate' ], query: { term: { user: 'kimchy' } } } ) puts response
const response = await client.search({ stored_fields: ["user", "postDate"], query: { term: { user: "kimchy", }, }, }); console.log(response);
GET /_search { "stored_fields" : ["user", "postDate"], "query" : { "term" : { "user" : "kimchy" } } }
*
可以用于从文档中加载所有存储字段。
空数组将导致仅返回每个命中的 _id
和 _type
,例如
resp = client.search( stored_fields=[], query={ "term": { "user": "kimchy" } }, ) print(resp)
response = client.search( body: { stored_fields: [], query: { term: { user: 'kimchy' } } } ) puts response
const response = await client.search({ stored_fields: [], query: { term: { user: "kimchy", }, }, }); console.log(response);
GET /_search { "stored_fields" : [], "query" : { "term" : { "user" : "kimchy" } } }
如果请求的字段未存储(store
映射设置为 false
),则将忽略它们。
从文档本身获取的存储字段值始终作为数组返回。相反,像 _routing
这样的元数据字段永远不会作为数组返回。
此外,只能通过 stored_fields
选项返回叶子字段。如果指定了对象字段,则将被忽略。
单独使用 stored_fields
不能用于加载嵌套对象中的字段 — 如果字段的路径中包含嵌套对象,则不会返回该存储字段的任何数据。要访问嵌套字段,必须在 inner_hits
块中使用 stored_fields
。
禁用存储字段
编辑要完全禁用存储字段(和元数据字段),请使用:_none_
resp = client.search( stored_fields="_none_", query={ "term": { "user": "kimchy" } }, ) print(resp)
response = client.search( body: { stored_fields: '_none_', query: { term: { user: 'kimchy' } } } ) puts response
const response = await client.search({ stored_fields: "_none_", query: { term: { user: "kimchy", }, }, }); console.log(response);
GET /_search { "stored_fields": "_none_", "query" : { "term" : { "user" : "kimchy" } } }
脚本字段
编辑您可以使用 script_fields
参数来检索每个命中的脚本评估(基于不同的字段)。例如
resp = client.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 } } } }, ) print(resp)
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
const response = await client.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, }, }, }, }, }); console.log(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']
从中提取要返回的特定元素。这是一个例子
resp = client.search( query={ "match_all": {} }, script_fields={ "test1": { "script": "params['_source']['message']" } }, ) print(resp)
response = client.search( body: { query: { match_all: {} }, script_fields: { "test1": { script: "params['_source']['message']" } } } ) puts response
const response = await client.search({ query: { match_all: {}, }, script_fields: { test1: { script: "params['_source']['message']", }, }, }); console.log(response);
GET /_search { "query": { "match_all": {} }, "script_fields": { "test1": { "script": "params['_source']['message']" } } }
请注意此处的 _source
关键字,以导航类似 json 的模型。
理解 doc['my_field'].value
和 params['_source']['my_field']
之间的区别非常重要。第一个使用 doc 关键字将导致该字段的术语加载到内存(缓存),这将导致更快的执行速度,但会消耗更多的内存。此外,doc[...]
表示法仅允许使用简单值字段(您无法从中返回 json 对象),并且仅对非分析或基于单个术语的字段有意义。但是,如果可能,仍然建议使用 doc
来访问文档中的值,因为每次使用 _source
时都必须加载和解析它。使用 _source
非常慢。