Elasticsearch 可以更改 Mapping 嗎?如何修改?
1、實(shí)戰(zhàn)線上問題
最近幾個(gè)線上問題,都和 Mapping 字段更新有關(guān)系,問題列表如下:
問題 1:
Mapping新創(chuàng)建后,還可以更新嗎?
問題 2:
群友 A:有人知道怎么在kibana里面給索引新增,刪除字段嗎? 群友 B: 不就是改 mapping 嗎 群友 A:怎么改? 群友 B:寫dsl啊… 群友 A:只能加不能刪吧?
問題 3:
各位同學(xué)們 現(xiàn)在有個(gè)業(yè)務(wù)需求幫忙看一下?
需求:將 A 索引中一個(gè)為 String 的字段修改為 boolean。
例: sdry:"1" -> sdry:true。
問題 4:
join 類型怎么修改 join,append一個(gè)新的child?
業(yè)務(wù)需要 append join children,官方也說可以 append,但是又沒給方案,我嘗試都失敗了。
四個(gè)問題都可以歸結(jié)為 Mapping 更新問題,我們一起梳理實(shí)踐一把。
2、問題拆解解讀
問題1:Mapping新創(chuàng)建后,還可以更新嗎?
官方文檔有強(qiáng)調(diào):
In general, the mapping for existing fields cannot be updated. There are some exceptions to this rule.
也就是說,已經(jīng)定義的字段大多數(shù)情況不能被更新,除非 reindex 更新 mapping。
但,以下三種情況例外。
第一:new properties can be added to Object fields.
Object 對象可以添加新的屬性。
第二: new multi-fields can be added to existing fields.
已經(jīng)存在的fields里面可以添加fields,以構(gòu)成一個(gè)字段多種類型。
第三:the ignore_above parameter can be updated.
ignore_above 是可以更新的。
問題 1 特例情況實(shí)戰(zhàn)一把。
DELETE?my_index
PUT?my_index?
{
??"mappings":?{
????"properties":?{
??????"name":?{
????????"properties":?{
??????????"first":?{
????????????"type":?"text"
??????????}
????????}
??????},
??????"user_id":?{
????????"type":?"keyword"
??????}
????}
??}
}
更新 Mapping 操作如下示例:
PUT?my_index/_mapping
{
??"properties":?{
????"name":?{
??????"properties":?{
????????"first":{
??????????"type":"text",
??????????"fields":{
????????????"field":{
??????????????"type":"keyword"
????????????}
??????????}
????????},
????????"last":?{?
??????????"type":?"text"
????????}
??????}
????},
????"user_id":?{
??????"type":?"keyword",
??????"ignore_above":?100
????}
??}
}
以上:
對應(yīng)第一種情況,Object 對象可以添加新的屬性。我們添加了 last 字段。
對應(yīng)第二種情況,first 添加了keyword 類型,以組合構(gòu)造fields。
對應(yīng)第三種情況,user_id 添加了ignore_above。
這三種 Mapping 更新特列情況,大家需要掌握。實(shí)戰(zhàn)環(huán)節(jié)不需要 reindex 就可以更新 Mapping,還是非常便捷的。
問題2:如何給索引新增、刪除字段?
有人知道怎么在kibana里面給索引新增,刪除字段嗎?
強(qiáng)調(diào)一下:
Mapping 中已有的字段是不可以刪除的,除非 reindex。
Mapping 字段設(shè)置默認(rèn)是 "dynamic:true",表明支持動(dòng)態(tài)添加字段。
更新 Mapping 添加字段舉例如下:
DELETE??my-index-003
#創(chuàng)建索引同時(shí)指定?Mapping
PUT?my-index-003
{
??"mappings":?{
????"properties":?{
??????"message":?{
????????"type":?"keyword",
????????"ignore_above":?20
??????}
????}
??}
}
#更新?Mapping
POST?my-index-003/_mapping
{
??"properties":?{
????"title":?{
??????"type":?"text",
??????"analyzer":?"ik_max_word"
????}
??}
}
dynamic 設(shè)置值及含義如下表所示:
| 屬性值 | 含義 |
|---|---|
| true | 默認(rèn),支持動(dòng)態(tài)更新 |
| false | 忽略新增字段 |
| strict | 嚴(yán)格定義字段,類似寫死固定字段,再新增未設(shè)定字段會(huì)報(bào)錯(cuò) |
| runtime | 和默認(rèn)true有細(xì)微差別,參見官方文檔 |
問題 3:string 類型改成 boolean 類型,如何實(shí)現(xiàn)?
各位同學(xué)們 現(xiàn)在有個(gè)業(yè)務(wù)需求幫忙看一下。
需求:將 A 索引中一個(gè)為 String 的字段修改為 boolean。
例:sdry:"1" -> sdry:true
可以將問題進(jìn)一步提煉轉(zhuǎn)換為:修改 Mapping 字段類型。
Mapping 字段是不可以直接更新的,但我們可以“曲線救國”。
#?創(chuàng)建索引
PUT?test-002
{
?"mappings":?{
??"properties":?{
???"sflag":{
????"type":"keyword"
???}
??}
?}
}
#?模擬寫入數(shù)據(jù)
PUT?test-002/_bulk
{"index":{"_id":1}}
{"sflag":"1"}
{"index":{"_id":2}}
{"sflag":"0"}
#?更新Mapping
POST?test-002/_mapping
{
?"properties":{
??"bflag":{
???"type":"boolean"
??}
?}
}
#?對新增字段做數(shù)據(jù)處理
PUT?_ingest/pipeline/mychangepipeline
{
?"processors":[
??{
????"script":?{
?????"description":?"Extract?'tags'?from?'env'?field",
?????"lang":?"painless",
?????"source":?"""
?????if(ctx['sflag']?==?"1")
?????{
??????ctx['bflag']=true;
?????}else?if(ctx['sflag']=="0")
?????{
??????ctx['bflag']=false;
?????}
?????"""
????}
???}
??]
}
#?全量更新操作
POST?test-002/_update_by_query?pipeline=mychangepipeline
{
?"query":?{
??"match_all":?{}
?}
}
#?檢索結(jié)果
POST?test-002/_search
解讀一下:
第一步:新增了字段 bflag,且設(shè)置為 boolean 類型。
第二步:自建 ingest 預(yù)處理管道,結(jié)合原有 sflag 字段更新新增的 bflag 字段。
第三步:全量批量更新已有索引,實(shí)現(xiàn)字段的更新。
自此,“曲線救國”達(dá)到目的,如下圖所示,bflag 設(shè)置成了 boolean 值。

