背景

通常数据库进行分库分表后,目前比较常规的作法,是通过将数据异构到Elasticsearch来提供分页列表查询服务;在创建Elasticsearch索引时,基本都是会参考目前的业务需求、关系数据库中的类型以及对数据的相关规划来定义相关字段mapping的类型.

在Elasticsearch的mapping中的列(或则叫属性),有几个比较重要的参数(更多参数参考官方文档)

  • 列类型:type

    指定了该列的数据类型,常用的有text, keyword, date, long, double,boolean以及 object和nested,不同的类型也有对应的不同查询方式,创建之后是不能修改的;

  • 是否可索引:index

    该index选项控制字段值是否被索引。它接受true or false,并且默认为true. 未索引的字段不可查询,当然也不能做为排序字段。

但是在实际的开发过程中,又会有需求对现有的mapping的type进行修改(类似对MySQL数据表的字段进行DDL操作)的诉求。比如商品上的价格price字段,按原来的业务分析,只需要提供数据返回即可,在创建索引时类型定义了keyword了,并且index设置成了false,这时我们需要根据价格的范围查询或则进行排序操作,就希望对mapping进行调整,将类型修改成数字类型,索引也需要加上;今天针对Elasticsearch的Mapping类型进行修改,讨论几个可行的方案

方案1:运用reindex

遇到问题第一时间,我们应该是查询官方文档是否有相关的操作说明,在官方文档中,确定能找到对已有mapping更新的相关api put-mapping,通过这个文档,很快可以找到文档中对修改已有mapping的列的方式(参考官方文档),同时也提到的通过 reindex的方式来修改已有类型的方式;

除了支持的mapping parameters外,您不能更改现有字段的映射或字段类型。更改现有字段可能会使已编制索引的数据无效。如果您需要更改字段的映射,请使用正确的映射创建一个新索引并将您的数据重新索引reindex到该索引中。

如原来索引的mapping如下

PUT /users
{
"mappings" : {
"properties": {
"user_id": {
"type": "long"
}
}
}
} //加一了两条数据
POST /users/_doc?refresh=wait_for
{
"user_id" : 12345
} POST /users/_doc?refresh=wait_for
{
"user_id" : 12346
}

这时想在修改user_id的类型为keyword,我们直接是修改不了的。

//尝试直接修改type,行不通,会报错
PUT /users/_mapping
{
"properties": {
"user_id": {
"type": "keyword"
}
}
} //报错信息
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "mapper [user_id] of different type, current_type [long], merged_type [keyword]"
}
],
"type": "illegal_argument_exception",
"reason": "mapper [user_id] of different type, current_type [long], merged_type [keyword]"
},
"status": 400
}

按官方文档说的reindex重新索引可按以下步骤操作

操作步骤

第一步:创建新的mapping new_users 将user_id的类型定义成 keyword

PUT /new_users
{
"mappings" : {
"properties": {
"user_id": {
"type": "keyword"
}
}
}
}

第二步:将原user索引标记为只读

控制我们的应用系统,不再向老索引中写数据,最好对老索引进行只读操作设置,保证在reindex的过程中,不要生产新数据,导致新老索数据不一致;

//设置索引为读写的
PUT /users/_settings
{
"settings": {
"index.blocks.write": true
}
}

第三步:将原user索引中的数据迁移到new_users中

POST /_reindex
{
"source": {
"index": "users"
},
"dest": {
"index": "new_users"
}
}

reindex还有很多的参数可以配置,包括从别一个集群迁移数据都是可以的,详细可参考:Reindex API

如果新的索引的mapping的定义与原索引的定义有差异的,会按新索引定义的 dynamic 规则进行数据的迁移,具体的,可以参考: dynamic

该dynamic设置控制是否可以动态添加新字段。它接受三种设置:

值 说明
true 新检测到的字段被添加到映射中。(默认); 新增的数据类型的规则,可以参考:dynamic-mapping
false 忽略新检测到的字段。这些字段不会被编入索引,因此将无法搜索,但仍会出现在_source返回的命中字段中。这些字段不会添加到映射中,必须明确添加新字段。
strict 如果检测到新字段,则会抛出异常并拒绝文档。必须将新字段显式添加到映射中。

同时将原user索引标记为可读写

//设置索引为可读写
PUT /users/_settings
{
"settings": {
"index.blocks.write": false
}
}

第四步:切换到使用新的mapping

  1. 可以将应用系统中的配置改成新索引
  2. 也可以通过索引的别名的方式为新索引增加原来老索引的别名来操作,为索引增加别名参考文档:Add index alias API,在增加别名前,需要删除原来的老索引;
