Es索引文档全量更新与迁移

需求背景

es索引需新增字段,该字段初始值由某个旧字段确定。数据量大概1000w条文档。

两种方案:

1、直接使用update_by_query命令进行全量更新。

2、新建索引并进行全量迁移,迁移时更新新增字段的初始值。

经过测试,方案1的耗时较长(2小时左右),方案2耗时20分钟左右,所以采用方案2进行处理。

新建索引

新建目标索引

java 复制代码
PUT /tbproj_1211
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 1,
      "analysis" : {
        "normalizer" : {
          "CustomNormalizer" : {
            "filter" : [
              "lowercase",
              "asciifolding"
            ],
            "type" : "custom"
          }
        },
        "analyzer" : {
          "optimizeIK" : {
            "type" : "custom",
            "tokenizer" : "ik_max_word"
          }
        }
      }
    }
  },
  "mappings": {
    "dynamic" : "true",
    "properties" : {
      "createTime" : {
        "type" : "long",
        "coerce" : false
      },
      "creator" : {
        "type" : "keyword"
      },
      "credit" : {
        "type" : "keyword"
      },
      "dbId" : {
        "type" : "keyword"
      },
      "definition" : {
        "type" : "keyword"
      },
      "fileName" : {
        "type" : "keyword"
      },
      "fromDbId" : {
        "type" : "keyword"
      },
      "id" : {
        "type" : "keyword"
      },
      "isApproved" : {
        "type" : "keyword"
      },
      "modifiedTime" : {
        "type" : "long",
        "coerce" : false
      },
      "modifier" : {
        "type" : "keyword"
      },
      "note" : {
        "type" : "keyword"
      },
      "original" : {
        "type" : "text",
        "fields" : {
          "keyword" : {
            "type" : "keyword"
          },
          "normalizer" : {
            "type" : "keyword",
            "normalizer" : "CustomNormalizer"
          },
          "pattern" : {
            "type" : "text",
            "norms" : false,
            "analyzer" : "pattern"
          },
          "standard" : {
            "type" : "text",
            "norms" : false,
            "analyzer" : "standard"
          }
        },
        "norms" : false,
        "analyzer" : "optimizeIK"
      },
      "originalLang" : {
        "type" : "keyword"
      },
      "remark" : {
        "type" : "keyword"
      },
      "reviewTime" : {
        "type" : "long",
        "coerce" : false
      },
      "reviewer" : {
        "type" : "keyword"
      },
      "translation" : {
        "type" : "text",
        "fields" : {
          "keyword" : {
            "type" : "keyword"
          },
          "normalizer" : {
            "type" : "keyword",
            "normalizer" : "CustomNormalizer"
          },
          "pattern" : {
            "type" : "text",
            "norms" : false,
            "analyzer" : "pattern"
          },
          "standard" : {
            "type" : "text",
            "norms" : false,
            "analyzer" : "standard"
          }
        },
        "norms" : false,
        "analyzer" : "optimizeIK"
      },
      "translationLang" : {
        "type" : "keyword"
      }
    }
  }
}

迁移数据

由于数据量较大,采用全量迁移和增量迁移。全量迁移在凌晨执行,增量迁移可在发版时执行。

全量迁移

迁移脚本

java 复制代码
### 全量迁移
POST _reindex?wait_for_completion=false
{
  "conflicts": "proceed",
  "source": {
    "index": "tbproj",
    "size":10000
  },
  "dest": {
    "index": "tbproj_1211",
    "op_type": "index"
  },
  "script": {
    "lang": "painless",
    "params": {
      "lv1_terms": ["", "译员术语"],
      "lv2_terms": ["PM术语"],
      "lv3_terms": ["客户术语", "行业术语"]
    },
    "source": """
      // 处理字段不存在的情况
      if (!ctx._source.containsKey('remark')) {
        ctx._source.credit = 2;
        return;
      }
      
      def remark = ctx._source.remark;
      
      // 处理 null 值
      if (remark == null) {
        ctx._source.credit = 2;
        return;
      }
      
      String remarkStr = remark.toString();
      
      if (params.lv1_terms.contains(remarkStr)) {
        ctx._source.credit = 2;
      } else if (params.lv2_terms.contains(remarkStr)) {
        ctx._source.credit = 3;
      } else if (params.lv3_terms.contains(remarkStr)) {
        ctx._source.credit = 4;
      } else {
        ctx._source.credit = 2;
      }
    """
  }
}

