美文网首页ElasticSearch入门elasticsearch玩转大数据
六十三、Elasticsearch索引管理-reindex重建索

六十三、Elasticsearch索引管理-reindex重建索

作者: 编程界的小学生 | 来源:发表于2017-07-12 13:37 被阅读2729次

    **
    一个field的设置是不能被修改的,如果要修改一个field,那么应该重新按照新的mapping,建立一个index,然后将数据批量查询出来,重新用bulk api写入新index中。
    批量查询的时候,建议采用scroll api,并且采用多线程并发的方式来reindex数据,每次scroll就查询指定日期的一段数据,交给一个线程即可。
    **

    具体操作步骤:

    (1)一开始,依靠dynamic mapping,插入数据,但是不小心有些数据是2017-01-01这种日期格式的,所以ES自动将这种格式的field映射为了date类型,实际上他应该是string类型。这时候我们插入hello这类词语就会报错,因为他已经默认是date类型了

    PUT /my_index/my_type/3
    {
      "title" : "2017-01-01"
    }
    

    GET my_index/_mapping/my_type
    结果

    {
      "my_index": {
        "mappings": {
          "my_type": {
            "properties": {
              "title": {
                "type": "date"
              }
            }
          }
        }
      }
    }
    

    结果表明,ES的dynamic mapping自动将日志格式的字符串给映射为了date类型

    (2)当我们向索引中加入string类型的title值的时候就会报错

    PUT /my_index/my_type/4
    {
      "title" : "hello world"
    }
    

    返回结果

    {
      "error": {
        "root_cause": [
          {
            "type": "mapper_parsing_exception",
            "reason": "failed to parse [title]"
          }
        ],
        "type": "mapper_parsing_exception",
        "reason": "failed to parse [title]",
        "caused_by": {
          "type": "illegal_argument_exception",
          "reason": "Invalid format: \"hello world\""
        }
      },
      "status": 400
    }
    

    (3)如果此时想修改title的类型,那么是不可能的

    PUT /my_index/_mapping/my_type
    {
      "properties": {
        "title" : {
          "type": "text"
        }
      }
    }
    

    返回结果

    {
      "error": {
        "root_cause": [
          {
            "type": "illegal_argument_exception",
            "reason": "mapper [title] of different type, current_type [date], merged_type [text]"
          }
        ],
        "type": "illegal_argument_exception",
        "reason": "mapper [title] of different type, current_type [date], merged_type [text]"
      },
      "status": 400
    }
    

    结果表明:field一旦被创建就不可能被更改类型。

    (4)此时,唯一办法就是进行reindex,也就是说,重新建立一个新的索引,将旧索引的数据查询出来,再导入新索引。

    (5)如果说旧索引的名字是old_index,新索引的名字是new_index,终端java应用,已经在使用old_index在操作了,难道还要去停止线上的java应用,修改用户正在使用的index为new_index,再重启java服务吗?这个过程中,一定会导致用户正在浏览,但是突然就无法访问了的情况。

    (6)所以说,给java应用一个别名,这个别名是指向旧索引的,java应用先用着,java应用先用good_index alias来操作,此时实际指向的是旧的index(my_index)

    PUT /my_index/_alias/good_index

    此时我们去查good_index

    GET /good_index/_search
    {
      "query": {
        "match_all": {}
      }
    }
    

    返回结果:

    {
      "took": 4,
      "timed_out": false,
      "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
      },
      "hits": {
        "total": 1,
        "max_score": 1,
        "hits": [
          {
            "_index": "my_index",
            "_type": "my_type",
            "_id": "3",
            "_score": 1,
            "_source": {
              "title": "2017-01-01"
            }
          }
        ]
      }
    }
    

    结果表明:现在good_index就是my_index的别名,good_index指向了my_index。

    (7)新建一个index,调整其title的类型为string

    PUT /my_index_new
    {
      "mappings": {
        "my_type" : {
          "properties": {
            "title" : {
              "type": "string"
            }
          }
        }
      }
    }
    

    (8)使用scroll api将数据批量查询出来

    GET /my_index/_search?scroll=1m
    {
      "query": {
        "match_all": {}
      },
      "sort": ["_doc"],
      "size": 1
    }
    

    这里size:1,是因为我们没有那么多的数据。所以就模拟一下,真实场景可能成千上万,看自己的数据量了。

    返回结果

    {
      "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAASFVFnJyRk9uQ0IzUndxS094YUlleUxuVXcAAAAAAAEhVhZyckZPbkNCM1J3cUtPeGFJZXlMblV3AAAAAAABIVcWcnJGT25DQjNSd3FLT3hhSWV5TG5VdwAAAAAAASFYFnJyRk9uQ0IzUndxS094YUlleUxuVXcAAAAAAAEhWRZyckZPbkNCM1J3cUtPeGFJZXlMblV3",
      "took": 2,
      "timed_out": false,
      "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
      },
      "hits": {
        "total": 1,
        "max_score": null,
        "hits": [
          {
            "_index": "my_index",
            "_type": "my_type",
            "_id": "3",
            "_score": null,
            "_source": {
              "title": "2017-01-01"
            },
            "sort": [
              0
            ]
          }
        ]
      }
    }
    

    (9)采用bulk api将scroll查出来的一批数据,批量写入新索引

    POST /_bulk
    {"index": {"_index" : "my_index_new", "_type" : "my_type", "_id" : "3"}}
    {"title" : "2017-01-01"}
    

    (10)反复循环8~9次,查询一批又一批的数据出来,采取bulk api将每一批数据批量写入新索引

    (11)将goods_index alias切换到my_index_new上去,java应用会直接通过index别名使用心得索引中的数据,java应用程序不需要停机,零提交,高可用

    POST /_aliases
    {
      "actions" : [
        {"remove" : {"index" : "my_index", "alias" : "goods_index"}},
        {"add" : {"index" : "my_index_new", "alias" : "goods_index"}}
      ]
    }
    

    (12)直接通过goods_index别名来查询是否ok
    GET /goods_index/my_type/_search

    返回结果

    {
      "took": 1,
      "timed_out": false,
      "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
      },
      "hits": {
        "total": 1,
        "max_score": 1,
        "hits": [
          {
            "_index": "my_index_new",
            "_type": "my_type",
            "_id": "3",
            "_score": 1,
            "_source": {
              "title": "2017-01-01"
            }
          }
        ]
      }
    }
    

    大功告成!!!

    若有兴趣,欢迎来加入群,【Java初学者学习交流群】:458430385,此群有Java开发人员、UI设计人员和前端工程师。有问必答,共同探讨学习,一起进步!
    欢迎关注我的微信公众号【Java码农社区】,会定时推送各种干货:


    qrcode_for_gh_577b64e73701_258.jpg

    相关文章

      网友评论

      • fe2496cb377b:所以我理解的是,java应用程序一开始就是指定到alias index上。才是对的。
      • fe2496cb377b:“(6)所以说,给java应用一个别名,这个别名是指向旧索引的,java应用先用着,java应用先用good_index alias来操作,此时实际指向的是旧的index(my_index)”

        问题的关键在于,你怎么让java应用程序去动态的切换到alias上去啊???
        如果java应用程序不重启,肯定还是指向my_index,而不是alias(good_index)上。

      本文标题:六十三、Elasticsearch索引管理-reindex重建索

      本文链接:https://www.haomeiwen.com/subject/wnkbhxtx.html