Elasticsearch如何修改Mapping结构并实现业务零停机

Elasticsearch 版本:6.4.0html

1、疑问

在项目中后期,若是想调整索引的 Mapping 结构,好比将 ik_smart 修改成 ik_max_word 或者 增长分片数量 等,但 Elasticsearch 不容许这样修改呀,怎么办?mysql

常规 解决方法:linux

<!--more-->sql

  • 根据最新的 Mapping 结构再建立一个索引
  • 将旧索引的数据全量导入到新索引中
  • 告知用户,业务要暂停使用一段时间
  • 修改程序,将索引名替换成新的索引名称,打包,从新上线
  • 告知用户,服务能够继续使用了,并说一声抱歉

我认为最大的弊端就是:须要修改替换程序,甚至有时候还得告知用户暂停使用业务shell

有没有更好的方式去解决上面的需求呢?有!幸亏,Elasticsearch 为咱们提供了另一种解决方法,能够不须要告知用户和修改程序代码。那就是经过索引别名来重建索引windows

2、索引别名

索引别名能够关联一个或多个索引,而且能够在任何须要索引名称的 API 中使用。 通俗解释,别名相似于 windows 的快捷方式,linux 的软连接,mysql 的视图。别名为咱们提供了极大的灵活性。它们容许咱们执行如下操做:微信

  • 在正在运行的集群上,容许一个索引与另一个索引之间透明切换。
  • 对多个索引进行分组组合。好比,有根据月份来建立的索引,别名可与近三个月的索引进行关联。这样的话,咱们就能够经过 别名查询近三个月索引 的所有数据。若是别名用得好,能够更好地控制检索数据量的大小,来提升查询效率,但这也须要经验的积累。

本文开头遇到的问题,就能够经过索引别名来实现,如今咱们学习一下具体操做。数据结构

3、具体操做

如何在零停机(该索引所用到的程序不中止运行)的前提下,修改索引的 Mapping 字段类型呢?可大致分为三步:app

一、步骤一:复制数据

使用 reindex 操做来将旧索引(dynamic_data_v2)的数据彻底复制到新索引(dynamic_data_v5)上:elasticsearch

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

执行结果:

二、步骤二:修改别名关联

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/en/elasticsearch/reference/6.4/indices-aliases.html

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/en/elasticsearch/reference/6.4/indices-put-mapping.html#updating-field-mappings

5、总结

别名是个好东西,而索引别名只是别名的其中一个类型。通常在项目中后期,索引中有大量数据的时候,才能体会到索引别名的妙用。正如本文说起:

  • 用户无感知地维护数据修改更新。
  • 索引组合查询,若是使用得当,能够实现精准快速查询,提升效率。

建议: 相同索引别名的物理索引有 一致的 Mapping 和 数据结构 ,以提高检索效率。


点关注,不迷路

好了各位,以上就是这篇文章的所有内容了,能看到这里的人呀,都是人才

**白嫖很差,创做不易。**各位的支持和承认,就是我创做的最大动力,咱们下篇文章见!

若是本篇博客有任何错误,请批评指教,不胜感激 !

本文来自: 微信公众号【大数据实战演练】。阅读更多精彩好文,欢迎关注微信公众号【大数据实战演练】。

相关文章
相关标签/搜索