//为索引增加别名 基本格式
PUT /<index>/_alias/<alias>
POST /<index>/_alias/<alias> //为new_users索引增加别名users
PUT /new_users/_alias/users //没有删除老索引前,是增加不了别名的,需要先删除老别名
{
"error": {
"root_cause": [
{
"type": "invalid_alias_name_exception",
"reason": "Invalid alias name [users], an index exists with the same name as the alias",
"index_uuid": "8Rbq_32BTHC4CoO_CqWdXA",
"index": "users"
}
],
"type": "invalid_alias_name_exception",
"reason": "Invalid alias name [users], an index exists with the same name as the alias",
"index_uuid": "8Rbq_32BTHC4CoO_CqWdXA",
"index": "users"
},
"status": 400
}

方案优劣分析

【优点】操作简单,官方方案

该方案,不需要对原索引做操作,在线即可进行,并且操作步骤也简单;也是官方文档提供的方案。

【缺点】数据量大迁移耗时长

当数据最大时,这个数据迁移会比较耗时

结论

当数据量小时,并且希望mapping比较规整好看,该方案是比较推荐的。当数据量大时,可能该方案在数据迁移过程中,可能就是一个问题,需要评估是否可行了;

方案2:运用multi-fields

为不同的目的以不同的方式索引同一个字段通常很有用。这就是multi-fields的目的。例如,一个string 字段可以映射为text用于全文搜索的字段,也可以映射keyword为用于排序或聚合的字段;

