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

适用版本: 6.8-7.7

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

Aggregation [name] cannot support regular expression style include/exclude settings as they can only be applied to string fields 是 Elasticsearch 在执行聚合查询时抛出的异常。该错误的核心含义是:当前聚合类型为数值类型字段(numeric field)使用了正则表达式风格的 include / exclude 过滤,而正则表达式过滤仅支持 keyword 字符串类型的字段

常见现象 #

  • 搜索接口返回 HTTP 400 Bad Request,响应体中包含 illegal_argument_exceptionaggregation_execution_exception
  • Kibana 或其他可视化工具中配置的聚合图表无法正常渲染,控制台显示报错信息。
  • 应用日志中出现类似 AggregationExecutionException: Aggregation [xxx] cannot support regular expression style 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 numeric values for include/exclude clauses used to filter numeric fields"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "failed_shards": [
      {
        "reason": {
          "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 numeric values for include/exclude clauses used to filter numeric fields"
        }
      }
    ]
  },
  "status": 400
}

服务端日志中的异常栈通常类似:

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.
    at org.elasticsearch.search.aggregations.bucket.terms.TermsAggregatorFactory.buildAggregator(TermsAggregatorFactory.java:...)
    at org.elasticsearch.search.aggregations.AggregatorFactories.execute(AggregatorFactories.java:...)

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

该错误的根本原因是:Elasticsearch 的 include / exclude 参数在 terms 聚合中对字符串字段和数值字段提供了两种不同的过滤机制

字段类型支持的 include/exclude 形式说明
keyword / 字符串字段正则表达式(regex)或精确值数组正则表达式通过 Java 内置正则引擎匹配字符串
数值字段(longintegerdouble 等)仅支持精确值数组数值无法进行正则匹配,只能按值过滤

当聚合配置同时满足了以下两个条件时,就会触发此异常:

  1. 聚合目标是 数值类型字段longintegershortbytedoublefloat 等);
  2. includeexclude 的值被识别为 正则表达式形式(而非数值数组)。

常见触发场景 #

  • 对数值字段使用字符串形式的正则表达式进行过滤,例如 "include": "^[0-9]+$",ES 无法对数值做正则匹配。
  • 从旧版配置或脚本中复制了针对 keyword 字段的聚合 DSL,但字段类型已变更为数值类型,未同步调整 include / exclude 的写法。
  • rare_terms 聚合中使用正则形式的 include / exclude,而该聚合在部分版本中对数值字段有相同限制。
  • 动态脚本或应用代码中拼装 DSL 时,未根据字段类型区分 include / exclude 的格式。

3. 如何排查这个异常 #

第一步:确认报错聚合的完整 DSL #

从应用日志、Kibana 开发者工具或网关访问日志中获取触发异常的完整查询 DSL,重点检查:

  1. 聚合中 terms(或 rare_terms)的 field 值指向哪个字段;
  2. 该字段的 include / exclude 配置的具体内容;
  3. 确认 include / exclude 是字符串(正则)还是数组(精确值)。

第二步:检查目标字段的 mapping #

使用以下 API 查看索引中该字段的类型:

GET /your_index/_mapping/field/your_field

返回示例:

{
  "your_index": {
    "mappings": {
      "your_field": {
        "full_name": "your_field",
        "mapping": {
          "your_field": {
            "type": "long"
          }
        }
      }
    }
  }
}

如果 type 为数值类型(longintegerdouble 等),则确认是本文描述的错误场景。

第三步:判断 include/exclude 的使用方式 #

检查 DSL 中 include / exclude 的写法:

// ❌ 错误写法:对数值字段使用正则表达式字符串
{
  "aggs": {
    "my_agg": {
      "terms": {
        "field": "price",
        "include": "[0-9]+"
      }
    }
  }
}

// ✅ 正确写法(数值字段):使用数值数组
{
  "aggs": {
    "my_agg": {
      "terms": {
        "field": "price",
        "include": [100, 200, 300]
      }
    }
  }
}

4. 如何解决这个错误 #

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

如果聚合目标是数值字段,将 include / exclude 从正则表达式改为精确数值数组:

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

如果需要"范围式"过滤,可以先在 query 层用 rangebool 过滤,再对结果做聚合:

{
  "size": 0,
  "query": {
    "range": {
      "price": {
        "gte": 100,
        "lte": 500
      }
    }
  },
  "aggs": {
    "price_terms": {
      "terms": {
        "field": "price",
        "size": 20
      }
    }
  }
}

方案二:将字段改为 keyword 类型(如需正则匹配) #

如果业务上确实需要对数值做正则风格的分组(例如按数字前缀分组),可在 mapping 中增加一个 keyword 类型的多字段(multi-field):

PUT /your_index/_mapping
{
  "properties": {
    "status_code": {
      "type": "integer",
      "fields": {
        "as_keyword": {
          "type": "keyword"
        }
      }
    }
  }
}

然后对新字段使用正则 include

{
  "aggs": {
    "status_groups": {
      "terms": {
        "field": "status_code.as_keyword",
        "include": "2.*",
        "size": 10
      }
    }
  }
}

方案三:使用 script 聚合实现自定义过滤 #

如果需要更复杂的数值过滤逻辑,可以用 script 在聚合阶段实现:

{
  "aggs": {
    "custom_numeric_filter": {
      "terms": {
        "script": {
          "source": "doc['price'].value >= 100 && doc['price'].value <= 500 ? 'in_range' : 'out_of_range'"
        }
      }
    }
  }
}

注意: script 聚合会带来性能开销,不建议在高并发或大数据集场景下使用。

5. 如何预防此类问题 #

编码规范建议 #

  • 在应用代码中根据字段类型动态决定 include / exclude 的格式:字符串字段用正则,数值字段用数组。
  • 为聚合 DSL 的构建增加单元测试,覆盖不同类型字段的聚合场景,防止字段类型变更后 DSL 不同步。
  • 避免直接复制针对 keyword 字段的聚合配置到数值字段,两者的 include / exclude 语义不同。

Mapping 设计建议 #

  • 对既需要数值运算又需要字符串匹配过滤的字段,使用 multi-field 同时配置数值主类型和 keyword 子类型。
  • 在索引模板(Index Template)中明确字段类型,避免因动态 mapping 产生不符合预期的字段类型。

监控与告警 #

  • 通过 INFINI Gateway 对返回 400 的查询请求进行记录和采样,及时发现类似 DSL 错误。
  • INFINI Console 中查看集群的慢查询和错误请求趋势,定位频繁失败的聚合查询。

6. 小结 #

Aggregation cannot support regular expression style include/exclude 是一个典型的字段类型与 DSL 写法不匹配的问题。核心要点是:正则表达式形式的 include / exclude 仅适用于字符串(keyword)字段,数值字段必须使用精确值数组

排查时先确认字段类型,再检查 include / exclude 的格式;修复时优先采用数值数组或 range 查询前置过滤;长期来看,合理的 mapping 设计和 DSL 构建规范是避免此类问题的最佳保障。

相关错误 #

附:源码上下文 #

以下为触发该异常的 Elasticsearch 源码片段,帮助理解异常抛出的条件:

if ((includeExclude != null) && (includeExclude.isRegexBased())) {
    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 numeric values for include/exclude clauses "
        + "used to filter numeric fields");
}

if (valuesSource instanceof ValuesSource.Numeric) {
    // 数值类型的 ValuesSource,不支持正则过滤
}