1. 程式人生 > 其它 >DAY 124 ES--刪除對映型別

DAY 124 ES--刪除對映型別

一 前言

官方解釋:https://www.elastic.co/guide/en/elasticsearch/reference/6.0/removal-of-types.html

在elasticsearch6.0.0或更高的版本中建立索引僅能包含單個對映型別。在具有多種對映型別的5.x版本中建立的索引將繼續像以前一樣在elasticsearch6.x中執行。型別將在elasticsearch7.0.0中的API中棄用,並在8.0.0中完全刪除。

二 什麼是對映型別?

從elasticsearch釋出以來,每個文件都儲存在單個索引中並分配了單個對映型別。對映型別用於表示要編制索引的文件或實體的型別。例如微博(twitter)索引可能具有使用者(user)型別和推文(tweet)兩個型別。 每種對映型別都可以有自己的欄位,因此使用者(user)型別可能有full_name

user_nameemail欄位;而推文(tweet)型別可能有contenttweet_at欄位和使用者(user)型別的user_name欄位。 每個文件都有一個_type包含型別名稱的元欄位,通過在URL中指定型別名稱,搜尋可以限制為一種或多種型別:

GET twitter/user,tweet/_search
{
"query":{
"match":{
"user_name":"kimchy"
}
}
}

_type欄位與文件組合_id以生成_uid欄位,因此具有相同型別的文件_id可以儲存在單個索引中。 對映型別也用於在文件中建立父子關係,因此型別的文件question

可以是型別文件的父類answer 扯了半天淡,一切不都是挺好的嘛?那還為啥要刪除對映型別呢?

三 為什麼要刪除對映型別?

最初(其實到現在),為了便於理解elasticsearch的資料組織,通常拿elasticsearch和關係型資料庫做對比,比如我們談到一個es索引(index)時,通常將它比喻為類似於SQL資料庫中的database,而型別(type)等同於SQL資料庫中的表。 這真是一個糟糕的比喻!讓我們有了錯誤理解。因為在SQL資料庫中,表彼此獨立,一個表中的欄位與另一個表中具有相同名稱的欄位無關,而對映型別中的欄位不是這種情況。 在elasticsearch的索引中,不同對映型別具有相同名稱的欄位在內部由相同的Lucene欄位支援。換句話說,使用上面的示例,使用者(user)型別中的user_name

欄位儲存在和推文(tweet)型別中的user_name欄位完全相同的欄位中,而且兩種型別中的user_name欄位必須具有相同的對映(定義)。 當我們希望刪除一個型別的日期欄位和同一個索引中另一個型別的布林欄位時,這可能會導致挫敗感(可以理解為刪除失敗)。 最重要的是,在同一索引中儲存具有很少或沒有共同欄位的不同實體會導致稀疏資料並干擾Lucene有效壓縮文件的能力。 出於這些原因,我們決定從elasticsearch中刪除對映型別的概念。

四 對映型別的替代方法

4.1 將對映型別分開儲存在索引中

第一種方法是每個文件型別都有一個索引,例如微博(twitter)索引中,我們可以將推文(tweet)型別和使用者(user)型別分開,分別儲存在獨立的索引中。這樣兩個相互的索引就不會引起欄位衝突了。 這中方法有兩個好處:

  • 資料更可能是密集的,因此受益於Lucene中使用的壓縮技術。

  • 用於全文搜尋評分的詞條統計將會更精確,應為同一索引中的所有文件都代表單個實體。

每個索引的大小可以根據其包含的文件數量進行適當的調整,比如我們為使用者(user)型別分配較少的主分片,而為推文(tweet)型別分配較多的主分片。

4.2 自定義型別欄位回到頂部

當然了,叢集中可以儲存多少個主分片是有限制的,我們不希望僅為幾千個文件的集合而浪費整個分片。在這種情況下,我們可以實現自己的自定義type欄位,該欄位的工作方式與舊的_type相似。 還是上面微博(twitter)例子,最初,它的對映型別看起來是這樣的:

PUT twitter
{
"mappings": {
"user":{
"properties":{
"name":{
"type":"text"
},
"user_name":{
"type":"keyword"
},
"email":{
"type":"keyword"
}
}
},
"tweet":{
"properties":{
"content":{
"type":"text"
},
"user_name":{
"type":"keyword"
},
"tweet_at":{
"type":"date"
}
}
}
}
}

PUT twitter/user/kimchy
{
"name":"狗子",
"user_name":"二狗子",
"email":"[email protected]"
}

PUT twitter/tweet/1
{
"name":"kimchy",
"tweet_ad":"2019-04-30T10:26:20Z",
"content":"單身狗求包養"
}


GET twitter/tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
}

如上示例,請在5.x及以下版本測試 我們也可以通過新增自定義type欄位來實現相同目的:

PUT twitter
{
"mappings": {
"doc":{
"properties":{
"type":{
"type":"keyword"
},
"name":{
"type":"text"
},
"user_name":{
"type":"keyword"
},
"email":{
"type":"text"
},
"content":{
"type":"text"
},
"tweet_at":{
"type":"date"
}
}
}
}
}

PUT twitter/doc/user-kimchy
{
"type":"user",
"name":"狗子",
"user_name":"二狗子",
"email":"[email protected]"
}


