1. 使用场景

  • 一般以下几种情况时,需要重建索引:

    • 索引的 Mapping 发生变更:字段类型更改,分词器、字典更新
    • 索引的 Settings 发生变更:索引的主分片数发生改变
    • 集群内,集群间需要做数据迁移
  • Elasticsearch 的内置提供的 API

    • Update By Query:在现有索引上重建
    • ReIndex:在其他索引上重建索引

2. 案例1:为索引增加子字段

  • 写入文档,并查看 Mapping
    • 看到 text 字段默认会给它添加一个 keyword 子字段; ```json

      写入文档

      PUT blogs/_doc/1 { “content”:”Hadoop is cool”, “keyword”:”hadoop” }

查看 Mapping

GET blogs/_mapping

### Mapping配置

{ “blogs” : { “mappings” : { “properties” : { “content” : { “type” : “text”, “fields” : { “keyword” : { “type” : “keyword”, “ignore_above” : 256 } } }, “keyword” : { “type” : “text”, “fields” : { “keyword” : { “type” : “keyword”, “ignore_above” : 256 } } } } } } }

  1. - 改变 Mapping,增加子字段,使用英文分词器,最后查看 Mapping 配置
  2. - 看到 content 有两个子字段,keyword,以及新增的 english 子字段;
  3. ```json
  4. # 修改 Mapping,增加子字段,使用英文分词器
  5. PUT blogs/_mapping
  6. {
  7. "properties" : {
  8. "content" : {
  9. "type" : "text",
  10. "fields" : {
  11. "english" : {
  12. "type" : "text",
  13. "analyzer":"english"
  14. }
  15. }
  16. }
  17. }
  18. }
  19. # 查看 Mapping
  20. GET blogs/_mapping
  21. ######### Mapping配置 ############
  22. {
  23. "blogs" : {
  24. "mappings" : {
  25. "properties" : {
  26. "content" : {
  27. "type" : "text",
  28. "fields" : {
  29. "english" : {
  30. "type" : "text",
  31. "analyzer" : "english"
  32. },
  33. "keyword" : {
  34. "type" : "keyword",
  35. "ignore_above" : 256
  36. }
  37. }
  38. },
  39. "keyword" : {
  40. "type" : "text",
  41. "fields" : {
  42. "keyword" : {
  43. "type" : "keyword",
  44. "ignore_above" : 256
  45. }
  46. }
  47. }
  48. }
  49. }
  50. }
  51. }
  • 尝试对子字段进行查询
    • 无法匹配到 Mapping 变更前的已存在的数据;
    • 可以匹配到 Mapping 变更后的新写入的数据; ```json

      查询 Mapping 变更前写入的文档

      POST blogs/_search { “query”: { “match”: { “content.english”: “Hadoop” } } }
      ###虽然有符合条件的数据存在,但是没有返回结果

写入文档

PUT blogs/_doc/2 { “content”:”Elasticsearch rocks”, “keyword”:”elasticsearch” }

查询新写入文档

POST blogs/_search { “query”: { “match”: { “content.english”: “Elasticsearch” } } }

###可以匹配到新写入的文档数据

<a name="MdMCJ"></a>
## 2.1 Update By Query API
:::tips

- 当通过更改 Mapping,索引中某个字段增加了子字段后,那么 Mapping 更改前就已经存在数据是无法针对子字段进行查询的;
- 如果希望对旧有数据针对子字段也可以进行查询,那么可以使用 Update By Query API 对索引下所有文档进行更新;
:::
```json
# Update所有文档
POST blogs/_update_by_query
{

}

3. 案例2:更改已有字段类型的 Mappings

  • 查看现有的索引 Mapping 配置
    • 如果是对 content 字段下的子字段进行删减或者修改,是可以成功的;
    • 如果是对 keyword、content 这样的主字段类型进行修改,text -> keyword,是会报错的; ```json

      查看 Mapping

      GET blogs/_mapping
      ### Mapping配置
      { “blogs” : { “mappings” : { “properties” : { “content” : {
       "type" : "text",
       "fields" : {
         "english" : {
           "type" : "text",
           "analyzer" : "english"
         },
         "keyword" : {
           "type" : "keyword",
           "ignore_above" : 256
         }
       }
      
      }, “keyword” : {
       "type" : "text",
       "fields" : {
         "keyword" : {
           "type" : "keyword",
           "ignore_above" : 256
         }
       }
      
      } } } } }

修改keyword字段的类型 text->keyword

PUT blogs/_mapping { “properties” : { “content” : { “type” : “text”, “fields” : { “english” : { “type” : “text”, “analyzer” : “english” } } }, “keyword” : { “type” : “keyword” } } }

结果会报错

{ “error”: { “root_cause”: [ { “type”: “illegal_argument_exception”, “reason”: “mapper [keyword] of different type, current_type [text], merged_type [keyword]” } ] } }


<a name="8gslB"></a>
## 3.1 Reindex API
:::tips

- ES 不允许在原有 Mapping 上对字段类型进行修改;
- 只能创建新的索引,并且设定正确的字段类型,再重新导入数据;

- Reindex API 支持把文档从一个索引拷贝到另外一个索引;
- 使用 Reindex API 的一些场景:
   - 修改索引的主分片数;
   - 改变字段的 Mapping 中的字段类型;
   - 集群内数据迁移 / 跨集群的数据迁移;

**注意:**

- Reindex 要求对源索引中的所有文档都启用 _source。
- 在调用 _reindex API 之前,必须设置目标索引。Reindex 不会从源索引复制设置,映射、碎片计数、副本等必须提前配置。
- 一定要尽量使用 Index Alias 读写数据。即便发生 Reindex,也能实现零停机维护。
:::
```json
# 1.创建新的索引 blogs_fix,
并且设定符合新需求的 Mapping,keyword字段类型直接设为 keyword
PUT blogs_fix/
{
  "mappings": {
        "properties" : {
        "content" : {
          "type" : "text",
          "fields" : {
            "english" : {
              "type" : "text",
              "analyzer" : "english"
            }
          }
        },
        "keyword" : {
          "type" : "keyword"
        }
      }    
  }
}

