Elasticsearch 可以更改 Mapping 嗎?如何修改?

1、實戰線上問題

最近幾個線上問題,都和 Mapping 字段更新有關係,問題列表如下:

問題 1

Mapping 新創建後,還可以更新嗎?

問題 2:

問題 3:

各位同學們 現在有個業務需求幫忙看一下?

需求: 將 A 索引中一個爲 String 的字段修改爲 boolean。

例: sdry:"1" -> sdry:true。

問題 4:

join 類型怎麼修改 join,append 一個新的 child?

業務需要 append join children,官方也說可以 append,但是又沒給方案,我嘗試都失敗了。

四個問題都可以歸結爲 Mapping 更新問題,我們一起梳理實踐一把。

2、問題拆解解讀

問題 1:Mapping 新創建後,還可以更新嗎?

官方文檔有強調:

In general, the mapping for existing fields cannot be updated. There are some exceptions to this rule.

也就是說,已經定義的字段大多數情況不能被更新,除非 reindex 更新 mapping。

但,以下三種情況例外。

Object 對象可以添加新的屬性。

已經存在的 fields 裏面可以添加 fields,以構成一個字段多種類型。

ignore_above 是可以更新的。

問題 1 特例情況實戰一把。

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
    }
  }
}

以上:

對應第一種情況,Object 對象可以添加新的屬性。我們添加了 last 字段。

對應第二種情況,first 添加了 keyword 類型,以組合構造 fields。

對應第三種情況,user_id 添加了 ignore_above。

這三種 Mapping 更新特列情況,大家需要掌握。實戰環節不需要 reindex 就可以更新 Mapping,還是非常便捷的。

問題 2:如何給索引新增、刪除字段?

有人知道怎麼在 kibana 裏面給索引新增,刪除字段嗎?

強調一下:

更新 Mapping 添加字段舉例如下:

DELETE  my-index-003
#創建索引同時指定 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 設置值及含義如下表所示:

Hc8tG7

問題 3:string 類型改成 boolean 類型,如何實現?

各位同學們 現在有個業務需求幫忙看一下。

需求: 將 A 索引中一個爲 String 的字段修改爲 boolean。

例: sdry:"1" -> sdry:true

可以將問題進一步提煉轉換爲:修改 Mapping 字段類型。

Mapping 字段是不可以直接更新的,但我們可以 “曲線救國”。

# 創建索引
PUT test-002
{
 "mappings"{
  "properties"{
   "sflag":{
    "type":"keyword"
   }
  }
 }
}

# 模擬寫入數據
PUT test-002/_bulk
{"index":{"_id":1}}
{"sflag":"1"}
{"index":{"_id":2}}
{"sflag":"0"}


# 更新Mapping
POST test-002/_mapping
{
 "properties":{
  "bflag":{
   "type":"boolean"
  }
 }
}

# 對新增字段做數據處理
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"{}
 }
}

# 檢索結果
POST test-002/_search

解讀一下:

第一步:新增了字段 bflag,且設置爲 boolean 類型。

第二步:自建 ingest 預處理管道,結合原有 sflag 字段更新新增的 bflag 字段。

第三步:全量批量更新已有索引,實現字段的更新。

自此,“曲線救國” 達到目的,如下圖所示,bflag 設置成了 boolean 值。

問題 4:join 類型添加新 child 如何實現?

join 類型怎麼修改 join,append 一個新的 child?

業務需要 append join children,官方也說可以 append,但是又沒給方案,我嘗試都失敗了。

實踐一把,給出答案。

DELETE test-join-index
# 創建父子文檔關聯索引
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 的父子關聯關係,轉化爲:1 對 4 的父子關聯關係,如下圖所示:

3、小結

Mapping 字段的 dynamic 特性有利有弊,要結合業務場景選型,對不希望動態擴展字段以至字段 “膨脹” 的場景下,建議設置爲 strict。

Mapping 創建後,已有字段不可以修改,但可以 “曲線救國” 實現字段更新,間接實現字段的“修改”。

Mapping 中已有字段更新的三個特列要掌握。

Runtime field 運行時類型也能很好的解決本文提出的動態擴展字段的問題,鑑於篇幅原因,本文沒有展開。更多 runtime field 實戰解讀,推薦閱讀:

Elasticsearch 運行時類型 Runtime fields 深入詳解

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/t0ce5WESP4twECP_LPVI9Q