Elasticserch 5.6到Elasticsearch7.11跨版本升级踩坑记录

Elasticserch 5.6到Elasticsearch7.11跨版本升级踩坑记录

1.背景

公司老的业务使用的是Elasticsearch5.6版本,使用的客户端是TransportClient,java集成的SDK,由于老版本的Elasticsearch不支持加密操作,由于日前网络安全显得很重要,所以需要对索引库进行加密,保证数据的正确性,所以一个工程中要兼容两个版本的Elasticsearch,且能够通过读取环境变量来选择执行哪套代码,所以有了下面这些坑。

2.过程

2.1 安装Elasticsearch7.11和对应版本的分词器

要使用Elasticsearch7.11首先需要做的是从官方下载安装包,然后进行安装,如果需要安装分词器的话可以去Gitlub下载一些开源的分词器,像现在开源的比较流行的是lc-pinyin ,pinyin,ik分词器,再装elasticsearch分词器的时候切记分词器的版本一定要与安装的elasticsearch7.11的版本保持一致,elasticsearch会通过读取plugin-descriptor.properties这个文件中的信息来判断安装分词器的版本,具体的源码可以去gitlub上下,据我所知pinyin这个分词器的版本只更新到了5.6版本,如果要在Elasticsearch7.11中使用肯定是不行的,可以自己将代码下载下来,修改pom文件的jar包版本然后打成jar,最后修改plugin-descriptor.properties中的配置,再上传到elasticsearch7.11目录的plugin目录下,以普通用户启动elasticsearch,用root权限启动elasticsearch会报错,具体的安装步骤网上有很多资料,这里不再叙述

2.2 创建索引

1.Elasticsearch5.6到Elasticsearch7.11.1最大的改变其实是去除了type这个类型,统一文档类型为_doc,但是这个改变从Elasticsearch7.0就开始了,之所以使用Elasticsearch7.11.1主要是因为支持加密并且开源不收费,而7.9以前都是要收费的,当然你可以去申请免费的,大概有效期是30天,如果是个人用户,其实可以更改代码里面的配置来实现永久,但是用于商业最好还是不要用。

2.创建索引主要遇到以下问题

1.当把Elasticsearch5.6中mapping放到Elasticsarch7.11中创建会出现以下问题

{"error":{"root_cause":[{"type":"mapper_parsing_exception","reason":"Root mapping definition has unsupported parameters:

在这里插入图片描述

出现上述问题的根本原因是由于Elasticsearch去除了type这个概念,默认都是_doc,只要把doc这个属性去掉就可以了。

2.当我们把doc这个属性去掉以后,再创建索引,然后又出来新来的问题

{"error":{"root_cause":[{"type":"mapper_parsing_exception","reason":"Root mapping definition has unsupported parameters:  [_all : {enabled=false}]"}]

在这里插入图片描述

看错误我们知道是不支持_all这个属性,原来Elasticsearch7.11把__all这个属性去除了,然后我们再把_all这个去除掉再执行

3.当我们把_all这个属性去除掉后,然后再创建索引,新的问题又来了

{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"The difference between max_gram and min_gram in NGram Tokenizer must be less than or equal to: [1] but was [19]

出现这个问题的主要原因是因为,我们设置分词器的时候最大分词和最小分词大于1,由于公司问题只能截取部分图片
在这里插入图片描述

解决方案其实也很简单,只要将最大和最小的在setting中设置成我们相差的就可以,如下图
在这里插入图片描述

2.3思考兼容方案

1.实际上方案我是探索了三四个方案,第一个方案是做一个新的工程,但是由于新的工程后期比较难维护,所以被否掉了,然后就是将Elasticsearch7.11的java的SDk导入gradle会出现在冲突,由于Rest-high-level-client和Transportclient中的类名和包名都是一致的,导致jvm虚拟机不知道加载哪一个类,所以我们采用的是自定义类加载器的方式,通过配置去决定加载哪个版本的jar包,自定义加载器肯定是会有很多不可规避的问题,像一些轮子其实都已经搞了,但是找了半天都没有gradle的都是基于maven的,像蚂蚁金服的SOFAArk和shade还有滴滴的JuShaTa看了很多但是就是没有合适自己的方案,尝试自己写类加载器,写了两天就放弃了,毕竟对于我这种刚毕业的小白,让我写类加载器肯定是有点困难的,怎么办?

2.突然有一天我突发奇想,本身不管是TransportClient和RestHigh-level的Client底层都是用的json的格式去访问Elasticseasrch的,于是我就将TransportClient生成的查询语句用Elasticsearch7.11查询结果发现各种报错,Elasticsearch7.11竟然还剔除了一些查询字段,就连返回结果的格式都变了,我真的是想骂人了。

3.于是我又换了种思考方式,ElasticSearch不是可以通过http请求直接访问吗,我可不可以直接自己调用http请求的来返回结果呢,当我准备做的时候,我说出了我的想法,没想到公司的架构说Elasticsearch低版本的也有Rest-Client可以发送http请求,但是我真的是感慨自己还是要好好学习,再经过讨论,以及公司其他项目组有人用过这种方式的时候准备尝试

2.4尝试

1.思考

在业务逻辑改动不大的情况下,实现两个版本的兼容,怎么说呢,这个工程师个tomcat工程,说实话老工程就是这么恶心,如果自己再把组装查询语句工作量肯定很大,从时间成本上和后期维护上来看肯定是不行的,于是我又灵机一动,直接把生成的查询语句发送http请求不就好了,再把放回的结果写成一个公用的方法来解析不就好了

2.踩坑

尝试避免不了采坑,TransportClient java SDK生成的查询语句中,BoolQueryBuilder这个类中每次生成的时候都会带上adjust_pure_negative这个属性

{
  "bool" : {
    "should" : [
      {
        "match_phrase" : {
          "robotName" : {
            "query" : "kafka",
            "slop" : 0,
            "boost" : 1.0
          }
        }
      },
      {
        "match" : {
          "pinyin" : {
            "query" : "kafka",
            "operator" : "AND",
            "prefix_length" : 0,
            "max_expansions" : 50,
            "fuzzy_transpositions" : true,
            "lenient" : false,
            "zero_terms_query" : "NONE",
            "boost" : 1.0
          }
        }
      }
    ],
    "disable_coord" : false,
    "adjust_pure_negative" : true,
    "boost" : 1.0
  }
}

从网上查看这个属性好像作用也不是很大默认是false,当是true的时候主要是怕查询must_not的时候没有数据返回,而做的一种优化,软用没有,但是怎么剔除呢,中途我有想过转换成JSONObject然后取剔除,但是由于层级是不清楚的,采用递归的方式可能会出现栈深度过大而导致出问题,然后就是过程实在是太复杂,果断放弃

3.灵感

记得那天我干到8点还没吃饭,下去吃饭的时候边吃饭边想,果然吃饱了饭,有了灵感,这个东西本身也是一个String,可不可以将他替换呢,吃完饭上来试了一下,结果替换不了,实在太晚了后面就回去了,然后第二天来了给组长讲了我的方法,然后组长给了一点提示,自己经过慢慢试错,最后得出了下面的正则表达式,这下面代码才是精髓,完美的剔除了所有的这个字段,然后取Elasticsearch中查询没有报错,测试了20多个接口都正常

    static  final String check="\"disable_coord\"\\s:\\sfalse,\n\\s+";
    static Pattern pattern=Pattern.compile(check);

4.迁移数据

数据量小的情况下我是使用reindex的方式供自己测试使用,因为公司有运维,大的话可以采用logstatch的方式

下面给出迁移数据的curl

curl --location --request POST 'http://192.168.22.92:9700/_reindex?pretty' \  -目标机器的http端口
--header 'Authorization: Basic ZWxhc3RpYzpLaW5nZGVlQDIwMjE=' \    -elasticsearch 集群的用户名 密码
--header 'Content-Type: application/json' \
--data-raw '{
    "conflicts": "proceed",
    "source": {
        "remote": {
            "host": "http://192.168.22.92:9200/"  -源机器
        },
        "index": "textmessage",  -需要迁移的索引
        "query": {
            "term": {
                "_type": "doc"     -匹配类型
            }
        },
        "size": 6000
    },
    "dest": {
        "index": "textmessage"    -目标索引
    },
    "script": {
        "inline": "if (ctx._id.length()>512) {ctx._id = ctx._id.substring(0,511)}", -防止id过长报错进行截取
        "lang": "painless"
    }
}'

5.插曲

那天和和运维一起玩Elasticsearch,结果他把elasticsearch的索引全部干掉了,然后通过密码去连接报错,显示没有权限,但是密码还是那个密码,为什么会把错了,原来Elasticsearch将用户的账号和密码保存到一个叫.security这个索引中,删除全部索引会把这个索引也删除掉,所以当你装了x-pack的时候鉴权就会失败,需要重新创建一个用户,让我很懵的是Elasticsearch竟然没有做校验直接将索引删了,Elasticsearch还是有一点比较好的,当磁盘空间不足的时候,Elasticsearch会开启自我保护措施,只能读不能写,这点做的还是做的挺好的

3.总结

当你装了x-pack的时候鉴权就会失败,需要重新创建一个用户,让我很懵的是Elasticsearch竟然没有做校验直接将索引删了,Elasticsearch还是有一点比较好的,当磁盘空间不足的时候,Elasticsearch会开启自我保护措施,只能读不能写,这点做的还是做的挺好的

3.总结

开发是一个很有趣的过程,刚开始的时候我很不情愿,老是怕,但是思考又是一个很令人兴奋的事情,特别是当你想到一个灵感的时候,只有不断的学习才能提高自己,通过这件事情我学到了很多的,分析的问题不要将事情想的太复杂,如果一开始你就怕那肯定解决不了问题,要敢于尝试,将问题拆分开,比如我写那个正则表达式的时候,特别想一步到位就写出来,本身对那个就不熟,所以写不出来,只有理智分析问题,把问题拆分开来看,一步一步来最后只要方向对了都能够解决问题,写这个完全是记录自己工作中踩过的一些坑,菜鸡一枚勿喷!


版权声明:本文为qq_45136592原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。