問題4:join 類型添加新 child 如何實(shí)現(xiàn)?
join 類型怎么修改 join,append一個(gè)新的child?
業(yè)務(wù)需要 append join children,官方也說可以 append,但是又沒給方案,我嘗試都失敗了。
實(shí)踐一把,給出答案。
DELETE?test-join-index
#?創(chuàng)建父子文檔關(guān)聯(lián)索引
PUT?test-join-index
{
??"mappings":?{
????"properties":?{
??????"my_id":?{
????????"type":?"keyword"
??????},
??????"my_join_field":?{
????????"type":?"join",
????????"relations":?{
??????????"question":?"answer_a"
????????}
??????}
????}
??}
}
#?更新?Mapping
POST?test-join-index/_mapping
{
??"properties":?{
????"my_join_field":?{
??????"type":?"join",
??????"relations":?{
????????"question":?[
??????????"answer_a",
??????????"answer_b",
??????????"answer_c",
??????????"answer_d"
????????]
??????}
????}
??}
}
上面的更新 Mapping 部分,由 1 對 1 的父子關(guān)聯(lián)關(guān)系,轉(zhuǎn)化為:1 對 4 的父子關(guān)聯(lián)關(guān)系,如下圖所示:

3、小結(jié)
Mapping 字段的 dynamic 特性有利有弊,要結(jié)合業(yè)務(wù)場景選型,對不希望動(dòng)態(tài)擴(kuò)展字段以至字段“膨脹”的場景下,建議設(shè)置為 strict。
Mapping 創(chuàng)建后,已有字段不可以修改,但可以“曲線救國”實(shí)現(xiàn)字段更新,間接實(shí)現(xiàn)字段的“修改”。
Mapping 中已有字段更新的三個(gè)特列要掌握。
Runtime field 運(yùn)行時(shí)類型也能很好的解決本文提出的動(dòng)態(tài)擴(kuò)展字段的問題,鑒于篇幅原因,本文沒有展開。更多 runtime field 實(shí)戰(zhàn)解讀,推薦閱讀:
推薦
更短時(shí)間更快習(xí)得更多干貨!
已帶領(lǐng)72位球友通過 Elastic 官方認(rèn)證!
中國僅通過百余人