在这个方案中,应用的是mapping参数fields来对同一个列,定义多种数据类型;详细[【官方文档】multi-fields] (https://www.elastic.co/guide/en/elasticsearch/reference/7.5/multi-fields.html)

操作步骤

第一步:为列增加fields属性

还是用上面的users这个索引为例,我们还是想在为将user_id的类型定义成 keyword;

PUT /users/_mapping
{
"properties":{
"user_id":{
"type":"long",
"fields":{
"raw":{
"type":"keyword"
}
}
}
}
}

操作完成后,在users的 user_id列下,就多个了个raw的子属性;在我们正常写数据user_id时,索引中就会后成两直索引,一个是long类型的user_id,以及keyword类型的user_id.raw;

该put mapping时,type参数必需有,同时需要跟原来的类型一致,fields中新定义的属性,可以多个;

方案优劣分析

【优点】不影响原索引,同一列可以定义多种类型

通过这方式不会影响原来的索引数据,可以不修改现在的应用程序,查询方式与数据写入方式,都是可以按原来的执行,对应用方无感知,只需要在使用新类型时使用即可,可以说影响是最小的;

同时只是做了一个定义,执行速度是非常快的,对Elasticsearch服务基本不会有太大影响;并且对于同一个列可以定义多个类型,比如商品名称,在多国环境下可以根据不同语言定义不同的分词器;

【缺点】老数据不会自动创建子索引,多出额外的存储

老数据不会自动创建索引,因为需要多出新的索引来,会增加额外的存储;

结论

1、需要对多一列创建多个索引类型时,是一个非常推荐的方案;

2、对于新索引,只有新业务使用,对老数据没有诉求的,也非常推荐该方案;

方案3:运用copy_to

copy_to是将多个字段的值,合并到一个字段中,便于搜索。但是也可以实现一个字段存在多个类型的需求。详细参考【官方文档】copy_to

操作步骤

还是用上面的users这个索引为例,为user_id创建一个copy列: user_id_raw 类型定义成 keyword

PUT /users/_mapping
{
"properties":{
"user_id_raw":{
"type":"keyword",
"copy_to":"user_id"
}
}
}

这个方案与方案2:multi-fields 基本是一样的,只是创建列的方式不同,优缺点都一样;

参考资料

Elasticsearch Mapping类型修改的更多相关文章

  1. Elasticsearch 的坑爹事——记录一次mapping field修改过程

    Elasticsearch 的坑爹事 本文记录一次Elasticsearch mapping field修改过程 团队使用Elasticsearch做日志的分类检索分析服务,使用了类似如下的_mapp ...

  2. Elasticsearch 的坑爹事——记录一次mapping field修改过程(转)

    原文:http://www.cnblogs.com/Creator/p/3722408.html 本文记录一次Elasticsearch mapping field修改过程 团队使用Elasticse ...

  3. (转)Elasticsearch 的坑爹事——记录一次mapping field修改过程

    Elasticsearch 的坑爹事 本文记录一次Elasticsearch mapping field修改过程 团队使用Elasticsearch做日志的分类检索分析服务,使用了类似如下的_mapp ...

  4. ES mapping field修改过程

    Elasticsearch 的坑爹事--记录一次mapping field修改过程 http://www.cnblogs.com/Creator/p/3722408.html Elasticsearc ...

  5. 如何设计一个高性能 Elasticsearch mapping

    目录 前言 mapping mapping 能做什么 Dynamic mapping dynamic=true dynamic=runtime dynamic=false dynamic=strict ...

  6. Elasticsearch教程(五) elasticsearch Mapping的创建

    一.Mapping介绍 在Elasticsearch中,Mapping是什么? mapping在Elasticsearch中的作用就是约束. 1.数据类型声明 它类似于静态语言中的数据类型声明,比如声 ...

  7. Elasticsearch节点类型

    当我们启动Elasticsearch的实例,就会启动至少一个节点.相同集群名的多个节点的连接就组成了一个集群. 在默认情况下,集群中的每个节点都可以处理http请求和集群节点间的数据传输,集群中所有的 ...

  8. 检测空值,以及会不会出现mapping类型不一致的问题

    /// <summary> /// 检测空值,以及会不会出现mapping类型不一致的问题 /// </summary> /// <typeparam name=&quo ...

  9. ES mapping可以修改include_in_all,也可以修改index_options,norm,但是无法修改_all属性!

    ES mapping可以修改include_in_all,也可以修改index_options,norm,但是无法修改_all属性! curl -XPOST "http://localhos ...

  10. Elasticsearch Date类型,时间存储相关说明

    资料 网址 Elasticsearch 插入时间字段时数据格式问题 https://segmentfault.com/a/1190000016296983 Elasticsearch Date类型,时 ...

随机推荐

  1. 利用KubeEdge在A500部署边缘推理任务

      利用KubeEdge在A500部署边缘推理任务 目  录 1 环境介绍... 1 2 云端环境部署... 2 2.1 在master节点安装Docker和k8S (ubuntu) 2 2.1.1 ...

  2. Go语言核心36讲27

    在前面的文章中,我们一起学习了Go程序测试的基础知识和基本测试手法.这主要包括了Go程序测试的基本规则和主要流程.testing.T类型和testing.B类型的常用方法.go test命令的基本使用 ...

  3. 支持 equals 相等的对象(可重复对象)作为 WeakHashMap 的 Key

    原文地址 代码地址 问题 长链接场景下通常有一个类似 Map<String, Set<Long>> 的结构,用来查找一个逻辑组内的哪些用户,String 类型的 Entry.k ...

  4. Windows自带管理工具

    exe类notepad 记事本 control 控制面板 mstsc 远程桌面连接explorer 资源管理器 taskmgr 任务管理器resmon 资源监视器 perfmon 性能监视器reged ...

  5. VS 新版本无法打开旧项目问题处理

    问题 最近想阅读 WorkflowCore 的源码,苦于代码量巨大,就想将项目回退到 Init Commit 版本 但是在回退版本后,工程内Project 显示已卸载 重新加载后 提示: 不支持 Th ...

  6. 深度解析KubeEdge EdgeMesh 高可用架构

    摘要:通过高可用特性应用场景.高可用特性使用手册.课题总结.未来展望等四个部分的内容来向大家介绍新版本EdgeMesh的高可用架构. 本文分享自华为云社区<KubeEdge EdgeMesh 高 ...

  7. C ++:树

    C++:树 树的概念: 所谓"树"是输就结构的一种,树大概可以分为两大类: 有根树 和 无根树 有根树使有一个确定的根节点,反之为无根树 · 子节点:从树根开始,通过树边向下扩展的 ...

  8. 【每日一题】【DFS/回溯】2022年1月1日-113. 路径总和 II

    给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径. 叶子节点 是指没有子节点的节点. 来源:力扣(LeetCode)链接 ...

  9. 【每日一题】2021年12月11日-69. Sqrt(x)/x的平方根

    给你一个非负整数 x ,计算并返回 x 的 算术平方根 . 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 . 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或 ...

  10. C# 操作IIS加强版(添加,删除,启动,暂停网站,默认页,绑定信息)

    C# 操作IIS加强版(添加,删除,启动,暂停网站,默认页,绑定信息) 主要功能如下 在本机的IIS创建Web网站 删除网站包括应用程序池 删除应用程序池 添加默认文档 删除默认文档 添加虚拟目录 删 ...