执行上述命令后,会返回任务id,可根据返回的任务id查询迁移的进度。

java 复制代码
GET _tasks/ouuGEmiVSOaw2ih49hGepg:13942427

增量迁移

执行完全量迁移脚本后,可使用下方脚本继续迁移增量数据(在执行全量迁移命令后产生的数据)。

java 复制代码
### 增量迁移
POST _reindex?wait_for_completion=false
{
  "conflicts": "proceed", ###出现冲突时,继续迁移
  "source": {
    "index": "tbproj",
    "size":10000,
    "query": {
      "range": {
        "modifiedTime": {
          "gte": 1764910963831  ###执行全量迁移操作的时间
        }
      }
    }
  },
  "dest": {
    "index": "tbproj_1211",
    "op_type": "index"  ###出现冲突时,覆盖已有数据
  },
  "script": {
    "lang": "painless",
    "params": {
      "lv1_terms": ["", "译员术语"],
      "lv2_terms": ["PM术语"],
      "lv3_terms": ["客户术语", "行业术语"]
    },
    "source": """
      // 处理字段不存在的情况
      if (!ctx._source.containsKey('remark')) {
        ctx._source.credit = 2;
        return;
      }
      
      def remark = ctx._source.remark;
      
      // 处理 null 值
      if (remark == null) {
        ctx._source.credit = 2;
        return;
      }
      
      String remarkStr = remark.toString();
      
      if (params.lv1_terms.contains(remarkStr)) {
        ctx._source.credit = 2;
      } else if (params.lv2_terms.contains(remarkStr)) {
        ctx._source.credit = 3;
      } else if (params.lv3_terms.contains(remarkStr)) {
        ctx._source.credit = 4;
      } else {
        ctx._source.credit = 2;
      }
    """
  }
}

删除索引

迁移完成后,校验数据完整性,校验通过后可删除旧索引(如果不需要新索引名称与旧索引名称一致,可不用删除)

java 复制代码
DELETE /tbproj

创建别名

旧索引删除后,可为新索引创建和旧索引名称一致的别名,后续就可以继续使用旧索引名称进行相关操作。

java 复制代码
###查看已有别名
GET /tbproj_1211/_alias
###创建或删除别名
POST _aliases
{
  "actions": [
    {
      "add": { ###创建别名
        "index": "tb_1211",
        "alias": "tb"
      }
    },
    {
      "add": {
        "index": "tbproj_1211",
        "alias": "tbproj"
      }
    },
    {
      "remove": { ###删除别名
        "index": "tbproj_1211",
        "alias": "tbproj_01"
      }
    }
  ]
}
相关推荐
说私域15 小时前
AI智能名片S2B2C商城小程序在微商中的应用与影响
大数据·人工智能·小程序·流量运营
2501_9443321616 小时前
如何联系北京的金融业务流程外包服务商?
大数据·人工智能·金融
CHrisFC16 小时前
环境第三方检测机构LIMS系统选型:从合规基础到效率制胜
java·大数据·人工智能
小五传输16 小时前
探秘主流的内外网文件传输方式,解锁高效安全共享新途径
大数据·运维·安全
易晨 微盛·企微管家16 小时前
2025企业微信AI智能机器人实战指南:3步实现客服自动化
大数据·人工智能·算法
Hello.Reader16 小时前
Flink DataGen SQL Connector 本地造数、压测、边界数据与“像真数据”的生成技巧
大数据·sql·flink
安河桥畔16 小时前
Git使用
大数据·git·elasticsearch
小北方城市网16 小时前
MyBatis 进阶实战:插件开发与性能优化
数据库·redis·python·elasticsearch·缓存·性能优化·mybatis
Hello.Reader16 小时前
Flink SQL 压测最短闭环Print 验证正确性 + BlackHole 榨干性能上限(附 Join/Agg/TopN/UDF 模板)
大数据·sql·flink
驾数者16 小时前
Flink SQL CDC实时同步:基于Debezium的变更数据捕获
大数据·sql·flink