ES 13 - Elasticsearch的元字段(_index、_type、_source、_routing等)
目錄
- 1 標識元字段
- 1.1 _index - 文檔所屬的索引
- 1.2 _uid - 包含_type和_id的復合字段
- 1.3 _type - 文檔的類型
- 1.4 _id - 文檔的id
- 2 文檔來源元字段
- 2.1 _source - 文檔原始JSON內容
- 2.1.1 關閉_source功能
- 2.1.2 查詢時指定返回字段
- 2.2 _size - _source字段占用的字節數
- 2.1 _source - 文檔原始JSON內容
- 3 索引元字段
- 3.1 _all - 文檔所有字段的值
- 3.2 _field_names - 文檔所有非空字段名
- 4 路由元字段
- 4.1
[過期]_parent - 在type間創建父子關系 - 4.2 _routing - 自定義的路由值
- 4.1
- 5 其他元字段
元字段是ES為每個文檔配置的內置字段, 主要用於ES內部相關操作.
1 標識元字段
1.1 _index - 文檔所屬的索引
_index
標註document屬於哪個index, 是一個虛擬字段, 不會被添加到Lucene索引中.
將類似的文檔 (也就是具有相同field的文檔) 存放到同一個index中, 是一種良好的數據建模思想.
提供大量查詢的index, 最好不要同時提供大量的統計、聚合等操作——通過把特定的index路由到指定的shard上, 便於系統的優化.
註意: 索引名稱必須是小寫的字母, 不能以下劃線"_"開頭, 不能包含逗號 ",".
在term或者terms查詢, 聚合、腳本以及排序時, 可以訪問_index
字段的值.
在多個索引中執行查詢時, 可以通過添加查詢子句來關聯特定的索引文檔, 使用示例——同時查詢多種index:
GET website,book_shop/_search { "query": { "terms": { // 查詢_index是website和book_shop的文檔 "_index": [ "website", "book_shop"] } }, "aggs": { "indices": { // 對_index字段進行聚合操作 "terms": { "field": "_index", "size": 10 } } }, "sort": { // 對_index字段進行排序操作 "_index": { "order": "asc" } }, "script_fields": { // 使用腳本, 顯示_index字段 "index_name": { "script": { "lang": "painless", "source": "doc['_index']" } } } }
1.2 _uid - 包含_type和_id的復合字段
_uid
是_type
和_id
的組合, 形式為{type}#{id}
. 可以用於查詢、聚合、腳本和排序.
(1) 添加文檔:
PUT website/blog/4
{
"text": "blog with ID 4"
}
PUT website/blog/5?refresh=true
{
"text": "blog with ID 5"
}
(2) 檢索文檔:
說明: 對
_uid
字段的訪問API已經過期, 需要使用_id
替換.#! Deprecation: Fielddata access on the _uid field is deprecated, use _id instead
GET website/_search
{
"query": {
"terms": { // 通過_uid查詢_type和_id的復合字段
"_uid": ["blog#4", "blog#5"]
}
},
"aggs": {
"uid_aggs": {
"terms": { // 這裏通過_uid聚合的操作已經過期
"field": "_id", "size": 10
}
}
},
"sort": { // 這裏通過_uid排序的操作已經過期
"_id": { "order": "desc"}
},
"script_fields": {
"uid_script": {
"script": { // 這裏對_uid的腳本操作已經過期
"lang": "painless",
"source": "doc['_id']"
}
}
}
}
1.3 _type - 文檔的類型
_type
元字段用來標註document屬於哪個類型, 也被稱作映射類型.
註意: type的名稱可以是大寫或小寫字母, 但不能以下劃線"_"開頭, 不能包含逗號",".
在Elasticsearch 6.0之前的版本中, 一個index可能會被劃分為多個type, 例如: 商品中有電子商品, 服裝商品, 生鮮商品...
但在Elasticsearch 6.0之後, 一個index只能包含一個type, 否則將出現錯誤.
每一個索引文檔都包含_type
和_id
字段, _type
字段的目的是通過類型名加快搜索速度.
_type
字段可以在查詢、聚合、排序以及腳本中訪問到.
關於type的底層數據結構, 可參見ES XX - Elasticsearch對索引類型(_type)的處理方式.
1.4 _id - 文檔的id
_id
代表document的唯一標識, 與_index
和_type
一起, 唯一標識和定位一個document.
註意: 可以手動指定document的id(
PUT index/type/id
), 也可以不指定, Elasticsearch在添加文檔時會自動為其創建id.
可以在查詢、腳本中訪問, 查詢示例:
GET website/_search
{
"query": {
"terms": {"_id" : ["1", "2"]}
},
"aggs": {
"id_aggs": {
"terms": {
"field": "_id", "size": 10
}
}
},
"script_fields": {
"id_script": {
"script": {
"lang": "painless",
"source": "doc['_id']"
}
}
}
}
2 文檔來源元字段
2.1 _source - 文檔原始JSON內容
文檔的原始JSON內容將索引到_source
字段中, 該字段本身不建立索引, 但是會被存儲.
搜索文檔時默認返回該字段及其內容, 但無法用於搜索.
2.1.1 關閉_source功能
_source
功能默認是開啟的, 它會產生額外的存儲開銷, 可以關閉:
PUT website
{
"mappings": {
"blog": {
"_source": {"enabled": false}
}
}
}
// 或者:
PUT website/_mapping/blog
{
"_source": {"enabled": false}
}
註意: 必須在創建索引時關閉, 創建之後不允許修改, 否則將會發生如下錯誤:
{
"error": {
"root_cause": [
{
"type": "resource_already_exists_exception",
"reason": "index [website/zIUdhInBQsOUi_4Tt2SSkQ] already exists",
"index_uuid": "zIUdhInBQsOUi_4Tt2SSkQ",
"index": "website"
}
],
"type": "resource_already_exists_exception",
"reason": "index [website/zIUdhInBQsOUi_4Tt2SSkQ] already exists",
"index_uuid": "zIUdhInBQsOUi_4Tt2SSkQ",
"index": "website"
},
"status": 400
}
2.1.2 查詢時指定返回字段
_source功能被禁止, 將造成大量功能無法使用:
partial update 功能基於_source實現;
hilight 高亮顯示功能基於_source實現;
reindex 重建索引功能基於_source實現, 不需要從其他外部存儲中獲取數據, 再index;
基於_source定制返回field;
調試query時更容易, 因為可以很直觀地看到_source內容……
可以在創建index時, 在mapping中通過includes/excludes
參數來減少_source
字段的內容:
PUT logs
{
"mappings": {
"event": {
"_source": {
"includes": ["*.count", "meta.*"], // 包含的字段
"excludes": ["meta.desc", "meta.other.*"] // 不包含的字段
}
}
}
}
移除的字段不會被存儲在_source中, 但仍然可以搜索到這些字段.
可以在檢索時, 禁止返回原始內容:
GET website/blog/1?_source=false
如果只想獲取_source
的部分內容, 可以使用_source_includes
或_source_excludes
參數:
GET website/blog/1?_source_includes=title,content
GET website/blog/1?_source_excludes=post_date,author_id
Elasticsearch 6.0之前的版本中: 使用
_source_include
和_source_exclude
用來指定檢索的結果中是否包含_source
中的某個字段;
Elasticsearch 6.0之後的版本中: 相關的API修改為:_source_includes
和_source_excludes
——多加了s
.
2.2 _size - _source字段占用的字節數
記錄_source
字段占用的字節數, 由插件mapper-size提供.
3 索引元字段
3.1 _all - 文檔所有字段的值
(1) ES 6.0之後的方法:
在Elasticsearch 6.0版本中, _all
字段已經被禁用了. 若要開啟, 官方建議是:
"Enabling [_all] is disabled in 6.0. As a replacement, you can use [copy_to] on mapping fields to create your own catch all field."
——大致意思是:_all
已經不允許使用了, 作為替換, 我們可以使用copy_to
關鍵字來創建需要獲取的所有字段的內容.
copy_to
的使用方法如下:
PUT logs
{
"mappings": {
"event": {
"properties": {
"event_id": {
"type": "text",
"copy_to": {"enabled": true}
},
"event_desc": {
"type": "text",
"copy_to": {"enabled": true},
"analyzer": "english"
},
"time": {
"type": "date",
"copy_to": {"enabled": true},
"format": "strict_date_optional_time||epoch_millis"
}
}
}
}
}
(2) ES 6.0以前的方法:
在Elasticsearch 6.0之前, _all
字段的使用方式如下:
_all
字段包含1個文檔的全部field的內容: 用一個大字符串關聯其他所有字段的值, 用空格作為分隔符.
_all
字段可以被分析和索引, 但不會被存儲 —— 默認的搜索field.
通過_all
字段可以對文檔的值進行搜索而不必知道相關的字段名.
_all
字段丟失了長字段(低相關性)和短字段(高相關性)之間的區別 —— 在相關性搜索要求比較高的時候, 應該明確指出要查詢的字段.
① **_all字段需要額外的處理器周期, 且耗費更多的磁盤空間, 若不需要, 建議禁用此功能:**
PUT website/_mapping/blog
{
"_all": {"enabled": false}
}
② 或 在field中設置include_in_all
—— 是否要將field的值包含在_all
中:
PUT website/_mapping/blog
{
"properties": {
"test_field": {
"type": "text",
"include_in_all": false
}
}
}
3.2 _field_names - 文檔所有非空字段名
該字段可以用在查詢、聚合以及腳本中 —— 用於查找指定字段的值非空的文檔是否存在.
使用示例:
GET website/_search
{
"query": {
"terms": {"_field_names": ["content"]}
}
}
4 路由元字段
4.1 [過期]_parent - 在type間創建父子關系
(1) 創建映射:
PUT store
{
"mappings": {
"book": {},
"it_book": {
"_parent": {"type": "book"} // 指定其父類
}
}
}
(2) 插入父文檔:
PUT store/book/1
{ "desc": "this is parent book"}
(3) 插入子文檔, 並指出其父文檔:
PUT store/it_book/2?parent=1
{ "desc": "this is child it_book"}
(4) 父子文檔的限制:
① 父type和子type必須不同.
② _parent的type的值只能是不存在的類型 —— 一個type被創建後就不能稱為父類型了.
(5) 其他說明:
父子文檔必須索引在同一個分片上:
① parent的編號用於子文檔的路由值, 確保子文檔被索引到父文檔所在的分片中.
② 查詢、更新、刪除子文檔時, 也需要提供相同的parent值.
4.2 _routing - 自定義的路由值
用於將文檔路由到指定的分片上. 通過如下公式將文檔路由到特定的分片:
shard_num = hash(_routing) % num_primary_shards
如果不指定_routing
的值, 默認使用文檔的_id
字段. 如果存在父文檔則使用其_parent
的編號.
可以通過為某些文檔都指定相同的路由值, 來實現對這些文檔的自定義路由功能:
// 此文檔使用'user_5220'作為其路由值, 在查詢、更新、刪除時同樣需要提供此路由值
PUT website/blog/1?routing=user_5220
{
"title": "xxx"
}
_routing
字段可以在查詢、聚合、腳本以及排序的時候訪問. 比如直接指定路由值來搜索相關的文檔:
GET website/_search
{
"query": {
"terms": {"_routing": [ "user_5220" ] }
}
}
5 其他元字段
_meta - 應用特定的元字段: 每個type都可以擁有自定義的元數據 —— ES並不會使用, 但可以用來存儲應用程序的特定信息.
使用示例:
PUT website
{
"mappings": {
"user": {
"_meta": {
"class": "com.healchow.website.pojo.User",
"version": {"min": "1.0", "max": "1.3"}
}
}
}
}
參考資料
Elasticsearch官方文檔 - Meta-Fields
版權聲明
作者: ma_shoufeng(馬瘦風)
出處: 博客園 馬瘦風的博客
您的支持是對博主的極大鼓勵, 感謝您的閱讀.
本文版權歸博主所有, 歡迎轉載, 但請保留此段聲明, 並在文章頁面明顯位置給出原文鏈接, 否則博主保留追究相關人員法律責任的權利.
ES 13 - Elasticsearch的元字段(_index、_type、_source、_routing等)