elasticsearch8.x如何优雅的实现字段名称批量修改?

铭毅天下 铭毅天下     2023-03-13     120

关键词:

1、线上实战问题

写入es前,数据格式如下

"json_lbm_01":"test01","json_lbm_02":"test02","tmp_lbm_01":"test03","tmp_lbm_02":"test04"

需求:单纯用pipeline可不可以实现,如果写入key包含json_提换为空,包含tmp提换为core,因为key字段有很多不考虑穷举,最终效果要如下:


  "lbm_01":"test01",
  "lbm_02":"test02",
  "core_lbm_01":"test03",
  "core_lbm_02":"test04"

——问题来源:死磕Elasticsearch知识星球 https://t.zsxq.com/0bzWL3w1X

2、认知前提

Elasticsearch mapping 一旦创建是不允许修改的!允许更新 mapping 的地方是几个特殊的点,可以参见:Elasticsearch 可以更改 Mapping 吗?如何修改?

除此之外的 mapping 层面尤其字段层面想要修改需要转换思路。

3、Mapping 字段非要修改,以满足业务需求怎么搞?

看开篇问题,本质上属于建模问题,应该建模阶段处理好,后期就不存在这个问题,这点期望大家可以达成共识。

关于Elasticsearch 数据建模的重要性,推荐参考:

干货 | Elasticsearch 数据建模指南

针对开篇问题,考虑如下的解决方案:

3.1 方案一,字段别名实现。

字段别名 field-alias 区别于索引别名 alias。

索引别名大家都比较熟悉,字段别名听到的多,但是实际用的不见得有那么多。

字段别名是 Elasticsearch 6.4 版本新上的功能,具体参见:

https://www.elastic.co/cn/blog/introducing-field-aliases-in-elasticsearch

因为一般前期建模做足功课,后面环节就不需要了。

  • 优点:已有mapping保持不动,只是在其基础上做了更新操作。

  • 缺点:批量1000个字 段,需要构造1000个字段的mapping,其实可以 脚本实现。

实操参考:

POST mytxindex-20230303/_bulk
"index":"_id":1
"json_lbm_01":"test01","json_lbm_02":"test02","tmp_lbm_01":"test03","tmp_lbm_02":"test04"


PUT mytxindex-20230303/_mapping

    "properties": 
      "lbm_01": 
        "type": "alias",
        "path": "json_lbm_01"
      ,
      "lbm_02": 
        "type": "alias",
        "path": "json_lbm_02"
      ,
      "core_lbm_01": 
        "type": "alias",
        "path": "tmp_lbm_01"
      ,
      "core_lbm_02": 
        "type": "alias",
        "path": "tmp_lbm_02"
      
    


POST mytxindex-20230303/_search

  "query": 
    "match": 
      "lbm_01": "test01"
    
  

召回结果数据如下截图所示:

3.2 方案二,重新建模,然后 reindex 操作实现。

核心点介绍如下:

  1. 优先推荐使用模板 template,解决了字段名称相似的模板化匹配问题。 

  2. 预处理管道实现分两块:

  • 其一,script 实现了新旧字段的赋值;

  • 其二,remove 移除了不必要的老字段。 

优点:这种操作比较常见,中规中矩。

缺点:需要 reindex 迁移索引数据,且在迁移的时候做预处理操作。

具体实现如下:

#### step1:创建模板,有了模板,字段一键搞定
PUT _index_template/mytx_template_20230303

  "index_patterns": [
    "mytx_new_*"
  ],
  "template": 
    "settings": 
      "number_of_shards": 1
    ,
    "mappings": 
      "dynamic_templates": [
        
          "lbm_to_keyword": 
            "match_mapping_type": "string",
            "match": "lbm_*",
            "mapping": 
              "type": "keyword"
            
          
        ,
        
          "core_lbm_to_keyword": 
            "match_mapping_type": "string",
            "match": "core_lbm_*",
            "mapping": 
              "type": "keyword"
            
          
        
      ]
    
  


#### step2:创建预处理管道
PUT _ingest/pipeline/mytx_pipeline_20230303

  "processors": [
    
      "script": 
        "source": """
        ctx.lbm_01 = ctx.json_lbm_01;
        ctx.lbm_02 = ctx.json_lbm_02;
        ctx.core_lbm_01 = ctx.tmp_lbm_01;
        ctx.core_lbm_02 = ctx.tmp_lbm_02;
        """,
        "lang": "painless"
      
    ,
    
      "remove": 
        "field": [
          "json_lbm_01",
          "json_lbm_02",
          "tmp_lbm_01",
          "tmp_lbm_02"
        ],
        "if": "ctx.json_lbm_01 != null && ctx.json_lbm_02 != null && ctx.tmp_lbm_01 != null && ctx.tmp_lbm_02 != null"
      
    
  ]


#### step3:数据迁移操作
POST _reindex

  "source": 
    "index": "mytxindex-20230303"
  ,
  "dest": 
    "index": "mytx_new_001",
    "pipeline": "mytx_pipeline_20230303"
  


#### step4:执行检索
POST mytx_new_001/_search

召回结果如下图所示:

3.3 方案三:解决遍历问题的终极方案

方案一、方案二都解决不了 N 个字段的问题。

假设有多个字段,不想一个字段一个字段的复制处理,也不想借助第三方脚本如shell 或者 python 处理。

那有没有更好的方案呢?方案三基于字段遍历实现,字段无非是 key:value 组合。

先通过:entry.getKey( )获取 key,然后基于 key 做逻辑判定,构造新的key,然后将旧value 复制给新 key。

最后,通过 putAll 更新。

PUT _ingest/pipeline/rename_fields_pipeline

  "processors": [
    
      "script": 
        "source": """
          def new_fields = [:];
          for (entry in ctx.entrySet()) 
            String key = entry.getKey();
            if (key.startsWith('json_')) 
              key = key.replace('json_', '');
             else if (key.startsWith('tmp_')) 
              key = 'core_' + key.replace('tmp_', '');
            
            new_fields[key] = entry.getValue();
          
          ctx.clear();
          ctx.putAll(new_fields);
        """
      
    
  ]



POST _reindex

  "source": 
    "index": "mytxindex-20230303"
  ,
  "dest": 
    "index": "mytx_new_002",
    "pipeline": "rename_fields_pipeline"
  

最终执行结果如下,和预期一致。

4、小结

类似问题即便给出了3种不同的实现方案,都能达到给定的业务需求。

但,仍然不建议业务中后期这么处理。更优的解决方案,推荐借助 Elasticsearch 建模阶段做好规划,避免中后期的类似上述问题的涉及大量数据迁移的大的改动。

更多实践想法,欢迎大家一起交流!!!

推荐阅读

  1. 全网首发!从 0 到 1 Elasticsearch 8.X 通关视频

  2. 重磅 | 死磕 Elasticsearch 8.X 方法论认知清单(2022年国庆更新版)

  3. 如何系统的学习 Elasticsearch ?

  4. 2023,做点事

更短时间更快习得更多干货!

和全球近 1900+ Elastic 爱好者一起精进!

比同事抢先一步学习进阶干货!

elasticsearch8.x如何动态的为正文添加摘要字段?

1、实战问题返回指定字段可以用:"_source":     "includes": [      *    ],    "excludes": [      "a"    ]  那有没有什么办法在返回指定字段的基础上指定返回前50个字符呢?例如我现在... 查看详情

elasticsearch8.x如何动态的为正文添加摘要字段?

1、实战问题返回指定字段可以用:"_source":     "includes": [      *    ],    "excludes": [      "a"    ]  那有没有什么办法在返回指定字段的基础上指定返回前50个字符呢?例如我现在... 查看详情

elasticsearch8.x如何动态的为正文添加摘要字段?

1、实战问题返回指定字段可以用:"_source":     "includes": [      *    ],    "excludes": [      "a"    ]  那有没有什么办法在返回指定字段的基础上指定返回前50个字符呢?例如我现在... 查看详情

jmeter如何实现elasticsearch8.x性能测试?

1、Elasticsearch性能测试工具包含但不限于:1、rallyElasticsearch官方压测工具。下载地址:https://github.com/elastic/rally文档地址:https://esrally.readthedocs.io/en/stable/2、LoadgenElasticsearch专属压测工具,Medcl 查看详情

jmeter如何实现elasticsearch8.x性能测试?

1、Elasticsearch性能测试工具包含但不限于:1、rallyElasticsearch官方压测工具。下载地址:https://github.com/elastic/rally文档地址:https://esrally.readthedocs.io/en/stable/2、LoadgenElasticsearch专属压测工具,Medcl 查看详情

jmeter如何实现elasticsearch8.x性能测试?

1、Elasticsearch性能测试工具包含但不限于:1、rallyElasticsearch官方压测工具。下载地址:https://github.com/elastic/rally文档地址:https://esrally.readthedocs.io/en/stable/2、LoadgenElasticsearch专属压测工具,Medcl 查看详情

一个线上问题引发的思考——elasticsearch8.x如何实现更精准的检索?

1、线上问题——问题来自:死磕Elasticsearch知识星球微信群这个问题涉及到业务细节,至今没有定论。不过,该问题引发了我的思考。2、我的一点思考我们使用Elasticsearch到底用来做什么?除了Elasticsearch早已不是10... 查看详情

一个线上问题引发的思考——elasticsearch8.x如何实现更精准的检索?

1、线上问题——问题来自:死磕Elasticsearch知识星球微信群这个问题涉及到业务细节,至今没有定论。不过,该问题引发了我的思考。2、我的一点思考我们使用Elasticsearch到底用来做什么?除了Elasticsearch早已不是10... 查看详情

图解:elasticsearch8.x如何求解环比上升比例?(代码片段)

1、企业级Elasticsearch8.X实战问题问题描述:有个聚合的需求,问下大家,一个索引中有时间字段要求计算本月和上月相比的环比上升比例?——来自GPVIP群2、问题释义2.1啥叫环比?环比是统计学术语,表示... 查看详情

logstash:如何配置metricbeat及logstash为elasticsearch8.x收集数据

如何配置Metricbeat及Logstash为Elasticsearch8.0收集数据如何配置Metricbeat及Logstash为Elasticsearch8.0收集数据_哔哩哔哩_bilibili 查看详情

图解:elasticsearch8.x如何求解环比上升比例?(代码片段)

1、企业级Elasticsearch8.X实战问题问题描述:有个聚合的需求,问下大家,一个索引中有时间字段要求计算本月和上月相比的环比上升比例?——来自GPVIP群2、问题释义2.1啥叫环比?环比是统计学术语,表示... 查看详情

elasticsearch:如何在docker上运行elasticsearch8.x进行本地开发(代码片段)

对于Elasticsearch的新主要版本(8.x.x),有关于在Docker上运行Elasticsearch和Kibana的重大更新。过去适用于以前版本的Docker和DockerCompose的命令和语法需要更新才能适用于最新版本。在这篇文章中,我们将介绍如何使用Docker和DockerC... 查看详情

elasticsearch8.x防止mapping“爆炸”的三种方案

1、什么是Mapping“爆炸”?Elasticsearch映射如果不做特殊处理,默认dynamic为true。dynamic为true的确切含义是:根据导入的数据自定识别字段类型(有可能不精确),也就是说,可以提前不指定Mapping,也... 查看详情

elasticsearch8.x防止mapping“爆炸”的三种方案

1、什么是Mapping“爆炸”?Elasticsearch映射如果不做特殊处理,默认dynamic为true。dynamic为true的确切含义是:根据导入的数据自定识别字段类型(有可能不精确),也就是说,可以提前不指定Mapping,也... 查看详情

干货|elasticsearch8.x版本升级指南

1、Elasticsearch版本升级常见问题问题1:我现在集群是:5.X、6.X、7.X,要不要升级?问题2:版本跨度这么大,如何升级?7月6日,读者凌晨00:30留言:“怎么不出升级的文章呢?需求比较迫切&#... 查看详情

elasticsearch-elasticsearch8.x;elasticsearch8.x集群(代码片段)

阅读本文前可先参考Elasticsearch-Elasticsearch详解;安装部署(一)_MinggeQingchun的博客-CSDN博客Elasticsearch-Elasticsearch集群Cluster(三)_MinggeQingchun的博客-CSDN博客一、Elasticsearch8.X 距2019年Elast 查看详情

elasticsearch:如何在docker上运行elasticsearch8.x进行本地开发(代码片段)

对于Elasticsearch的新主要版本(8.x.x),有关于在Docker上运行Elasticsearch和Kibana的重大更新。过去适用于以前版本的Docker和DockerCompose的命令和语法需要更新才能适用于最新版本。在这篇文章中,我们将介绍如何使用Docker和DockerC... 查看详情

elasticsearch8.x有哪些自动补全的检索方式?(代码片段)

1、自动补全或前缀匹配检索实现效果图Elasticsearch能实现自动补全检索的方案很多,可以简单归结为如下几种不同的方案:方案一:Prefix前缀匹配检索。方案二:MatchPhraseprefix短语前缀匹配检索。方案三:更细... 查看详情