1. 介紹
默認情況下,搜索響應(yīng)中的每個命中文檔都包含字段_source,它是索引文檔時提供的整個JSON對象。為了避免搜索時加載和解析整個_source對象,可以使用以下幾種方式來獲取所選特定字段的值:
- Doc值字段(Doc value fields)
- 存儲字段(Stored fields)
- 源過濾(Source filtering)
- 腳本字段(Script fields)
2. Doc值字段
可以使用docvalue_fields參數(shù)在搜索響應(yīng)中返回一個或多個字段的doc值,字段的doc值存儲與_source中相同的值,但是doc值存儲在磁盤上基于列的結(jié)構(gòu)中,該結(jié)構(gòu)對排序和聚合進行了優(yōu)化,因為每個字段是單獨存儲的,所以Elasticsearch只讀取請求的字段值,從而避免加載整個文檔_source。
例如,下面的搜索請求使用docvalue_fields參數(shù)來檢索特定字段的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形式,使用格式化參數(shù)來為字段doc值自定義格式,只支持日期字段和數(shù)值字段,日期類型支持日期格式,數(shù)值類型支持DecimalFormat模式。
執(zhí)行結(jié)果如下圖所示:

3. 存儲字段
也可以使用stored_fields參數(shù)在搜索響應(yīng)中包含特定存儲的值,需先在映射中設(shè)置store為true,有選擇地為搜索命中的每個文檔加載特定的存儲字段,例如,只加載字段content的存儲值,示例如下:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"stored_fields" : ["content"]
}
執(zhí)行結(jié)果片段如下所示:
{
"_index" : "my_index_01",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.18232156,
"fields" : {
"content" : [
"Quick White Fox"
]
}
}
- 如果請求的字段沒有被存儲(存儲映射設(shè)置為false),那么它們將被忽略。
- 只能通過stored_fields選項返回葉子字段,如果指定了一個對象字段,那么它將被忽略。
- 通常不推薦使用stored_fields。
禁用存儲字段
使用none值可以完全禁用存儲字段(包括元數(shù)據(jù)字段),示例如下:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"stored_fields": "_none_"
}
4. 源過濾
可以使用_source參數(shù)來選擇返回的源字段,這種叫做源過濾(source filtering)。
如果只返回源字段的子集,請在_source參數(shù)中指定通配符(*)模式。下面的搜索API請求只返回user字段及其屬性的源值:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"_source": "user.*"
}
可以在_source字段中指定一個數(shù)組。下面的搜索API請求只返回user字段及其屬性、id字段源:
GET my_index_01/_search
{
"query": { "match": { "content": "Fox" } },
"_source": ["user.*", "id"]
}
也可以在_source參數(shù)中指定一個對象,該對象包括includes和excludes模式數(shù)組。
includes屬性,表示只返回與其中一個模式匹配的源字段,如果沒有指定includes,則返回整個文檔源數(shù)據(jù)。使用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參數(shù)為每個命中結(jié)果(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字段的值,乘以參數(shù)params.factor值
注釋3:獲取文檔中user.name字段的值
返回結(jié)果片段如下:
{
"_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會將該字段的詞條加載到內(nèi)存中緩存,這會有更快的執(zhí)行,但也會有更多的內(nèi)存消耗。此外,doc['field']形式中的字段只允許簡單值類型字段(不能返回json對象),并且只對未分析的或基于單詞條的字段有意義。
- 使用params['_source']['field']形式,Elasticsearch每次使用_source時都必須加載和解析它,這樣使用_source會非常慢,影響執(zhí)行速度。
- 官方推薦使用doc['field']形式從文檔中訪問值,而不是params['_source']['field']。