PUT twitter/doc/tweet-1
{
"type":"tweet",
"user_name":"kimchy",
"tweet_at":"2019-04-30T10:26:20Z",
"content":"單身狗求包養"
}

GET twitter/_search
{
"query": {
"bool": {
"must":[
{
"match": {
"user_name": "kimchy"
}
}
],
"filter": {
"match":{
"type":"tweet"
}
}
}
}
}

上述示例6.5.4版本執行無誤。

五 沒有對映型別的父/子

以前,通過將一個對映型別設定為父級,將一個或多個其他對映型別設定為子級來表示父子關係。現在,沒有了多型別,我們就不能再使用這種語法了。除了表示文件之間的關係方式已改為使用新的join欄位之外,父子特徵將繼續像以前一樣執行。

六 刪除對映型別的計劃

這個刪除對映型別的計劃,對於使用者來說是一個很大的變化,所以我們試圖讓它儘可能輕鬆,更改將如下所示: 在elasticsearch5.6.0中:

  • index.mapping.single_type:true在索引上設定將啟用在6.0中強制執行的單索引型別。

  • 父子的join欄位替換可用於在5.6中建立索引。

在elasticsearch6.x中:

  • 在5.x中建立的索引將繼續在6.x中執行,就像在5.x中一樣。

  • 在6.x中建立的索引僅允許每個索引使用單一型別,任何欄位都可以用於該型別,但必須是唯一的。

  • _type名稱可以不再與_id組合形成_uid欄位,_uid欄位已成為_id欄位的別名。

  • 新索引不再支援舊的父/子關係,而是應該使用連線欄位。

  • 不推薦使用_default_mapping型別。

  • 在6.7中,索引建立、索引模板和對映API支援查詢字串引數(include_type_name),該引數僅表示請求和響應是否應該包含型別名稱,預設為true,應該設定為一個顯式值,以便準備升級到7.0。未設定include_type_name將導致一個棄用警告,沒有顯式型別的索引將使用預設的型別名稱_doc

在elasticsearch7.x中:

  • 不推薦在請求中指定型別。例如,索引文件不再需要文件型別。對於自動生成的id,新的索引API在顯式ids和POST {index_name}/_doc的情況下是PUT {index_name}/_doc/{id}

  • 索引建立,索引模板和對映API中的include_type_name引數將預設為false,未設定引數將導致啟動警告。

  • 刪除了_default_mapping型別。

在elasticsearch8.x中:

  • 不在支援在請求中指定型別。

  • include_type_name引數已刪除。

七將多型別索引遷移到單一型別

Reindex API可用於將多型別索引轉換為單型別索引。下面的例子可以在Elasticsearch 5.6或Elasticsearch 6.x中使用。在6.x中,不需要指定index.mapping。預設為單一型別。

7.1 每種文件型別的索引

第一個示例將微博(twitter)索引拆分為推文(tweets)索引和使用者(users)索引:

PUT users
{
"mappings": {
"user":{
"properties":{
"name":{
"type":"text"
},
"user_name":{
"type":"keyword"
},
"email":{
"type":"keyword"
}
}
}
}
}

PUT tweets
{
"mappings": {
"tweet":{
"properties":{
"content":{
"type":"text"
},
"user_name":{
"type":"keyword"
},
"tweet_at":{
"type":"date"
}
}
}
}
}

POST _reindex
{
"source": {
"index":"twitter",
"type":"user"
},
"dest": {
"index":"users"
}
}

POST _reindex
{
"source": {
"index":"twitter",
"type":"tweet"
},
"dest": {
"index": "tweets"
}
}

上述程式碼在6.5.4版本中執行無誤。 上述的示例意思是,在之前我們在微博(twitter)索引中,有兩個型別(tweet和user)。現在要將兩個型別分開,成為獨立的索引。所以,首先先創建出各自的索引(tweets和users),然後通過POST _reindex來完成遷移工作。

7.2 自定義型別欄位

第二個示例新增自自定義的type欄位,並將其設定為原始值_type。它還添加了型別到id,以防有任何不同型別的文件具有衝突的id:

PUT new_twitter
{
"mappings": {
"doc":{
"properties":{
"type":{
"type":"keyword"
},
"name":{
"type":"text"
},
"user_name":{
"type":"keyword"
},
"email":{
"type":"keyword"
},
"content":{
"type":"text"
},
"tweet_at":{
"type":"date"
}
}
}
}
}


POST _reindex
{
"source": {
"index":"twitter"
},
"dest":{
"index": "new_twitter"
},
"script": {
"source": """
ctx._source.type = ctx._type;
ctx._id = ctx._type + "-" + ctx._id;
ctx._type = "doc";

"""
}
}

上述程式碼在6.5.4版本執行無誤。

八 總結

總之,通篇看下來,如果對elasticsearch,尤其是各版本不太瞭解的話,這篇文件看著索然無味!重要的是看不懂,如果我們是新手,接觸elasticsearch的時候,就是從6.x版本開始的,那隻要記得,一個索引下面只能建立一個型別就行了,其中各欄位都具有唯一性,如果在建立對映的時候,如果沒有指定文件型別,那麼該索引的預設索引型別是_doc,不指定文件id則會內部幫我們生成一個id字串。其他的,who care?