1. 介绍
默认情况下,搜索响应中的每个命中文档都包含字段_source,它是索引文档时提供的整个JSON对象。为了避免搜索时加载和解析整个_source对象,可以使用以下几种方式来获取所选特定字段的值:
- Doc值字段(Doc value fields)
- 存储字段(Stored fields)
- 源过滤(Source filtering)
- 脚本字段(Script fields)
2. Doc值字段
可以使用docvalue_fields参数在搜索响应中返回一个或多个字段的doc值,字段的doc值存储与_source中相同的值,但是doc值存储在磁盘上基于列的结构中,该结构对排序和聚合进行了优化,因为每个字段是单独存储的,所以Elasticsearch只读取请求的字段值,从而避免加载整个文档_source。
例如,下面的搜索请求使用docvalue_fields参数来检索特定字段的doc值,示例如下:
PUT /my_index_01
{
"mappings": {
"properties": {
"content": {
"type": "text",
"store": true
},
"create_date": { "type": "date" },
"id": { "type": "keyword" },
"user": {
"properties": {
"name": { "type": "keyword" },
"age": { "type": "integer" }
}
}
}
}
}
POST /my_index_01/_doc/1
{"id":"00000001", "content":"Quick Brown Fox", "create_date": "2015-01-01", "user.name":"james", "user.age": 35}
POST /my_index_01/_doc/2
{"id":"00000002", "content":"Quick White Fox", "create_date": "2015-01-02", "user.name":"fake", "user.age": 26}
GET my_index_01/_search
{
"query": {
"match": {
"content": "Fox"
}
},
"docvalue_fields": [
"id",
"user*", //1
{
"field": "create_date",
"format": "epoch_millis" //2
}
],
"_source": false
}
注释1:支持完整字段名和通配符匹配模式。
注释2:使用object形式,使用格式化参数来为字段doc值自定义格式,只支持日期字段和数值字段,日期类型支持日期格式,数值类型支持DecimalFormat模式。
执行结果如下图所示:
3. 存储字段
也可以使用stored_fields参数在搜索响应中包含特定存储的值,需先在映射中设置store为true,有选择地为搜索命中的每个文档加载特定的存储字段,例如,只加载字段content的存储值,示例如下:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"stored_fields" : ["content"]
}
执行结果片段如下所示:
{
"_index" : "my_index_01",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.18232156,
"fields" : {
"content" : [
"Quick White Fox"
]
}
}
- 如果请求的字段没有被存储(存储映射设置为false),那么它们将被忽略。
- 只能通过stored_fields选项返回叶子字段,如果指定了一个对象字段,那么它将被忽略。
- 通常不推荐使用stored_fields。
禁用存储字段
使用none值可以完全禁用存储字段(包括元数据字段),示例如下:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"stored_fields": "_none_"
}
4. 源过滤
可以使用_source参数来选择返回的源字段,这种叫做源过滤(source filtering)。
如果只返回源字段的子集,请在_source参数中指定通配符(*)模式。下面的搜索API请求只返回user字段及其属性的源值:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"_source": "user.*"
}
可以在_source字段中指定一个数组。下面的搜索API请求只返回user字段及其属性、id字段源:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"_source": ["user.*", "id"]
}
也可以在_source参数中指定一个对象,该对象包括includes和excludes模式数组。
includes属性,表示只返回与其中一个模式匹配的源字段,如果没有指定includes,则返回整个文档源数据。使用exclude属性来排除,从满足includes属性的文档中排除exclude中模式匹配的源字段。下面的搜索API请求只返回user字段及其属性、id字段源,但是需要排除任何有age属性的字段源:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"_source": {
"includes": [ "user.*", "id"],
"excludes": [ "*.age" ]
}
}
5. 脚本字段
通过script_fields参数为每个命中结果(hit)基于不同的字段进行自定义脚本估算,然后返回脚本计算值。例如,自定义test1、test2、test3三个脚本,示例如下:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"script_fields": {
"test1": {
"script": {
"lang": "painless",
"source": "doc['user.age'].value * 2" //1
}
},
"test2": {
"script": {
"lang": "painless",
"source": "doc['user.age'].value * params.factor", //2
"params": {
"factor": 2.0
}
}
},
"test3": {
"script": {
"lang": "painless",
"source": "doc['user.name']" //3
}
}
}
}
注释1:获取文档中user.age字段的值,乘以2
注释2:获取文档中user.age字段的值,乘以参数params.factor值
注释3:获取文档中user.name字段的值
返回结果片段如下:
{
"_index" : "my_index_01",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.18232156,
"fields" : {
"test1" : [ 25 ],
"test2" : [ 52.0 ],
"test3" : [ "fake" ]
}
}
脚本字段还可以访问实际的_source文档,并通过使用params['_source']提取要从其中返回的特定元素。示例如下:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"script_fields" : {
"test1" : {
"script" : "params['_source']['content']"
}
}
}
理解doc['field']与params['_source']['field']
- 使用doc['field']形式,Elasticsearch会将该字段的词条加载到内存中缓存,这会有更快的执行,但也会有更多的内存消耗。此外,doc['field']形式中的字段只允许简单值类型字段(不能返回json对象),并且只对未分析的或基于单词条的字段有意义。
- 使用params['_source']['field']形式,Elasticsearch每次使用_source时都必须加载和解析它,这样使用_source会非常慢,影响执行速度。
- 官方推荐使用doc['field']形式从文档中访问值,而不是params['_source']['field']。