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

适用版本: 7.3-7.7

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

Aggregation [name] cannot support regular expression style include/exclude settings as they can only be applied to string fields 是 Elasticsearch 在执行聚合(Aggregation)阶段抛出的异常。该错误明确指出:正则表达式形式的 include / exclude 筛选条件只能应用于字符串类型的字段,当前聚合所引用的字段不满足此条件。

常见现象 #

  • 搜索请求返回 HTTP 400 Bad Request,响应体中包含 search_phase_execution_exceptionaggregation_execution_exception
  • Kibana 可视化面板加载失败,Dev Tools 中执行对应查询立即报错。
  • 应用日志中出现 AggregationExecutionException 堆栈,伴随 illegal_argument_exception 信息。
  • 仅影响使用了正则 include/exclude 的聚合请求,普通搜索和未使用该特性的聚合请求正常。

典型报错与异常栈 #

{
  "error": {
    "root_cause": [
      {
        "type": "aggregation_execution_exception",
        "reason": "Aggregation [my_agg] cannot support regular expression style include/exclude settings as they can only be applied to string fields. Use an array of values for include/exclude clauses"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "failed_shards": 1,
    "caused_by": {
      "type": "aggregation_execution_exception",
      "reason": "Aggregation [my_agg] cannot support regular expression style include/exclude settings as they can only be applied to string fields. Use an array of values for include/exclude clauses"
    }
  },
  "status": 400
}

对应 Java 异常栈:

org.elasticsearch.search.aggregations.AggregationExecutionException: Aggregation [my_agg] cannot support regular expression style include/exclude settings as they can only be applied to string fields. Use an array of values for include/exclude clauses
    at org.elasticsearch.search.aggregations.bucket.terms.GlobalOrdinalsStringTermsAggregator.build(GlobalOrdinalsStringTermsAggregator.java:...)
    at org.elasticsearch.search.aggregations.bucket.terms.TermsAggregatorFactory.create(TermsAggregatorFactory.java:...)

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

该异常的根本原因是:对不支持正则表达式筛选的字段类型使用了正则形式的 include / exclude

Elasticsearch 的 terms 聚合支持通过 includeexclude 参数对桶(bucket)进行过滤,支持两种形式:

形式示例适用字段类型
正则表达式"include": ".*foo.*"仅限 keyword / text 等字符串类型字段
精确值数组"include": ["foo", "bar"]所有支持 terms 聚合的字段类型

当聚合字段为数值类型(longintegerdouble 等)、booleandateip 等非字符串类型时,使用正则表达式形式的 include/exclude 就会触发该异常。

常见触发场景 #

  • integerlongdouble 等数值字段执行 terms 聚合,并配置了正则形式的 include/exclude
  • 聚合字段的 mapping 类型为 booleandateip,却使用了 ".*true.*" 之类的正则过滤。
  • 字段原本是 keyword 类型,但索引重建或 mapping 变更后变成了数值类型,导致原有查询报错。
  • 使用 doc_valuesfalse 的字符串字段进行聚合(虽然这通常报其他错误,但可能叠加出现)。

3. 如何排查这个异常 #

建议按以下步骤定位问题:

3.1 确认聚合字段的 mapping 类型 #

# 查看目标索引的 mapping
GET /your_index/_mapping/field/your_field

重点关注字段的 type 值,确认是否为 keywordtext 以外的类型。

3.2 检查聚合 DSL 中的 include/exclude 写法 #

{
  "aggs": {
    "my_agg": {
      "terms": {
        "field": "status_code",
        "include": ".*200.*",   // ← 如果 status_code 是 long/integer 类型,这里就会报错
        "size": 10
      }
    }
  }
}

3.3 确认是否为跨索引查询导致 #

当使用通配符索引模式(如 log-*)时,不同索引的同一字段可能 mapping 不一致:

# 检查所有相关索引的 mapping
GET /log-*/_mapping/field/status_code

如果部分索引中该字段为 keyword,部分为 long,则查询在这些索引上执行时会报错。

4. 如何解决这个错误 #

方案一:将 include/exclude 改为数组形式(推荐) #

正则形式只适用于字符串字段,对于数值或日期字段,改用精确值数组:

{
  "aggs": {
    "status_agg": {
      "terms": {
        "field": "status_code",
        "include": [200, 201, 204],
        "size": 10
      }
    }
  }
}

方案二:将字段改为 keyword 类型后使用正则 #

如果业务上确实需要对字段使用正则匹配,需确保字段为 keyword 类型:

# 创建新索引并指定正确 mapping
PUT /your_index_new
{
  "mappings": {
    "properties": {
      "status_code": {
        "type": "keyword"
      }
    }
  }
}

# 使用 reindex 迁移数据
POST /_reindex
{
  "source": { "index": "your_index" },
  "dest": { "index": "your_index_new" }
}

之后即可使用正则形式:

{
  "aggs": {
    "status_agg": {
      "terms": {
        "field": "status_code",
        "include": ".*200.*",
        "size": 10
      }
    }
  }
}

方案三:移除 include/exclude 并在应用层过滤 #

如果正则筛选逻辑不复杂,可以在聚合返回后在应用层进行过滤,避免在 Elasticsearch 侧触发异常:

{
  "aggs": {
    "status_agg": {
      "terms": {
        "field": "status_code",
        "size": 100
      }
    }
  }
}

方案四:使用 script 实现复杂过滤(性能敏感场景慎用) #

{
  "aggs": {
    "status_agg": {
      "terms": {
        "script": {
          "source": "doc['status_code'].value.toString()",
          "lang": "painless"
        },
        "include": ".*200.*",
        "size": 10
      }
    }
  }
}

5. 预防与最佳实践 #

  • Mapping 设计阶段明确字段用途:如果计划对某个字段做正则过滤的聚合,务必将其设置为 keyword 类型,避免使用数值类型存储枚举值。
  • 跨索引查询前统一 mapping:使用 Index Template 或 Component Template 确保所有相关索引的字段类型一致,避免 log-2023-01log-2023-02 中同一字段类型不同。
  • 避免在数值字段上使用正则 include/exclude:数值字段的 terms 聚合应使用精确值数组形式的 include/exclude,或完全省略该参数。
  • 在 Kibana 可视化中注意字段类型:Kibana 的字段选择下拉框不会区分字段类型是否支持正则,使用正则过滤前需确认字段类型。
  • 使用运行时字段(Runtime Field)作为过渡方案:如果无法修改原始 mapping,可以通过运行时字段将数值字段转换为字符串类型后再聚合:
{
  "runtime": {
    "status_code_str": {
      "type": "keyword",
      "script": {
        "source": "emit(doc['status_code'].value.toString())"
      }
    }
  },
  "aggs": {
    "status_agg": {
      "terms": {
        "field": "status_code_str",
        "include": ".*200.*",
        "size": 10
      }
    }
  }
}

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

  • INFINI Console 可查看集群各索引的 mapping 差异、聚合请求失败趋势,快速定位跨索引 mapping 不一致问题。
  • INFINI Gateway 可部署在 Elasticsearch 前端,对包含非法正则 include/exclude 的请求进行拦截和改写,避免异常请求到达集群。

6. 小结 #

Aggregation cannot support regular expression style include/exclude 异常的核心原因是字段类型与 include/exclude 的形式不匹配。修复的关键是根据字段类型选择正确的过滤形式:字符串字段用正则,数值字段用精确值数组。在设计 mapping 时提前规划字段用途,是避免此类问题的最有效手段。

相关错误 #

附:源码上下文 #

以下为触发该异常的 Elasticsearch 源码片段,便于深入理解其触发条件:

if (valuesSource instanceof ValuesSource.Bytes) {
    ExecutionMode execution = ExecutionMode.MAP;
    DocValueFormat format = config.format();
    if ((includeExclude != null) && (includeExclude.isRegexBased()) && format != DocValueFormat.RAW) {
        throw new AggregationExecutionException("Aggregation [" + name + "] cannot support " +
            "regular expression style include/exclude settings as they can only be applied to string fields. " +
            "Use an array of values for include/exclude clauses");
    }
    return execution.create(name, factories, valuesSource, format,
        ...
}