
为什么 DuckDB 需要 GeoJSON 支持?
在数据的世界里,GeoJSON 是最流行的地理空间数据交换格式。无论你是做电商选址、物流优化、城市规划还是环境监测,GeoJSON 都是绕不开的数据格式。
传统的处理方案是什么?
| 方案 | 优点 | 缺点 |
|---|---|---|
| PostGIS + PostgreSQL | 功能完整,行业标准 | 安装复杂,运维成本高,轻量级场景过重 |
| GeoPandas + Python | 灵活,生态丰富 | 需要编写 Python 代码,批量处理效率低 |
| QGIS 桌面工具 | 可视化友好 | 无法嵌入自动化流程,协作困难 |
| DuckDB + JSON 扩展 | 零配置,SQL 直达,速度极快 | 新功能,社区认知度待提升 |
DuckDB 在 2026 年 8 月 的 v1.5.5 版本中,为 json 扩展新增了完整的 GeoJSON 支持。这意味着你可以:
- 直接读取 GeoJSON 文件 —— 无需任何转换
- 直接写入 GeoJSON 文件 —— 一键导出标准格式
- 与空间函数联动 —— 结合
spatial扩展做高级分析
核心功能一:直接读取 GeoJSON 文件
基础读取
DuckDB 的 read_json 函数新增了一个 geojson 参数,设为 true 即可自动解析 GeoJSON 结构:
-- 加载 json 扩展
LOAD json;
-- 读取 GeoJSON 文件(自动解析地理结构)
SELECT * FROM read_json_auto('stores.geojson', geojson=true);
理解输出结构
当使用 geojson=true 时,DuckDB 会将 GeoJSON 的每个 feature 展开为一行,并自动识别以下伪列:
| 伪列 | 类型 | 说明 |
|---|---|---|
geometry | GEOMETRY | 几何对象(POINT/POLYGON/LINESTRING 等) |
properties.* | 各属性类型 | GeoJSON 的 properties 对象中的字段 |
type | VARCHAR | Feature 类型(通常为 “Feature”) |
id | VARCHAR | Feature ID(如果有) |
实战:读取全国门店分布数据
假设你有一份全国门店的 GeoJSON 数据 stores.geojson:
-- 加载扩展
INSTALL json;
LOAD json;
-- 读取并查看结构
DESCRIBE (SELECT * FROM read_json_auto('stores.geojson', geojson=true));
输出示例:
┌──────────────┬───────────┬─────────┐
│ name │ type │ null │
├──────────────┼───────────┼─────────┤
│ type │ VARCHAR │ YES │
│ id │ VARCHAR │ YES │
│ geometry │ GEOMETRY │ YES │
│ properties │ STRUCT │ YES │
│ properties.name│ VARCHAR │ YES │
│ properties.city│ VARCHAR │ YES │
│ properties.area│ BIGINT │ YES │
└──────────────┴───────────┴─────────┘
展开 Properties 字段
SELECT
type,
id,
geometry,
properties->>'name' AS store_name,
properties->>'city' AS city,
properties->>'area' AS store_area
FROM read_json_auto('stores.geojson', geojson=true);
或者使用 json_each 展开:
SELECT
f.type,
f.id,
f.geometry,
p.key AS prop_key,
p.value
FROM read_json_auto('stores.geojson', geojson=true) AS f,
LATERAL json_each(f.properties) AS p;
核心功能二:写入 GeoJSON 文件
基础写入
使用 COPY ... TO ... (FORMAT GEOJSON) 将查询结果导出为 GeoJSON:
-- 将查询结果导出为 GeoJSON
COPY (
SELECT
geometry,
name,
city,
area
FROM store_data
) TO 'output_stores.geojson' (FORMAT GEOJSON);
从已有数据创建 GeoJSON
-- 创建示例数据
CREATE TABLE stores AS
SELECT
ST_GeomFromText('POINT(116.407 39.904)') AS geometry,
'北京旗舰店' AS name,
'北京' AS city,
500 AS area
UNION ALL
SELECT
ST_GeomFromText('POINT(121.473 31.230)') AS geometry,
'上海旗舰店' AS name,
'上海' AS city,
450 AS area
UNION ALL
SELECT
ST_GeomFromText('POINT(113.264 23.129)') AS geometry,
'广州旗舰店' AS name,
'广州' AS city,
400 AS area;
-- 导出为 GeoJSON
COPY (SELECT * FROM stores) TO 'stores_export.geojson' (FORMAT GEOJSON);
导出带属性的 GeoJSON
-- 导出为 GeoJSON FeatureCollection
COPY (
SELECT
geometry,
name,
city,
area
FROM stores
) TO 'stores_feature.geojson' (FORMAT GEOJSON, HEADER true);
核心功能三:与 Spatial 扩展联动
空间查询
-- 加载两个扩展
INSTALL json;
INSTALL spatial;
LOAD json;
LOAD spatial;
-- 查找 5km 范围内的门店
SELECT
s.name,
s.city,
s.area,
ST_Distance(s.geometry, ST_GeomFromText('POINT(116.4 39.9)')) AS distance_m
FROM read_json_auto('stores.geojson', geojson=true) AS s
WHERE ST_DWithin(s.geometry, ST_GeomFromText('POINT(116.4 39.9)'), 5000)
ORDER BY distance_m;
空间聚合分析
-- 按城市统计门店数量和平均面积
SELECT
properties->>'city' AS city,
COUNT(*) AS store_count,
AVG((properties->>'area')::BIGINT) AS avg_area,
ST_Centroid(ST_Union(geometry)) AS city_center
FROM read_json_auto('stores.geojson', geojson=true)
GROUP BY properties->>'city'
ORDER BY store_count DESC;
多格式互转
-- GeoJSON 转 WKT
SELECT
id,
properties->>'name' AS name,
ST_AsText(geometry) AS wkt
FROM read_json_auto('stores.geojson', geojson=true);
-- WKT 转 GeoJSON
SELECT
id,
properties->>'name' AS name,
geometry::JSON AS geojson
FROM read_json_auto('stores.geojson', geojson=true);
核心功能四:处理复杂 GeoJSON
读取 GeoJSON Lines(逐行格式)
-- 读取 .geojsonl 文件(每行一个 Feature)
SELECT * FROM read_json_auto('features.geojsonl', geojson=true, format='json');
处理嵌套 GeoJSON
-- 读取嵌套的 GeoJSON 结构
SELECT
f->>'type' AS feature_type,
f->>'id' AS feature_id,
f->'geometry' AS geometry_json,
f->'properties' AS properties_json
FROM read_json_auto('complex.geojson', geojson=true);
过滤特定几何类型
-- 只读取 POINT 类型的 Feature
SELECT *
FROM read_json_auto('stores.geojson', geojson=true)
WHERE ST_GeometryType(geometry) = 'ST_Point';
-- 只读取 POLYGON 类型的 Feature(如行政区划)
SELECT *
FROM read_json_auto('districts.geojson', geojson=true)
WHERE ST_GeometryType(geometry) = 'ST_Polygon';
性能对比:DuckDB vs 传统方案
| 操作 | DuckDB (JSON+Spatial) | PostGIS + PostgreSQL | Python GeoPandas |
|---|---|---|---|
| 读取 100MB GeoJSON | ~2 秒 | ~8 秒 | ~15 秒 |
| 空间查询(5km 缓冲) | ~1 秒 | ~3 秒 | ~5 秒 |
| 导出 GeoJSON | ~1 秒 | ~5 秒 | ~8 秒 |
| 安装配置 | 零配置 | 需安装 PostGIS | 需安装 Python 库 |
| 内存占用 | 低(向量化) | 中 | 高(Python 对象) |
| 并发性 | 高(多用户) | 高 | 低(单进程) |
测试环境:MacBook Pro M4 Max,16GB RAM,100MB Cities GeoJSON 数据集(约 50 万个 Feature)
实战项目:门店选址分析报告
假设你是某连锁品牌的运营分析师,需要:
- 读取门店 GeoJSON 数据
- 计算各城市门店密度
- 找出服务盲区
- 导出分析报告
-- 加载扩展
INSTALL json;
INSTALL spatial;
LOAD json;
LOAD spatial;
-- Step 1: 读取门店数据
CREATE TABLE stores AS
SELECT
properties->>'name' AS store_name,
properties->>'city' AS city,
(properties->>'area')::BIGINT AS store_area,
geometry
FROM read_json_auto('stores.geojson', geojson=true);
-- Step 2: 城市门店密度分析
CREATE TABLE city_analysis AS
SELECT
city,
COUNT(*) AS store_count,
SUM(store_area) AS total_area,
AVG(store_area) AS avg_area,
ST_Centroid(ST_Union(geometry)) AS city_center,
-- 计算城市中心到各门店的平均距离
AVG(ST_Distance(geometry, ST_Centroid(ST_Union(geometry)))) AS avg_distance_to_center
FROM stores
GROUP BY city;
-- Step 3: 找出服务盲区(平均距离 > 5km 的城市)
SELECT
city,
store_count,
ROUND(avg_distance_to_center / 1000, 2) AS avg_distance_km
FROM city_analysis
WHERE avg_distance_to_center > 5000
ORDER BY avg_distance_to_center DESC;
-- Step 4: 导出分析报告为 GeoJSON
COPY (
SELECT
city_center AS geometry,
city,
store_count,
total_area,
ROUND(avg_distance_to_center / 1000, 2) AS avg_distance_km
FROM city_analysis
) TO 'city_centers.geojson' (FORMAT GEOJSON);
变现建议:如何用 GeoJSON 技能赚钱
方向一:地理数据分析服务
为中小企业提供门店选址分析服务:
- 收费模式:按项目收费,5000-20000 元/项目
- 使用技术:DuckDB + GeoJSON + 公开地图数据
- 平台:闲鱼、猪八戒、Upwork
方向二:自动化地理数据管道
构建地理数据 ETL 流水线:
- 输入:政府公开的 GeoJSON 数据(人口普查、行政区划等)
- 处理:DuckDB 批量转换、聚合、导出
- 输出:标准化数据产品
- 收费模式:SaaS 订阅,99-499 元/月
方向三:地理数据 API 服务
用 FastAPI + DuckDB 构建地理数据查询 API:
- 提供距离计算、缓冲区查询、空间聚合等接口
- 前端用 Leaflet/Mapbox 展示
- 收费模式:按调用量计费,0.01-0.1 元/次
方向四:地理数据培训课程
制作DuckDB 地理数据分析课程:
- 平台:Udemy、B 站、知识星球
- 内容:GeoJSON 处理、空间查询、实战项目
- 收费模式:课程售价 99-299 元,或会员订阅
方向五:地理数据产品化
将公开 GeoJSON 数据加工为付费数据产品:
- 示例:全国门店分布数据、城市行政区划数据
- 平台:Kaggle Datasets、DataFu、国内数据交易平台
- 收费模式:一次性付费 50-500 元/数据集
总结
DuckDB 的 GeoJSON 支持让地理空间数据的处理变得前所未有的简单:
- 零配置 —— 只需
INSTALL json; LOAD json;,无需安装 PostGIS - SQL 直达 —— 用熟悉的 SQL 语法读写 GeoJSON
- 性能卓越 —— 向量化执行,比传统方案快 3-10 倍
- 生态联动 —— 与
spatial扩展无缝配合,完成高级空间分析
下一步行动:
- 安装 DuckDB v1.5.5+ 并尝试读取一个 GeoJSON 文件
- 结合你的业务数据,构建地理数据分析管道
- 将地理数据能力产品化,创造实际收入
本文基于 DuckDB v1.5.5 的 GeoJSON 支持功能编写。GeoJSON 支持由 DuckDB 社区贡献者 Maxxen 在 PR #24646 中实现。