Elasticsearch Mapping类型修改
背景
通常数据库进行分库分表后,目前比较常规的作法,是通过将数据异构到Elasticsearch来提供分页列表查询服务;在创建Elasticsearch索引时,基本都是会参考目前的业务需求、关系数据库中的类型以及对数据的相关规划来定义相关字段mapping的类型.
在Elasticsearch的mapping中的列(或则叫属性),有几个比较重要的参数(更多参数参考官方文档)
列类型:
type
指定了该列的数据类型,常用的有
text
,keyword
,date
,long
,double
,boolean
以及object
和nested
,不同的类型也有对应的不同查询方式,创建之后是不能修改的;是否可索引:
index
该
index
选项控制字段值是否被索引。它接受true
orfalse
,并且默认为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
- 可以将应用系统中的配置改成新索引
- 也可以通过索引的别名的方式为新索引增加原来老索引的别名来操作,为索引增加别名参考文档: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
基本是一样的,只是创建列的方式不同,优缺点都一样;
参考资料
- [1] 【官方文档】Mapping parameters
- [2] 【官方文档】Mapping Field datatypes
- [3] [【官方文档】multi-fields] (https://www.elastic.co/guide/en/elasticsearch/reference/7.5/multi-fields.html)
- [4] Elasticsearch Rename Index
- [5] elasticSearch7.x—mapping中的fields属性||copy_to配置(同一个字段两种类型)
- [6] 《Elasticsearch:权威指南》Mapping -- Mapping parameters -- fields(multi-fields)
Elasticsearch Mapping类型修改的更多相关文章
- Elasticsearch 的坑爹事——记录一次mapping field修改过程
Elasticsearch 的坑爹事 本文记录一次Elasticsearch mapping field修改过程 团队使用Elasticsearch做日志的分类检索分析服务,使用了类似如下的_mapp ...
- Elasticsearch 的坑爹事——记录一次mapping field修改过程(转)
原文:http://www.cnblogs.com/Creator/p/3722408.html 本文记录一次Elasticsearch mapping field修改过程 团队使用Elasticse ...
- (转)Elasticsearch 的坑爹事——记录一次mapping field修改过程
Elasticsearch 的坑爹事 本文记录一次Elasticsearch mapping field修改过程 团队使用Elasticsearch做日志的分类检索分析服务,使用了类似如下的_mapp ...
- ES mapping field修改过程
Elasticsearch 的坑爹事--记录一次mapping field修改过程 http://www.cnblogs.com/Creator/p/3722408.html Elasticsearc ...
- 如何设计一个高性能 Elasticsearch mapping
目录 前言 mapping mapping 能做什么 Dynamic mapping dynamic=true dynamic=runtime dynamic=false dynamic=strict ...
- Elasticsearch教程(五) elasticsearch Mapping的创建
一.Mapping介绍 在Elasticsearch中,Mapping是什么? mapping在Elasticsearch中的作用就是约束. 1.数据类型声明 它类似于静态语言中的数据类型声明,比如声 ...
- Elasticsearch节点类型
当我们启动Elasticsearch的实例,就会启动至少一个节点.相同集群名的多个节点的连接就组成了一个集群. 在默认情况下,集群中的每个节点都可以处理http请求和集群节点间的数据传输,集群中所有的 ...
- 检测空值,以及会不会出现mapping类型不一致的问题
/// <summary> /// 检测空值,以及会不会出现mapping类型不一致的问题 /// </summary> /// <typeparam name=&quo ...
- ES mapping可以修改include_in_all,也可以修改index_options,norm,但是无法修改_all属性!
ES mapping可以修改include_in_all,也可以修改index_options,norm,但是无法修改_all属性! curl -XPOST "http://localhos ...
- Elasticsearch Date类型,时间存储相关说明
资料 网址 Elasticsearch 插入时间字段时数据格式问题 https://segmentfault.com/a/1190000016296983 Elasticsearch Date类型,时 ...
随机推荐
- gin领域层:用户实体编写和值对象(初步)
1.用户实体和值对象 2. 要做的事 3.常见的四层模型 4.Domin层 5.值对象
- labuladong
由于 labuladong 的算法网站频繁被攻击,且国内访问速度可能比较慢,所以本站同时开放多个镜像站点: https://labuladong.gitee.io/algo/ https://labu ...
- 1、Docker最新入门教程-Docker概述
1. Docker概述 Docker 是一个用于开发.运输和运行应用程序的开放平台.Docker 使您能够将应用程序与基础架构分开,以便您可以快速交付软件.使用 Docker,您可以像管理应用程序一样 ...
- combotree 的简单使用2
上一次我在 combotree 的简单使用 中介绍了一种combotree的写法,不过有一个缺点,就是当输的结构非常大的时候,分级较多时,消耗内存的现象会比较严重,下面介绍的一种方法,使combotr ...
- WeetCode3 暴力递归->记忆化搜索->动态规划
笔者这里总结的是一种套路,这种套路笔者最先是从左程云的b站视频学习到的 本文进行简单总结 系列文章目录和关于我 一丶动态规划的思想 使用dp数组记录之前状态计算的最佳结果,找出当前状态和之前状态的关系 ...
- 【每日一题】【上右下左模拟&while循环体条件不满足时】54.螺旋矩阵-211110/220204
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素. 解答:while循环内部不满足也会继续走到结尾 import java.util.ArrayList; ...
- 【笔面试题目】Java集合相关的面试题-List、Map、Set等
一.List 1.subList 不会返回新的list对象--与String的subString不同 返回原来list的从[fromIndex,toIndex)之间这一部分的视图,实际上,返回的lis ...
- 【每日一题】2021年12月6日-剑指 Offer 22. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点.为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点. 例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1.2.3.4.5.6 ...
- C#多线程(四)并行编程篇之结构化
前言 在前三章中我们的案例大量使用到了Thread这个类,通过其原始API,对其进行创建.启动.中断.中断.终止.取消以及异常处理,这样的写法不仅不够优雅(对接下来这篇,我称其为.NET现代化并行编程 ...
- 使用linux的ffmpeg进行B站直播推流
很久之前买了个友善的开发板R2S,一直在家吃灰.最近看到网上有用ffmpeg进行直播推流的案例,想把吃灰的的开发板利用起来,于是有了这篇教程. 第一步:安装ffmpeg sudo apt update ...