ES 如何解决 Fielddata is disabled on text fields by default 错误

卡拉先生
发布于 2020年09月04日 | 上次编辑:2020年09月04日

header

在使用 ElasticSearch 的时候,如果索引中的字段是 text 类型,针对该字段聚合、排序和查询的时候常会出现 Fielddata is disabled on text fields by default. Set fielddata=true 的错误。本文总结这个错误出现的原因,可能的修复方法等。

如果你在尝试构建搜索功能,可以尝试卡拉搜索,无需配置维护即可实现毫秒级搜索,后台可轻松控制排序算法让运营和产品可以轻松调整,降低开发负担

常见原因

在 ElasticSearch 中,Fielddata 默认在 text 类型的字段时是不启用的。设想,如果默认打开,那么你的数据中,每个字符串大概率不一样的话,那么这个字段需要的集合大小(Cardinality)会非常大。

而这个字段是需要存在内存中的 (heap),因此不可能默认打开。所以如果你从一个 script 来对一个 text 字段进行排序、聚合或者查询的话,就会出现这个错误。

Fielddata is disabled on text fields by default.  Set `fielddata=true` on
[`你的字段名字`] in order to load  fielddata in memory by uninverting the
inverted index. Note that this can however use significant memory.

错误表现

出现这个错误的返回 JSON 会类似如下,root_cause 字段中的类型为 illegal_argument_exception

{
    "error": {
        "root_cause": [
            {
                "type": "illegal_argument_exception",
                "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [YOUR_FIELD] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
            }
        ],
        "type": "search_phase_execution_exception",
        "reason": "all shards failed",
        "phase": "query",
        "grouped": true,
        "failed_shards": [
            {
                "shard": 0,
                "index": "XXXX",
                "node": "YOUR_NODE",
                "reason": {
                    "type": "illegal_argument_exception",
                    "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [YOUR_FIELD] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
                }
            }
        ]
    },
    "status": 400
}

多数情况下这个错误其实信息量相对大,且指导清晰了,无非查询的字段里没有 enable fielddata。但有时,如果你重新定义了 mapping ,则很有可能在查询时少了后缀的 .keyword (具体请见下文)

如何解决

1. 尝试用 keyword 类型

尝试将对应的字段 map 成 keyword 类型。比如说:

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "my_field": { 
        "type": "text",
        "fields": {
          "keyword": { 
            "type": "keyword"
          }
        }
      }
    }
  }
}

但请注意,如果 map 过后,查询时的字段需要加上后缀 .keyword。比如如果你的字段如上是叫 my_field 那么查询时需要使用 my_field.keyword (参考: How to fix ElasticSearch ‘Fielddata is disabled on text fields by default’ for keyword field)

es.search(index="strings", body={
    "size": 0,
    "aggs" : {
        "patterns" : {
            "terms" : { "field" : "pattern.keyword" }
        }
    }

2. 对已存在字段更改 mapping

如果这个字段已经存在的话,那么你需要把这个字段的 fielddata 改为 true。比如说,用以下 PUT 方法:

PUT my-index-000001/_mapping
{
  "properties": {
    "my_field": { 
      "type":     "text",
      "fielddata": true
    }
  }
}

3. 重建索引

如果按方法 1 和 2 中的方式调整过后仍然有错误的话,建议重新建立索引。(参考How to fix ElasticSearch ‘Fielddata is disabled on text fields by default’ for keyword field)

总结

多数情况下,出现 Fielddata 相关的错误都是因为尝试聚合和排序一个 text 字段,因此只要把字段的 fielddata 设为 true 或者类型调整为 keyword 即可。如果是已存在字段可能需要重新索引。

如果在构建搜索功能的话,也可以尝试卡拉搜索,几行代码就可以接入,可以极大程度免去搭建和维护 ES 的烦恼。

扩展阅读推荐:

ElasticSearch 初学终极教程

ES 配置 yaml 中文教程

如何快速搭建站内搜索

API 是什么

相关文章

友情链接更新日志© 2020, 卡拉搜索, Built with ❤️ in San Francisco + Beijing

京ICP备15049164号-3