2019 年使用 Elasticsearch 7.x 时,一个按 createDate 倒序查询的接口,在新索引上报错。给排序增加 unmapped_type 后,当时的查询恢复。

当时使用的 Java 片段

下面是旧 Java High Level REST Client 风格:

FieldSortBuilder sort = SortBuilders
    .fieldSort("createDate")
    .order(SortOrder.DESC)
    .unmappedType("date");

searchSourceBuilder.sort(sort);

对应请求结构可以写为:

GET /example_articles/_search
{
  "sort": [
    {
      "createDate": {
        "order": "desc",
        "unmapped_type": "date"
      }
    }
  ]
}

unmapped_type 指定遇到未映射字段时按什么类型处理,避免该类排序失败;它不会给索引补建字段映射。ES 7.3 排序说明

空数据不是根因的充分描述

空索引可以已经有显式 mapping;有文档的索引也可能一直没有 createDate。动态映射只在相应字段进入文档、满足配置规则时才可能建立,不能说“有第一条数据就一定创建所有字段”。

先检查真正被查询的目标:

GET /example_articles/_mapping

如果请求覆盖多个索引,也要分别检查 createDate 是否存在、是否都是 date,以及日期格式是否兼容。

三类问题不能混用一个选项

未映射字段、已映射但某条文档缺值、不同索引里类型冲突,是三种不同情况。unmapped_type 针对第一种,并不修复后两种的所有问题;缺值排序可另看 missing 选项,类型冲突则应先修正数据模型。

对于明确要求按日期排序的新索引,预先声明 mapping 更能表达契约。保留 unmapped_type 作为兼容选择时,也应知道自己在容忍什么,不能让它掩盖本应存在的字段缺失。