Skip to main content

说明

GeoJSON 数据以单个 FeatureCollection 文档的形式进行交换,ClickHouse 会将其映射到三列——idgeometryproperties——每个 Feature 对应一组。读取文档时,每个 Feature 会生成一行;写入时,每一行会生成一个 Feature

读取数据

读取 FeatureCollection 时,每个要素都会生成一行,并采用以下固定 schema: 每个几何数据都存储在 ClickHouse 的 Geometry 类型中 (即一种 Variant) 。支持的 GeoJSON 几何类型包括 PointLineStringMultiLineStringPolygonMultiPolygon。另外两种 GeoJSON 几何类型 GeometryCollectionMultiPoint 无法由 Geometry 类型表示;默认情况下,如果将其读入 geometry 列,会引发异常,但也可以改为插入 NULL——参见下文的处理不支持的几何类型。默认情况下,只有当要素的几何数据是显式的 JSON null 时,geometry 列才为 NULL;在 input_format_geojson_unsupported_geometry_handling = 'null' 下,不支持的几何类型也会记为 NULL 系统会验证文档的结构:顶层 type 必须是 FeatureCollection,并且 features 中的每个元素都必须具有 type Feature。默认情况下,坐标必须满足 GeoJSON 的形态不变量——LineString (以及 MultiLineString 中的每一条线) 必须至少包含两个点,而 Polygon 的 Ring (以及 MultiPolygon 中的每个 Ring) 必须闭合且至少包含四个点 (参见几何校验) 。格式错误的文档会被拒绝,而不会静默加载。 键的顺序很灵活:顶层 type 可以出现在 features 数组之前或之后,在几何对象内部,coordinates 也可以出现在 type 之前或之后。 schema 推断会返回上述固定 schema,因此 DESCRIBESELECT ... FROM format(...) 无需表定义即可工作。 给定以下 GeoJSON 文件 london.geojson,其中包含多种几何类型:
我们可以查询该文件并查看几何类型:
Query
Response
文件扩展名 .geojson 会被自动检测到,因此可以省略 format 参数:
Query
我们可以使用 variantType 来判断每个 Geometry 对象的实际类型:
Query
Response
我们还可以这样提取底层数据:
Query
Response
访问 Geometry 子列时,如果该行存储的是该类型,则返回该值;否则返回该类型的默认值——Point(0,0),基于数组的类型为 []——因此请使用 variantType(geometry) 来判断当前设置的是哪种类型。 我们也可以将 GeoJSON 数据摄取到表中:
Query
然后按要素类型进行查询:
Query
Response
无需表定义,我们也可以推断 GeoJSON 数据的 schema:
Query
Response

处理不支持的几何类型

某些有效的 GeoJSON 几何类型 — 例如 GeometryCollectionMultiPoint — 无法用 ClickHouse 的 Geometry 类型表示。你可以使用 input_format_geojson_unsupported_geometry_handling 设置,控制当这类几何对象必须存储到 geometry 列中时应如何处理。可能的值为:
  • 'throw' — 抛出异常 (默认)
  • 'null' — 为 geometry 列插入 NULL 值并继续解析
这种处理方式仅在读取 geometry 列时适用。当 geometry 不是请求输出的列时 (例如 SELECT id FROM ...) ,不受支持的几何对象仍会验证其格式是否正确,但不会触发该处理方式——既不会抛出异常,也不会插入 NULL,因为不会将任何几何值 materialize。

限制

读取时只能反映固定 schema 所能容纳的内容,因此部分 GeoJSON 信息无法保留:
  • 只会生成 idgeometryproperties;其他文档结构不会作为列公开。
  • 位置的第三个 (高程) 坐标以及其后的所有坐标都会被丢弃——位置将变为 [longitude, latitude]
  • bbox 和外部成员 (例如顶层的 namecrs,或 Feature 内部的额外成员) 都会被忽略。
  • 数值型 id 会以文本形式存储,因此字符串与数字的区别会丢失;缺失或为 nullid 会变为 NULL
  • GeometryCollectionMultiPoint 无法表示——请参阅处理不支持的几何类型

写入数据

