Elasticsearch 創建索引前必須要了解的知識,提前避坑

Elasticsearch 創建索引前必須要了解的知識,提前避坑

每一個成功人士的背後,必定曾經做出過勇敢而又孤獨的決定。

放棄不難,但堅持很酷~

Elasticsearch 版本:6.4.0

一、疑問

在項目中後期,如果想調整索引的 Mapping 結構,比如將 ik_smart 修改為 ik_max_word或者增加分片數量等,但 Elasticsearch 不允許這樣修改呀,怎麼辦?

常規解決方法:

  • 根據最新的 Mapping 結構再創建一個索引

  • 將舊索引的數據全量導入到新索引中

  • 告知用戶,業務要暫停使用一段時間

  • 修改程序,將索引名替換成新的索引名稱,打包,重新上線

  • 告知用戶,服務可以繼續使用了,並說一聲抱歉

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

有沒有更好的方式去解決上面的需求呢?有!幸好,Elasticsearch 為我們提供了另外一種解決方法,可以不需要告知用戶和修改程序代碼。那就是通過索引別名來重建索引

二、索引別名

索引別名可以關聯一個或多個索引,並且可以在任何需要索引名稱的 API 中使用。通俗解釋,別名類似於 windows 的快捷方式,linux 的軟鏈接,mysql 的視圖。別名為我們提供了極大的靈活性。它們允許我們執行以下操作:

  • 在正在運行的集群上,允許一個索引與另外一個索引之間透明切換。

  • 對多個索引進行分組組合。比如,有根據月份來創建的索引,別名可與近三個月的索引進行關聯。這樣的話,我們就可以通過 別名查詢近三個月索引的全部數據。如果別名用得好,可以更好地控制檢索數據量的大小,來提高查詢效率,但這也需要經驗的積累。

本文開頭遇到的問題,就可以通過索引別名來實現,現在我們學習一下具體操作。

三、具體操作

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

1、步驟一:複製數據

使用 reindex 操作來將舊索引(dynamic_data_v2)的數據完全複製到新索引(dynamic_data_v5)上:

<code>POST _reindex
{
"source": {
"index": "dynamic_data_v2"
},
"dest": {
"index": "dynamic_data_v5"
}
}
/<code>

執行結果:

Elasticsearch 创建索引前必须要了解的知识,提前避坑

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

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

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

<code>DELETE dynamic_data_v2
/<code>

4、小結

至此,我們達到了偽更新(對於用戶來說透明化,無需停止服務)的效果。不過這裡存在一個問題,如果數據量超大的話,複製數據所消費的時間比較多,所以構建索引前還是要儘量考慮周全 Mapping 結構。

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

https://www.elastic.co/guide/en/elasticsearch/reference/

6.4/indices-aliases.html

四、可修改 mapping 的個別情況

Elasticsearch 不允許修改/刪除 Mapping 已存在字段是因為:其底層使用的是 lucene 庫,索引和搜索要涉及分詞方式等操作,更改 Mapping 將意味著使已建立索引的文檔失效,所以不允許修改 已存在字段類型等設置。

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

1、可以新增字段

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

2、可以更改字段類型為 multi_field

<code>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
# }
# }
/<code>

3、可以將新 properties 添加到 “對象” 數據類型字段。

在 Mapping 的 field 裡面設置 properties ,可以使字段存儲 Object 的數據類型。以下的 name 可以理解為 “對象”數據類型字段:

<code># 新增 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"
}
}
}
}
}
/<code>

如下圖所示:

Elasticsearch 创建索引前必须要了解的知识,提前避坑

存儲數據:

<code># name 的對象裡面有兩個字段,分別為:first 和 last,代表名和姓,比如“範閒”。
PUT dynamic_data_v2/_doc/1

{
"name": {
"first": "閒",
"last": "範"
}
}
/<code>

查詢數據:

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

返回結果:

Elasticsearch 创建索引前必须要了解的知识,提前避坑

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

https://www.elastic.co/guide/en/elasticsearch/reference/6.4/indices-put-mapping.html#updating-field-mappings

五、總結

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

  • 用戶無感知地維護數據修改更新。

  • 索引組合查詢,如果使用得當,可以實現精準快速查詢,提高效率。

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

Elasticsearch 创建索引前必须要了解的知识,提前避坑

歡迎大家留言討論

Elasticsearch 創建索引前必須要了解的知識,提前避坑


分享到:


相關文章: