当前位置:   article > 正文

Elasticsearch 8.X 如何优雅的实现字段名称批量修改?

批量修改es字段

1、线上实战问题

写入es前,数据格式如下

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

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

  1. {
  2.   "lbm_01":"test01",
  3.   "lbm_02":"test02",
  4.   "core_lbm_01":"test03",
  5.   "core_lbm_02":"test04"
  6. }

——问题来源:死磕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,其实可以 脚本实现。

实操参考:

  1. POST mytxindex-20230303/_bulk
  2. {"index":{"_id":1}}
  3. {"json_lbm_01":"test01","json_lbm_02":"test02","tmp_lbm_01":"test03","tmp_lbm_02":"test04"}
  4. PUT mytxindex-20230303/_mapping
  5. {
  6.     "properties": {
  7.       "lbm_01": {
  8.         "type""alias",
  9.         "path""json_lbm_01"
  10.       },
  11.       "lbm_02": {
  12.         "type""alias",
  13.         "path""json_lbm_02"
  14.       },
  15.       "core_lbm_01": {
  16.         "type""alias",
  17.         "path""tmp_lbm_01"
  18.       },
  19.       "core_lbm_02": {
  20.         "type""alias",
  21.         "path""tmp_lbm_02"
  22.       }
  23.     }
  24. }
  25. POST mytxindex-20230303/_search
  26. {
  27.   "query": {
  28.     "match": {
  29.       "lbm_01""test01"
  30.     }
  31.   }
  32. }

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

a45c2ee551389d29e1ddd16e5d3a575a.png

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

核心点介绍如下:

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

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

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

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

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

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

具体实现如下:

  1. #### step1:创建模板,有了模板,字段一键搞定
  2. PUT _index_template/mytx_template_20230303
  3. {
  4.   "index_patterns": [
  5.     "mytx_new_*"
  6.   ],
  7.   "template": {
  8.     "settings": {
  9.       "number_of_shards"1
  10.     },
  11.     "mappings": {
  12.       "dynamic_templates": [
  13.         {
  14.           "lbm_to_keyword": {
  15.             "match_mapping_type""string",
  16.             "match""lbm_*",
  17.             "mapping": {
  18.               "type""keyword"
  19.             }
  20.           }
  21.         },
  22.         {
  23.           "core_lbm_to_keyword": {
  24.             "match_mapping_type""string",
  25.             "match""core_lbm_*",
  26.             "mapping": {
  27.               "type""keyword"
  28.             }
  29.           }
  30.         }
  31.       ]
  32.     }
  33.   }
  34. }
  35. #### step2:创建预处理管道
  36. PUT _ingest/pipeline/mytx_pipeline_20230303
  37. {
  38.   "processors": [
  39.     {
  40.       "script": {
  41.         "source""""
  42.         ctx.lbm_01 = ctx.json_lbm_01;
  43.         ctx.lbm_02 = ctx.json_lbm_02;
  44.         ctx.core_lbm_01 = ctx.tmp_lbm_01;
  45.         ctx.core_lbm_02 = ctx.tmp_lbm_02;
  46.         """,
  47.         "lang""painless"
  48.       }
  49.     },
  50.     {
  51.       "remove": {
  52.         "field": [
  53.           "json_lbm_01",
  54.           "json_lbm_02",
  55.           "tmp_lbm_01",
  56.           "tmp_lbm_02"
  57.         ],
  58.         "if""ctx.json_lbm_01 != null && ctx.json_lbm_02 != null && ctx.tmp_lbm_01 != null && ctx.tmp_lbm_02 != null"
  59.       }
  60.     }
  61.   ]
  62. }
  63. #### step3:数据迁移操作
  64. POST _reindex
  65. {
  66.   "source": {
  67.     "index""mytxindex-20230303"
  68.   },
  69.   "dest": {
  70.     "index""mytx_new_001",
  71.     "pipeline""mytx_pipeline_20230303"
  72.   }
  73. }
  74. #### step4:执行检索
  75. POST mytx_new_001/_search

召回结果如下图所示:

94ad56acdca9cad54943ddaf45ea1ea9.png

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

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

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

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

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

最后,通过 putAll 更新。

  1. PUT _ingest/pipeline/rename_fields_pipeline
  2. {
  3.   "processors": [
  4.     {
  5.       "script": {
  6.         "source""""
  7.           def new_fields = [:];
  8.           for (entry in ctx.entrySet()) {
  9.             String key = entry.getKey();
  10.             if (key.startsWith('json_')) {
  11.               key = key.replace('json_', '');
  12.             } else if (key.startsWith('tmp_')) {
  13.               key = 'core_' + key.replace('tmp_', '');
  14.             }
  15.             new_fields[key] = entry.getValue();
  16.           }
  17.           ctx.clear();
  18.           ctx.putAll(new_fields);
  19.         """
  20.       }
  21.     }
  22.   ]
  23. }
  24. POST _reindex
  25. {
  26.   "source": {
  27.     "index""mytxindex-20230303"
  28.   },
  29.   "dest": {
  30.     "index""mytx_new_002",
  31.     "pipeline""rename_fields_pipeline"
  32.   }
  33. }

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

af3fe620503eb38723e65140c7914eea.png

4、小结

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

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

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

推荐阅读

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

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

  3. 如何系统的学习 Elasticsearch ?

  4. 2023,做点事

bbf4e39ceb5ed93800ef3ebd2a02ef63.jpeg

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

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

a9817433353a35254b558ae1f9109236.gif

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

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号