移除映射類型(mapping type)
es在8.X之前的邏輯存儲模型是模擬關系型數據庫的三層結構:index(庫)-type(表)-document(record).這種結構在7.x時不再推薦使用,8.x的時候會把type移除變成最終的兩級結構:index(庫)-document(record).由於層級的調整,在7.x中影響范圍包括:index creation, put mapping, get mapping, put template, get template and get field mappings APIs.
什么是映射類型(mapping type)
es中每個文檔存儲在一個索引(index)中,同時分配到一個映射類型(mapping type)中.映射類型通常表示文檔類型和索引實體.如一個twitter索引可能有user類型和tweet類型.每個映射類型有自己的字段,所以user類型可能有full_name,user_name,email字段,tweet類型可能有content,tweeted_at,user_name字段.文檔通過_type元數據字段來標識類型名稱.查詢時也通過類型字段來限制查詢范圍:
GET twitter/user,tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
}
映射類型的缺點
關系數據庫中,每個表是獨立的,表間的字段即使同名也互相沒有干擾.但是es中的映射類型不同.
- es中同一個索引下的同名字段會被Lucene存儲在一起,這也要求它們的映射類型必須一致.如果不一致則會導致數據刪除失敗.
- 同一個索引中存儲不同的實體,往往相同字段很少,由於es的數據存儲是以索引為維度的,這就造成實際存儲的數據比較分散,不利於文檔壓縮.
這也看出來映射類型的存在很雞肋,因此es決定7.x時移除映射類型的概念.這也是基於查詢和存儲的效率最佳選擇.
推薦的映射類型方式
- 按文檔類型划分索引
實際存儲時,不再通過映射類型區分文檔類型,而是通過索引來區分.如上面的twitter索引示例,我們把user存到user索引中,把tweet存到tweet索引中,查詢,存儲完全獨立.
優點:
- 數據更密集,有利於lucene壓縮
- 同一索引中文檔數據表示獨立的實體,使得全文檢索條目排名分析更精確.
- 自定義類型字段(custome type field)
由於集群中主分片數量是有限的,你可能不想浪費整個分片存儲一些很少數量的文檔數據.這種情況下,你可以通過自定義類型字段實現類似之前映射類型的功能.
用上面的user/tweet舉例:
7.x之前的版本存儲流程如下:
PUT twitter
{
"mappings": {
"user": {
"properties": {
"name": { "type": "text" },
"user_name": { "type": "keyword" },
"email": { "type": "keyword" }
}
},
"tweet": {
"properties": {
"content": { "type": "text" },
"user_name": { "type": "keyword" },
"tweeted_at": { "type": "date" }
}
}
}
}
PUT twitter/user/kimchy
{
"name": "Shay Banon",
"user_name": "kimchy",
"email": "shay@kimchy.com"
}
PUT twitter/tweet/1
{
"user_name": "kimchy",
"tweeted_at": "2017-10-24T09:00:00Z",
"content": "Types are going away"
}
GET twitter/tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
}
7.x之后的版本通過添加自定義類型(type)字段存儲方式:
PUT twitter?include_type_name=true
{
"mappings": {
"_doc": {
"properties": {
"type": { "type": "keyword" },
"name": { "type": "text" },
"user_name": { "type": "keyword" },
"email": { "type": "keyword" },
"content": { "type": "text" },
"tweeted_at": { "type": "date" }
}
}
}
}
7.x之后明確指定類型(type)字段,而7.x之前是隱式指定的_type字段
PUT twitter/_doc/user-kimchy
{
"type": "user",
"name": "Shay Banon",
"user_name": "kimchy",
"email": "shay@kimchy.com"
}
PUT twitter/_doc/tweet-1
{
"type": "tweet",
"user_name": "kimchy",
"tweeted_at": "2017-10-24T09:00:00Z",
"content": "Types are going away"
}
GET twitter/_search
{
"query": {
"bool": {
"must": {
"match": {
"user_name": "kimchy"
}
},
"filter": {
"match": {
"type": "tweet"
}
}
}
}
}
- 父子結構(Parent/Child)不再提供映射類型
7.x前,parent-child關系,定義映射關系時可以指定parent和children類型.7.x后不使用這個語法.parent-child特性運行不做改變,但是實際關系表示改為通過join字段實現.
7.0無類型接口(typeless apis)
7.x作為過渡版本,它在弱化類型的實際影響.正常api使用中如果你明確指定了類型(type),會得到一個不推薦警告:
#! Deprecation: [types removal] Specifying types in search requests is deprecated.
- 索引APIs
索引創建,索引模板和映射apis支持新的url參數include_type_name.它指明在請求和響應映射定義中是否包含類型名稱.這個參數默認值在6.8中是true,以匹配7.0前的映射類型匹配問題.7.0后的默認值為false,8.0中將移除.
PUT /my-index-000001?include_type_name=false
{
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
新增索引映射時不進行類型映射.
- 文檔APIs
7.x中,索引APIs必須通過{index}/_doc路徑調用,自動生成_id或指明{index}/_doc/{id}中的id.
PUT /my-index-000001/_doc/1
{
"foo": "baz"
}
實際存儲數據
{
"_index": "my-index-000001",
"_id": "1",
"_type": "_doc",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
獲取和刪除APIs也類似:{index}/_doc/{id}
GET /my-index-000001/_doc/1
- 查詢APIs
當調用像_search, _msearch, 或_explain查詢API時,url中不應該包含類型.此外,_type字段不用於查詢,聚合和腳本中.
- 響應中的類型
文檔和查詢APIs的響應將繼續返回_type關鍵字,避免破壞現在的響應解析.然而,這個關鍵字不再推薦也不再被引用.在8.0中將被完全刪除.
- 索引模板
推薦在重新添加索引無類型模板時將include_type_name設置為false.后台實現中,無類型模板在創建指令中模仿類型_doc進行創建.
實際官方文檔中還展示舊版到新版的數據遷移方式,以及進行映射類型版本支持的計划.點擊參考資料即可獲取.