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

适用版本: 6.8-8.9

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

array elements in include/exclude clauses should be string values(include/exclude 子句中的数组元素应为字符串值)是 Elasticsearch 在解析查询 DSL 时抛出的 illegal_argument_exception 类型异常。该错误明确表示:在 includeexclude 数组中,出现了非字符串类型的元素。

此错误常见于以下两种场景:

  • 聚合查询(Aggregations):在使用 terms 聚合时,通过 includeexclude 参数指定需要包含或排除的字段值,但传入了数值、布尔值或对象等非字符串类型。
  • Source 过滤:在使用 _sourceincludes / excludes 参数时,数组中包含非字符串元素。

常见现象 #

  • 请求返回 HTTP 400 Bad Request,错误类型为 illegal_argument_exception
  • Elasticsearch 服务端日志中出现 ElasticsearchParseException: Array elements in include/exclude clauses should be string values
  • 应用侧表现为查询失败,相关聚合结果或搜索结果无法返回。
  • 在 Kibana Dev Tools 或客户端代码中直接执行查询时立即报错。

典型报错与异常栈 #

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "array elements in include/exclude clauses should be string values"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "array elements in include/exclude clauses should be string values"
  },
  "status": 400
}

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

ElasticsearchParseException: Array elements in include/exclude clauses should be string values
    at org.elasticsearch.search.aggregations.bucket.terms.IncludeExclude.merge(IncludeExclude.java:...)
    at org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder.doRewrite(TermsAggregationBuilder.java:...)
    at org.elasticsearch.search.aggregations.AggregationBuilder.rewrite(AggregationBuilder.java:...)

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

Elasticsearch 的 include / exclude 机制设计上只接受 字符串数组 作为参数值。其底层实现通过 XContentParser 解析请求体时,会逐个校验数组元素的类型,一旦发现非字符串 token(如数值、布尔值、START_OBJECT 等),立即抛出 ElasticsearchParseException

常见原因 #

  • 数值类型误用:在 include / exclude 数组中直接写入数字,如 [1, 2, 3],而 Elasticsearch 期望的是 ["1", "2", "3"]
  • 布尔类型误用:写入 true / false 而非 "true" / "false"
  • 对象类型误用:在数组中嵌套了对象或数组,而非纯字符串。
  • 客户端 SDK 序列化问题:某些 SDK 在序列化时,将原本是字符串的数字字段值序列化为数值类型,导致请求体不符合要求。
  • 动态生成查询时类型丢失:通过代码动态拼接查询 DSL 时,变量类型未显式转换为字符串。

3. 如何排查这个异常 #

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

  1. 获取完整报错信息:确认错误类型为 illegal_argument_exception,且 reason 字段包含 array elements in include/exclude clauses should be string values
  2. 检查查询 DSL:重点检查 aggregations 下的 terms 聚合中的 include / exclude 字段,以及 _sourceincludes / excludes 字段。
  3. 使用最小复现 DSL:将查询简化为只保留触发异常的聚合或过滤部分,逐步定位具体是哪个数组元素类型不正确。
  4. 核对字段类型:确认目标字段的 mapping 类型,理解其值是字符串还是数值,从而判断 include / exclude 中应使用何种格式的字符串。
  5. 检查客户端代码:如果是通过代码动态生成查询,检查变量类型是否正确转换为字符串。

排查注意事项 #

  • include / exclude 同时支持 字符串数组正则表达式字符串 两种形式,但不能混用,也不能在数组中包含非字符串元素。
  • 数值类型的字段值(如 keyword 类型的数字字符串)在 include / exclude 中仍需用字符串形式表示。

4. 如何解决这个错误 #

场景一:聚合查询中的 include/exclude 数组包含数值 #

错误示例:

{
  "aggs": {
    "tags": {
      "terms": {
        "field": "category",
        "include": [1, 2, 3]
      }
    }
  }
}

修复后:

{
  "aggs": {
    "tags": {
      "terms": {
        "field": "category",
        "include": ["1", "2", "3"]
      }
    }
  }
}

场景二:include/exclude 中包含布尔值 #

错误示例:

{
  "aggs": {
    "status_filter": {
      "terms": {
        "field": "status",
        "include": [true, false]
      }
    }
  }
}

修复后:

{
  "aggs": {
    "status_filter": {
      "terms": {
        "field": "status",
        "include": ["true", "false"]
      }
    }
  }
}

场景三:_source 过滤中的 includes/excludes 数组类型错误 #

错误示例:

{
  "_source": {
    "includes": ["title", 123, true]
  },
  "query": {
    "match_all": {}
  }
}

修复后:

{
  "_source": {
    "includes": ["title", "123", "true"]
  },
  "query": {
    "match_all": {}
  }
}

场景四:使用正则表达式时的正确写法 #

include / exclude 也支持直接传入正则表达式字符串(非数组形式):

{
  "aggs": {
    "tags": {
      "terms": {
        "field": "category",
        "include": "app.*",
        "exclude": "test.*"
      }
    }
  }
}

客户端代码示例(Python) #

# 错误写法
include_values = [1, 2, 3]

# 正确写法:显式转换为字符串
include_values = [str(v) for v in [1, 2, 3]]  # ["1", "2", "3"]

query = {
    "aggs": {
        "tags": {
            "terms": {
                "field": "category",
                "include": include_values
            }
        }
    }
}

5. 预防建议与最佳实践 #

  • 显式类型转换:在动态生成查询 DSL 时,始终将 include / exclude 数组元素显式转换为字符串类型,避免依赖语言的隐式类型推断。
  • 查询 DSL 校验:在将查询发送到 Elasticsearch 之前,使用 JSON Schema 或自定义校验逻辑检查 include / exclude 数组元素类型。
  • 统一封装查询构建方法:在项目中封装专门的聚合查询构建方法,确保 include / exclude 参数始终以字符串数组形式传入。
  • 使用正则表达式替代长数组:当需要包含或排除大量值时,优先考虑使用正则表达式形式,减少数组长度,同时避免类型错误。
  • 在测试环境验证查询:涉及动态参数拼接的查询,应在测试环境使用真实数据进行验证,提前发现类型问题。

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

  • INFINI Console 适合查看集群健康度、索引状态、查询错误趋势,帮助快速判断异常是查询构造问题还是集群层面的问题。
  • INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测、DSL 审计和流量治理,可以在请求到达 Elasticsearch 之前拦截并记录不合法的查询 DSL,便于提前发现问题。

6. 小结 #

array elements in include/exclude clauses should be string values 是一个典型的查询 DSL 类型错误,根因在于 include / exclude 数组中包含非字符串类型的元素。修复方法非常直接:确保所有数组元素均为字符串类型。通过显式类型转换、统一查询构建方法和在网关层做请求审计,可以有效预防此类问题再次发生。

相关错误 #

附:源码上下文 #

以下为 Elasticsearch 源码中触发此异常的相关逻辑,便于深入理解错误触发路径:

if (parser.currentToken() != XContentParser.Token.START_ARRAY) {
    throw new ElasticsearchParseException("Missing start of array in include/exclude clause");
}
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
    if (parser.currentToken().isValue() == false) {
        throw new ElasticsearchParseException("Array elements in include/exclude clauses should be string values");
    }
    set.add(new BytesRef(parser.text()));
}
return set;