# 2. Reindx API,将数据从旧索引迁移到新索引
POST  _reindex
{
  "source": {
    "index": "blogs"
  },
  "dest": {
    "index": "blogs_fix"
  }
}

# 3.测试,数据已迁移到位
GET  blogs_fix/_doc/1

1) op_type:create

  • _reindex 只会创建不存在的文档;
  • 文档如果已经存在,会导致版本冲突;

    POST  _reindex
    {
    "source": {
      "index": "blogs"
    },
    "dest": {
      "index": "blogs_fix",
      "op_type": "create"
    }
    }
    #如果存在的文档,会提示迁移失败,失败的原因是文档已存在,导致的版本冲突
    {
    "failures": [
      {
        "index": "blogs_fix",
        "type": "_doc",
        "id": "1",
        "cause": {
          "type": "version_conflict_engine_exception",
          "reason": "[1]: version conflict, document already exists (current version [1])",
          "index_uuid": "Nz6w5rpwTpq3SI7sGiZ8Sw",
          "shard": "0",
          "index": "blogs_fix"
        },
        "status": 409
      }
    ]
    }
    

    2) version_type

  • 缺省 version_type 或设置 version_type: internal,ES 会盲目的将文档迁移到目标索引中,如果目标索引恰好具有相同 ID 的文档,则会被迁移而来的文档覆盖,且 version 增加;

  • 设置 version_type: external,ES 会保留源索引中的 version,创建目标索引中不存在的文档,并更新目标索引中 version 比源索引中低的文档(如果目标索引中 _version=2,只有源索引中 _version>2 才能迁移并更新成功,如:源 _version=5,否则报错); ```json

    Reindx API

    POST _reindex { “source”: { “index”: “blogs” }, “dest”: { “index”: “blogs_fix” } }
    ############## version Type:Internal

    Reindx API,version Type Internal,目标索引中已经存在相同id的文档

    POST _reindex { “source”: { “index”: “blogs” }, “dest”: { “index”: “blogs_fix”, “version_type”: “internal” } }

不管目标索引中_version是多少,根据源索引中文档版本号增加,文档version: 1->2

GET blogs_fix/_doc/1

############## version Type:External

Reindx API,version Type External,目标索引中已经存在相同id的文档

POST _reindex { “source”: { “index”: “blogs” }, “dest”: { “index”: “blogs_fix”, “version_type”: “external” } }

如果目标索引中 _version=2,只有源索引中 _version>2 才能迁移并更新成功,如:源 _version=5,否则报错

<a name="lytrJ"></a>
### 3) conflicts: proceed

- 默认情况下,版本冲突会终止 Reindex 过程。
- 如果存在冲突时,要继续重建索引,可以设置 "conflicts": "proceed",这种情况下会继续 Reindex 过程,且返回遇到版本冲突的统计数量;
- 注意:其他错误类型的处理不受 "conflicts" 参数的影响;
```json
POST  _reindex
{
  "source": {
    "index": "blogs"
  },
  "dest": {
    "index": "blogs_fix",
    "version_type": "external"
  },
  "conflicts": "proceed"
}

4) 查看 Task API

  • 可以通过查看 Task API,了解 Reindex 的状况

    GET _tasks?detailed=true&actions=*reindex
    

    image.png

    5) Reindex 异步执行

  • ReIndex API 支持异步操作,执行只返回 Task Id

    POST _reindex?wait_for_completion=false
    

    6) 跨集群 Reindex

  • 需要修改 elasticsearch.yaml,并且重启节点

    reindex.remote.whitelist: "otherhost:9200, another:9200, 127.0.10.*:9200, localhost:*"
    
    POST _reindex
    {
    "source": {
      "remote": {
        "host": "http://otherhost:9200",
        "username": "user",
        "password": "pass"
      },
      "index": "source",
      "query": {
        "match": {
          "test": "data"
        }
      }
    },
    "dest": {
      "index": "dest"
    }
    }