写入结果集时会生成一个 GeoJSON FeatureCollection,其中每一行对应一个 Feature 结果中的列会按如下方式映射到各个 Feature 几何类型列可以是 Geometry Variant,也可以是某种具体的 Geo 类型;每种类型都会映射为相应的 GeoJSON 几何类型: Ring 不是 GeoJSON 几何类型——linear ringPolygon 的一个组成部分——因此,Ring 值会写为只包含单个环的 Polygon

示例

继续以上文创建london 表为例,导出普通属性列时,会将除 idgeometry 之外的每一列都转换为一个属性:
Query
Response
由于名为 properties 的唯一对象类型列会被直接写出,因此,读取 GeoJSON 文件并直接原样写回时会重现该文档 (为该文件推断出的列是 idgeometryproperties) :
Query
Response
数值型 id 列会以 JSON 数值形式写入 (如果 NullableidNULL,则会被完全省略) :
Query
Response
Ring 可写作单环 Polygon
Query
Response

写入文件

使用 INTO OUTFILE 可将客户端中的数据写出为 GeoJSON 文件:
Query
服务器本身可以使用 file 表函数写入该文件 (.geojson 扩展名会自动选择格式) :
Query

限制

ClickHouse 的 geo types 不包含坐标参考系统,因此输出会假定坐标已是 WGS84 经纬度,并按 [longitude, latitude] 顺序排列,这也是 RFC 7946 的要求。不会执行重投影或坐标轴交换,因此投影坐标——或以 (latitude, longitude) 形式存储的数据——会生成结构有效但不符合规范的 GeoJSON。
输出只反映 ClickHouse 中实际存储的内容:
  • 读取时丢失的信息——位置高程、bbox、外部成员,以及 id 的字符串/数字类型区别——都无法恢复;请参见读取限制
  • 坐标从 Float64 值写出时,会使用其可无损往返的最短表示形式。
  • 直接取自 JSON 列的 properties 对象,会按 JSON 类型的规范键顺序输出,这可能与输入顺序不同。
几何对象会严格按存储内容写出——坐标顺序和绕向都会被保留。默认情况下,写出时会强制校验 GeoJSON 几何形状的有效性 (参见几何校验) :如果某个几何对象不是有效的 GeoJSON 形状,例如只有一个点的 LineString,或未闭合的 Polygon Ring,则会被拒绝,以确保写出的文档能够被正确读回。将 format_geojson_validate_geometry = 0 设为 0 后,则会按原样输出这类几何对象,从而生成结构有效但不符合规范的 GeoJSON。无论是否这样设置,都不会强制执行右手法则 (绕向) 不变式,并且会保留 null 与空 properties 对象之间的区别。

几何校验

设置 format_geojson_validate_geometry 用于控制该格式在读写两个方向上是否都强制遵循 RFC 7946 的几何形态规则。该设置默认启用。 启用后,违反 GeoJSON 形态规则的几何体会被拒绝:点数少于两个的 LineString (或 MultiLineString 中的一条线) ;点数少于四个,或首尾点不同 (即未闭合 Ring) 的 PolygonMultiPolygon 的 Ring;以及空的 MultiLineStringPolygonMultiPolygon。读取此类文档和写入此类 ClickHouse 值时适用的规则完全相同,因此写出的文档始终都能再读回来。 禁用后,这些形态规则在两个方向上都不会强制执行:退化几何体会按原样读取,也会按原样写出。这样一来,那些不是有效 GeoJSON 几何体的 ClickHouse 几何值也可以通过该格式往返转换,但代价是生成的文档将不是有效的 GeoJSON。 这种校验仅限于结构层面:只检查点数和 Ring 是否闭合。它不会检查形状在几何意义上的正确性,因此结构有效但几何上退化的几何体在两个方向上都会被接受——例如面积为零的多边形、自相交的 Ring,或者孔 (内 Ring) 位于外 Ring 之外的多边形。同样,多边形 Ring 的右手法则 (绕向) 也从不会被强制要求。 有一项检查独立于该设置:非有限坐标 (NaNInf) 始终会被拒绝,因为它们无法表示为 JSON 数字。
最后修改于 2026年7月23日