Elasticsearch如何修改Mapping結構並實現業務零停機

Elasticsearch 版本:6.4.0

1、疑問

在項目中後期,若是想調整索引的 Mapping 結構,好比將 ik_smart 修改成 ik_max_word 或者 增長分片數量 等,但 Elasticsearch 不容許這樣修改呀,怎麼辦?html

常規 解決方法:mysql

<!--more-->linux

  • 根據最新的 Mapping 結構再建立一個索引
  • 將舊索引的數據全量導入到新索引中
  • 告知用戶,業務要暫停使用一段時間
  • 修改程序,將索引名替換成新的索引名稱,打包,從新上線
  • 告知用戶,服務能夠繼續使用了,並說一聲抱歉

我認爲最大的弊端就是:須要修改替換程序,甚至有時候還得告知用戶暫停使用業務sql

有沒有更好的方式去解決上面的需求呢?有!幸虧,Elasticsearch 爲咱們提供了另一種解決方法,能夠不須要告知用戶和修改程序代碼。那就是經過索引別名來重建索引shell

2、索引別名

索引別名能夠關聯一個或多個索引,而且能夠在任何須要索引名稱的 API 中使用。 通俗解釋,別名相似於 windows 的快捷方式,linux 的軟連接,mysql 的視圖。別名爲咱們提供了極大的靈活性。它們容許咱們執行如下操做:segmentfault

  • 在正在運行的集羣上,容許一個索引與另一個索引之間透明切換。
  • 對多個索引進行分組組合。好比,有根據月份來建立的索引,別名可與近三個月的索引進行關聯。這樣的話,咱們就能夠經過 別名查詢近三個月索引 的所有數據。若是別名用得好,能夠更好地控制檢索數據量的大小,來提升查詢效率,但這也須要經驗的積累。

本文開頭遇到的問題,就能夠經過索引別名來實現,如今咱們學習一下具體操做。windows

3、具體操做

如何在零停機(該索引所用到的程序不中止運行)的前提下,修改索引的 Mapping 字段類型呢?可大致分爲三步:數據結構

一、步驟一:複製數據

使用 reindex 操做來將舊索引(dynamic_data_v2)的數據徹底複製到新索引(dynamic_data_v5)上:app

POST _reindex
{
    "source": {
        "index": "dynamic_data_v2"
    },
    "dest": {
        "index": "dynamic_data_v5"
    }
}

執行結果:elasticsearch

二、步驟二:修改別名關聯

POST /_aliases
{
    "actions": [
        { "remove": { "index": "dynamic_data_v2", "alias": "dynamic_data" }},
        { "add":    { "index": "dynamic_data_v5", "alias": "dynamic_data" }}
    ]
}

三、步驟三:刪除舊索引(可選)

DELETE dynamic_data_v2

四、小結

至此,咱們達到了僞更新(對於用戶來講透明化,無需中止服務)的效果。不過這裏存在一個問題,若是數據量超大的話,複製數據所消費的時間比較多,因此構建索引前仍是要儘可能考慮周全 mapping 結構。

關於索引別名更多操做,可參考:

https://www.elastic.co/guide/...

4、可修改 mapping 的個別狀況

Elasticsearch 不容許修改/刪除 Mapping 已存在字段是由於:其底層使用的是 lucene 庫,索引和搜索要涉及分詞方式等操做,更改 Mapping 將意味着使已創建索引的文檔失效,因此不容許修改 已存在字段類型等設置。

但也有個別狀況:Elasticsearch 容許咱們 將字段添加到索引現有的 Mapping 結構中 或 更改現有字段的僅搜索設置。

一、能夠新增字段

POST dynamic_data_v2/_mapping/_doc
{
  "properties": {
     "amount":{
        "type":"text"
     }
  }
}

二、能夠更改字段類型爲 multi_field

PUT dynamic_data_v2/_mapping/_doc
{
  "properties": {
     "amount":{
        "type":"text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 10
          }
        }
     }
  }
}
# 爲 amount 增長 multi_field
# "fields": {
#    "keyword": {
#       "type": "keyword",
#       "ignore_above": 10
#    }
# }

三、能夠將新 properties 添加到 「對象」 數據類型字段。

在 Mapping 的 field 裏面設置 properties ,可使字段存儲 Object 的數據類型。如下的 name 能夠理解爲 「對象」數據類型字段:

# 新增 name 字段,附帶first的properties屬性
PUT dynamic_data_v2/_mapping/_doc
{
  "properties": {
     "name":{
        "properties": {
            "first": {
              "type": "text"
            }
        }
     }
  }
}
# 能夠支持繼續新增一個名爲last的properties屬性
PUT dynamic_data_v2/_mapping/_doc
{
  "properties": {
     "name":{
        "properties": {
            "last": {
              "type": "text"
            }
        }
     }
  }
}

以下圖所示:

存儲數據:

# name 的對象裏面有兩個字段,分別爲:first 和 last,表明名和姓,好比「範閒」。
PUT dynamic_data_v2/_doc/1
{
  "name": {
    "first": "閒",
    "last": "範"
  }
}

查詢數據:

GET dynamic_data_v2/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "name.last": "範"
          }
        },
        {
          "match_phrase": {
            "name.first": "閒"
          }
        }
      ]
    }
  }
}

返回結果:

上述三種方式,詳情可參考:

https://www.elastic.co/guide/...

5、總結

別名是個好東西,而索引別名只是別名的其中一個類型。通常在項目中後期,索引中有大量數據的時候,才能體會到索引別名的妙用。正如本文說起:

  • 用戶無感知地維護數據修改更新。
  • 索引組合查詢,若是使用得當,能夠實現精準快速查詢,提升效率。

建議: 相同索引別名的物理索引有 一致的 Mapping 和 數據結構 ,以提高檢索效率。


點關注,不迷路

好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是人才

白嫖很差,創做不易。 各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!

若是本篇博客有任何錯誤,請批評指教,不勝感激 !

相關文章
相關標籤/搜索