从搜索中检索选定字段编辑

默认情况下,搜索响应中的每个命中项都包含文档 _source,它是索引文档时提供的整个 JSON 对象。有两种推荐的方法可以从搜索查询中检索选定字段

  • 使用 fields 选项 来提取索引映射中存在的字段的值
  • 使用 _source 选项,如果您需要访问索引时传递的原始数据

您可以同时使用这两种方法,但 fields 选项更可取,因为它会同时查询文档数据和索引映射。在某些情况下,您可能希望使用 其他方法 来检索数据。

fields 选项编辑

要检索搜索响应中的特定字段,请使用 fields 参数。由于它会查询索引映射,因此 fields 参数比直接引用 _source 提供了几个优势。具体来说,fields 参数

其他映射选项也会被尊重,包括 ignore_aboveignore_malformednull_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
}

接受完整的字段名称和通配符模式。

使用 format 参数为字段的值应用自定义格式。

默认情况下,当请求的 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
}

响应将对 firstlast 名称进行分组,而不是将它们作为扁平列表返回。

{
  "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 请求只返回 obj1obj2 字段及其属性的源。

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 参数中指定一个包含 includesexcludes 模式数组的对象。

如果指定了 includes 属性,则只返回与其中一个模式匹配的源字段。您可以使用 excludes 属性从该子集中排除字段。

如果未指定 includes 属性,则返回整个文档源,排除与 excludes 属性中的模式匹配的任何字段。

以下搜索 API 请求仅返回 obj1obj2 字段及其属性的源,排除任何子 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

默认情况下,会为支持的字段存储文档值。但是,不支持 texttext_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" 
    }
  ]
}

接受完整的字段名称和通配符模式。

使用对象表示法,您可以传递 format 参数以对字段的文档值应用自定义格式。 日期字段 支持 日期 format数字字段 支持 DecimalFormat 模式。其他字段数据类型不支持 format 参数。

您不能使用 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" }
  }
}

如果使用 _none_,则无法激活 _sourceversion 参数。

脚本字段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'].valueparams['_source']['my_field'] 之间的区别非常重要。第一个使用 doc 关键字,将导致该字段的词条被加载到内存中(缓存),这将导致更快的执行速度,但内存消耗更多。此外,doc[...] 表示法只允许简单值字段(您无法从中返回 json 对象),并且仅对未分析或基于单个词条的字段有意义。但是,如果可能,使用 doc 仍然是访问文档中值的推荐方法,因为每次使用 _source 时都必须加载和解析它。使用 _source 非常慢。