📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 6.8-8.9+

1. 错误异常的基本描述 #

Aggregation [" + m.getName() + "] is of non-supported type [" + m.getType() + "] 是 Elasticsearch 在执行**聚合(aggregation)**时抛出的类型不兼容错误。当你在某个字段上执行聚合操作,但该字段的映射类型不支持该聚合时,就会触发此错误。例如,在 textdate 类型字段上使用 terms 聚合,或者在 keyword 类型字段上使用 histogram 聚合。

常见现象 #

  • Elasticsearch 返回 HTTP 400 Bad Request 状态码,响应体中包含 AggregationExecutionException
  • 包含聚合的搜索请求(_search)失败,聚合结果无法返回。
  • 在 Elasticsearch 服务端日志中会记录详细的异常信息和聚合名称。
  • 如果是通过 Kibana、应用程序或脚本发送查询,会在客户端收到异常响应。
  • 可能导致依赖聚合的报表、仪表盘或分析功能无法正常工作。

典型报错与异常栈 #

该异常的典型日志形态如下:

AggregationExecutionException: Aggregation [my_agg] is of non-supported type [date]
    at org.elasticsearch.search.aggregations.bucket.terms.TermsAggregator.buildValuesSource(TermsAggregator.java:...)
    at org.elasticsearch.search.aggregations.Aggregator.execute(Aggregator.java:...)
    at org.elasticsearch.search.aggregations.AggregationExecutionException.execute(AggregationExecutionException.java:...)

通过 API 请求的响应通常如下:

{
  "error": {
    "root_cause": [
      {
        "type": "aggregation_execution_exception",
        "reason": "Aggregation [my_agg] is of non-supported type [date]"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "failed_shards": [...]
  },
  "status": 400
}

另一种常见形态(字段类型不匹配):

AggregationExecutionException: Aggregation [my_agg] is of non-supported type [text]

2. 为什么会发生这个错误 #

Elasticsearch 的聚合功能对字段类型有特定要求。不同的聚合类型需要字段满足特定的映射条件:

聚合类型支持的字段类型
termskeywordipbytes 等,或启用 doc_values 的字段
histogram数值类型(longintegerdouble 等)
date_histogramdate 类型
range数值或 date 类型
geohashgeo_point 类型
cardinality任意支持 doc_values 的字段

源码中的逻辑是:

} else {
    throw new ElasticsearchException("Aggregation [" + m.getName() + "] is of non-supported type [" + m.getType() + "]");
}

常见原因包括:

  • 字段类型不兼容:如尝试在 date 类型字段上使用 terms 聚合。
  • 字段未启用 doc_values:聚合需要的 doc_values 被禁用。
  • 动态映射字段:字段被自动映射为意外的类型(如 text 而不是 keyword)。
  • 使用了错误的字段:聚合中引用了错误的字段名或子字段。
  • 版本差异:不同版本的 Elasticsearch 对聚合类型的要求可能不同。
  • 映射未更新:索引的映射已更新,但聚合还在使用旧字段类型。

3. 如何排查和解决这个异常和解决这个异常 #

排查步骤 #

建议按以下顺序进行排查:

第一步:获取完整的错误响应和聚合配置 #

# 重现错误并查看完整响应
curl -X GET "localhost:9200/my_index/_search" -H 'Content-Type: application/json' -d @query.json 2>&1 | jq .

# 查看 Elasticsearch 日志中的详细错误
tail -n 500 /var/log/elasticsearch/elasticsearch.log | grep -A 30 "is of non-supported type"

第二步:检查字段映射类型 #

# 查看索引的映射配置
curl -X GET "localhost:9200/my_index/_mapping?pretty" | jq '.my_index.mappings.properties.my_field'

# 检查字段类型和 doc_values 设置
curl -X GET "localhost:9200/my_index/_mapping?pretty" | grep -A 10 "my_field"

第三步:验证聚合与字段类型的兼容性 #

// 错误示例:在 date 字段上使用 terms 聚合
{
  "aggs": {
    "terms_agg": {
      "terms": {
        "field": "date_field",  // 错误:date 字段不支持 terms 聚合
        "size": 10
      }
    }
  }
}

// 正确示例:使用 date_histogram 代替
{
  "aggs": {
    "date_agg": {
      "date_histogram": {
        "field": "date_field",  // 正确:date 字段支持 date_histogram
        "calendar_interval": "1d"
      }
    }
  }
}

第四步:在测试环境验证 #

# 在测试环境使用正确的聚合配置
curl -X GET "localhost:9200/test_index/_search" -H 'Content-Type: application/json' -d '
{
  "aggs": {
    "terms_agg": {
      "terms": {
        "field": "keyword_field",  // 使用 keyword 字段
        "size": 10
      }
    }
  }
}'

排查时需要注意的问题 #

  • 区分聚合类型和字段类型:确认当前聚合类型是否支持目标字段的类型。
  • 检查 doc_values:某些聚合需要字段启用 doc_values
  • 注意子字段:对于 text 类型字段,可以使用 field.keyword 子字段。
  • 查看完整错误信息:错误信息会指出是哪个聚合和哪个字段类型有问题。

4. 如何解决这个错误 #

常用修复思路 #

方案一:使用正确的聚合类型(推荐) #

// 修复前:错误的聚合类型
{
  "aggs": {
    "terms_agg": {
      "terms": {
        "field": "date_field"  // 错误
      }
    }
  }
}

// 修复后:使用正确的聚合类型
{
  "aggs": {
    "date_agg": {
      "date_histogram": {
        "field": "date_field",  // 正确
        "calendar_interval": "1d"
      }
    }
  }
}

方案二:使用正确的字段或子字段 #

// 修复前:在 text 字段上直接使用 terms
{
  "aggs": {
    "terms_agg": {
      "terms": {
        "field": "text_field"  // 错误
      }
    }
  }
}

// 修复后:使用 keyword 子字段
{
  "aggs": {
    "terms_agg": {
      "terms": {
        "field": "text_field.keyword"  // 正确:使用 keyword 子字段
      }
    }
  }
}

方案三:更新字段映射或添加 keyword 字段 #

# 如果字段确实类型不对,考虑更新映射
curl -X PUT "localhost:9200/my_index/_mapping" -H 'Content-Type: application/json' -d '
{
  "properties": {
    "new_keyword_field": {
      "type": "keyword"
    }
  }
}'

# 或者使用 multi-field
curl -X PUT "localhost:9200/my_index/_mapping" -H 'Content-Type: application/json' -d '
{
  "properties": {
    "text_field": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword"
        }
      }
    }
  }
}'

