适用版本: 7.17-8.9
1. 错误异常的基本描述 #
GeoJSON 'coordinates' must be an array 是 Elasticsearch 在解析地理空间数据(GeoJSON)时抛出的异常,表示传入的 coordinates 字段不符合 GeoJSON 规范中"坐标必须是数组"的要求。该错误通常发生在索引文档写入阶段或地理查询解析阶段。
常见现象 #
- 写入包含
geo_point或geo_shape类型字段的文档时,返回400 Bad Request,错误信息包含GeoJSON 'coordinates' must be an array。 - 使用地理查询(如
geo_distance、geo_bounding_box、geo_polygon)时,如果查询 DSL 中的坐标格式不正确,也会触发类似错误。 - Kibana 或客户端应用在执行地理可视化时失败,控制台显示坐标解析异常。
- 批量写入(Bulk API)中部分文档失败,错误日志指向特定文档的坐标字段。
典型报错与异常栈 #
{
"error": {
"root_cause": [
{
"type": "parse_exception",
"reason": "GeoJSON 'coordinates' must be an array"
}
],
"type": "parse_exception",
"reason": "GeoJSON 'coordinates' must be an array"
},
"status": 400
}
底层 Java 异常栈通常类似:
ElasticsearchParseException[GeoJSON 'coordinates' must be an array]
at org.elasticsearch.common.geo.GeoJsonParser.parseCoordinates(GeoJsonParser.java:XXX)
at org.elasticsearch.common.geo.GeoJsonParser.parsePoint(GeoJsonParser.java:XXX)
at org.elasticsearch.index.mapper.GeoPointFieldMapper.parse(GeoPointFieldMapper.java:XXX)
2. 为什么会发生这个错误 #
GeoJSON 是 RFC 7946 定义的地理空间数据交换格式,其中 coordinates 字段必须是一个数组。Elasticsearch 严格遵循该规范,在解析 geo_point 和 geo_shape 类型数据时会校验坐标格式。
常见原因包括:
- 坐标写成字符串而非数组:例如
"coordinates": "116.4,39.9"而不是"coordinates": [116.4, 39.9],这是最常见的错误形式。 - 坐标缺少外层数组包裹:点坐标应为
[经度, 纬度]的数组形式,直接传[116.4, 39.9]是正确的,但如果嵌套在 GeoJSON 对象中写成了"coordinates": { "lon": 116.4, "lat": 39.9 }且 Elasticsearch 期望纯数组时也会出错。 - GeoJSON 对象结构不完整:使用
type: "Point"时,缺少coordinates字段,或coordinates的值不是数组。 - 客户端序列化问题:某些 JSON 序列化库在处理坐标数组时,可能将
[116.4, 39.9]序列化成了{"0": 116.4, "1": 39.9}这样的对象形式。 - 数据源格式不统一:从不同系统导入数据时,坐标可能是字符串、对象或单值,未做统一转换就直接写入 Elasticsearch。
- 使用错误的数据结构:例如将多边形坐标写成了
[116.4, 39.9, 117.4, 40.9](一维数组),而多边形需要二维数组[[[116.4, 39.9], [117.4, 39.9], [117.4, 40.9], [116.4, 40.9], [116.4, 39.9]]]。
3. 如何排查这个异常 #
建议按以下顺序排查:
- 确认报错文档的坐标字段值:从报错信息中找到具体的文档 ID 或报错位置,检查该文档中
geo_point或geo_shape字段的原始数据。 - 对照 GeoJSON 规范检查格式:确认
coordinates是数组,且数组元素的类型和嵌套层级正确(点为一维数组[lon, lat],线为二维数组[[lon,lat], ...],面为三维数组[[[lon,lat], ...]])。 - 检查客户端代码中的坐标构造逻辑:确认坐标是通过数组形式构造的,而不是字符串拼接或对象字面量。
- 验证索引 Mapping:通过
GET /<index>/_mapping确认目标字段的类型定义,确认是geo_point还是geo_shape,以及是否有自定义ignore_malformed等设置。 - 在测试环境复现:用最小文档在测试索引中复现问题,逐步调整坐标格式直到写入成功。
排查时需要注意的问题 #
- Elasticsearch 中
geo_point支持多种格式(字符串"lat,lon"、对象{"lat": 39.9, "lon": 116.4}、数组[lon, lat]、WKT),但 GeoJSON 格式严格要求数组形式,混合使用容易出错。 geo_shape类型严格遵循 GeoJSON 规范,coordinates必须是数组,不支持其他简写形式。- 批量写入时,单个文档的坐标错误会导致该文档失败,但不影响同批次其他文档,需要检查 Bulk API 的响应中每个 item 的状态。
4. 如何解决这个错误 #
常用修复思路 #
修复坐标格式(geo_point 类型):
确保坐标以数组形式传递,注意 Elasticsearch 的数组顺序是 [经度, 纬度](即 [longitude, latitude]),与日常习惯的"纬度在前"相反:
{
"location": [116.4, 39.9]
}
或者使用 GeoJSON 完整结构:
{
"location": {
"type": "Point",
"coordinates": [116.4, 39.9]
}
}
修复坐标格式(geo_shape 类型):
geo_shape 必须使用标准 GeoJSON 格式,coordinates 必须是数组:
{
"geometry": {
"type": "Point",
"coordinates": [116.4, 39.9]
}
}
线(LineString)坐标示例:
{
"geometry": {
"type": "LineString",
"coordinates": [
[116.4, 39.9],
[116.5, 40.0],
[116.6, 40.1]
]
}
}
多边形(Polygon)坐标示例:
{
"geometry": {
"type": "Polygon",
"coordinates": [
[
[116.4, 39.9],
[117.4, 39.9],
[117.4, 40.9],
[116.4, 40.9],
[116.4, 39.9]
]
]
}
}
修复客户端代码:
以 Python 为例,确保坐标构造为列表(数组):
# 错误写法
doc = {"location": f"{lat},{lon}"} # 字符串,可能触发错误
# 正确写法
doc = {"location": [lon, lat]} # 数组形式,注意顺序是 [经度, 纬度]
# 或使用 GeoJSON 结构
doc = {
"location": {
"type": "Point",
"coordinates": [lon, lat]
}
}
以 Java 为例:
// 错误写法
Map<String, Object> doc = new HashMap<>();
doc.put("location", lat + "," + lon); // 字符串
// 正确写法
List<Double> coords = Arrays.asList(lon, lat); // 数组
Map<String, Object> geoJson = new HashMap<>();
geoJson.put("type", "Point");
geoJson.put("coordinates", coords);
doc.put("location", geoJson);
后续注意事项与推荐建议 #
- 在数据写入前做坐标格式校验,确保
coordinates是数组类型,可以借助 JSON Schema 或应用层校验拦截非法数据。 - 如果数据源坐标格式不统一,建议在数据导入 ETL 流程中做标准化处理,统一转为
[lon, lat]数组格式。 - 对
geo_shape字段,建议在索引 Mapping 中设置"ignore_malformed": false(默认),让格式错误尽早暴露,而不是静默忽略。 - 建立地理字段的单元测试,覆盖点、线、面等常见 GeoJSON 类型的写入场景,防止回归。
借助 INFINI 产品提升排障效率 #
- INFINI Console 适合查看索引 Mapping、文档内容、写入错误详情和集群健康状态,帮助快速判断坐标格式是否符合预期。
- INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测、流量录制和异常请求定位,可以直接捕获写入失败的原始请求体,快速找到格式错误的坐标数据。
5. 小结 #
GeoJSON 'coordinates' must be an array 错误的根因是传入的地理坐标数据不符合 GeoJSON 规范中"坐标必须是数组"的要求。修复时只需确保 coordinates 字段的值是数组类型,并注意 Elasticsearch 中坐标顺序为 [经度, 纬度]。对于 geo_shape 类型,严格使用标准 GeoJSON 格式即可避免此类问题。
在数据处理链路中尽早做格式校验和标准化,是防止此类异常反复出现的根本方法。
相关错误 #
相关链接 #
附:日志上下文 #
下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:
coordinates = new ArrayList<>();
while (subParser.nextToken() != Token.END_ARRAY) {
coordinates.add(parseValidDouble(subParser, field));
}
} else {
throw new ElasticsearchParseException("GeoJSON 'coordinates' must be an array");
}
} else if (TYPE.equals(field)) {
if (subParser.currentToken() == Token.VALUE_STRING) {
geojsonType = subParser.text();
} else {





