ES 13 - Elasticsearch的元字段 (_index、_type、_source、_routing等)

元字段是ES爲每一個文檔配置的內置字段, 主要用於ES內部相關操做.web

1 標識元字段

1.1 _index - 文檔所屬的索引

_index標註document屬於哪一個index, 是一個虛擬字段, 不會被添加到Lucene索引中.json

將相似的文檔 (也就是具備相同field的文檔) 存放到同一個index中, 是一種良好的數據建模思想.
提供大量查詢的index, 最好不要同時提供大量的統計、聚合等操做——經過把特定的index路由到指定的shard上, 便於系統的優化.bash

注意: 索引名稱必須是小寫的字母, 不能如下劃線"_"開頭, 不能包含逗號 ",".數據結構

在term或者terms查詢, 聚合、腳本以及排序時, 能夠訪問_index字段的值.app

在多個索引中執行查詢時, 能夠經過添加查詢子句來關聯特定的索引文檔, 使用示例——同時查詢多種index:less

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}. 能夠用於查詢、聚合、腳本和排序.elasticsearch

(1) 添加文檔:ide

PUT website/blog/4
{
    "text": "blog with ID 4"
}

PUT website/blog/5?refresh=true
{
    "text": "blog with ID 5"
}

(2) 檢索文檔:post

說明: 對_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

版權聲明

做者: 馬瘦風

出處: 博客園 馬瘦風的博客

您的支持是對博主的極大鼓勵, 感謝您的閱讀.

本文版權歸博主全部, 歡迎轉載, 但請保留此段聲明, 並在文章頁面明顯位置給出原文連接, 不然博主保留追究相關人員法律責任的權利.

相關文章
相關標籤/搜索