方案四:在代码中添加类型校验 #

# Python 示例:在发送请求前校验聚合配置
def validate_aggregation(agg_config):
    field = agg_config.get('field')
    agg_type = agg_config.get('terms') or agg_config.get('histogram')  # 简化示例
    
    # 这里可以添加字段类型检查逻辑
    # 例如:terms 聚合需要 keyword 字段
    return True

# 使用
validate_aggregation(search_body['aggs']['terms_agg']['terms'])

后续注意事项与推荐建议 #

  • 建立聚合规范:为团队制定聚合使用规范,明确不同字段类型支持的聚合。
  • 使用 keyword 子字段:对于 text 类型字段,优先使用 field.keyword 进行聚合。
  • 在代码中添加校验:对于动态生成或接收用户输入的聚合,在发送请求前进行校验。
  • 使用可视化工具测试:在 Kibana 或 INFINI Console 中先测试聚合配置,确认正确后再集成到代码。
  • 监控聚合错误:通过日志监控及时发现聚合执行错误,快速定位和修复。

借助 INFINI 产品提升排障效率 #

  • INFINI Console 提供聚合查询的可视化构建和测试功能,可以帮助快速定位字段类型和聚合不兼容的问题。通过 Console 的聚合调试工具,可以在界面上直接测试聚合配置,查看详细的错误信息。

  • INFINI Gateway 可以拦截和检查发往 Elasticsearch 的搜索请求,自动检测并拒绝包含不兼容聚合的请求。Gateway 还提供请求重写功能,可以在请求到达 Elasticsearch 之前自动修正常见问题。

  • 对于需要频繁使用聚合的团队,建议结合 INFINI Console 的聚合分析能力和 INFINI Gateway 的请求治理能力,建立从聚合构造、验证、执行到监控的完整流程,大幅减少因字段类型不兼容导致的异常。

5. 小结 #

Aggregation [" + m.getName() + "] is of non-supported type 是一个典型的聚合与字段类型不兼容错误,根源在于聚合类型或参数与字段的映射类型不匹配。虽然报错信息直接指向类型不支持,但修复思路需要根据具体情况来决定:是更换聚合类型、使用正确的字段,还是调整字段映射。

在实际工作中,为避免此类问题,建议在开发阶段就使用 Kibana Dev Tools 或 INFINI Console 的查询工具测试聚合,在代码中建立参数验证机制,并使用 INFINI Gateway 作为防护层来拦截和修正不兼容的聚合请求。通过规范化和工具化的方式,可以大幅减少此类错误的发生。

相关错误 #

参考文档 #

附:日志上下文 #

下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:

} else {
    throw new ElasticsearchException("Aggregation [" + m.getName() + "] is of non-supported type [" + m.getType() + "]");
}