Featured image of post DuckDB 地理空间分析实战:从坐标到商业洞察

DuckDB 地理空间分析实战:从坐标到商业洞察

用 DuckDB 内置 ST_ 系列函数做地理空间分析——距离计算、缓冲区查询、热力图生成,无需 PostGIS。适合电商选址、物流优化、用户画像等场景。

DuckDB 地理空间分析实战:从坐标到商业洞察

为什么现在需要地理空间分析?

在电商、物流、零售行业,地理位置就是钱

  • 外卖平台需要根据用户位置推荐最近的商家
  • 连锁品牌选址要看周边 3 公里内的人流和竞争
  • 物流公司要计算最优配送路径
  • 金融风控需要识别异常交易地点

传统方案是什么?PostGIS + PostgreSQL,或者 Python 的 GeoPandas + Shapely。但这些都是重型工具——安装复杂、运维成本高、学习曲线陡峭。

DuckDB 的出现改变了这一切。内置的 ST_ 系列空间函数让你能在纯 SQL 中完成 90% 的地理空间分析需求,而且速度极快。


核心能力一览

DuckDB 的空间扩展提供了完整的 OGC Simple Features 标准支持:

功能类别常用函数典型场景
距离计算ST_Distance, ST_DWithin查找附近门店
缓冲区ST_Buffer划定服务半径
包含关系ST_Contains, ST_Within判断是否在区域内
相交检测ST_Intersects碰撞检测
中心点ST_Centroid区域中心计算
面积周长ST_Area, ST_Perimeter地块分析
最近邻ST_NearestPoint最优匹配

第一步:启用空间扩展

-- 加载空间扩展(首次需要下载)
LOAD spatial;
INSTALL spatial;

-- 验证安装
SELECT version();

第二步:创建地理空间数据集

假设你是一家连锁咖啡店的运营分析师,手头有:

  1. 全国门店列表(经纬度)
  2. 竞品门店列表
  3. 商圈 POI 数据
LOAD spatial;

-- 创建门店表
CREATE TABLE my_stores AS
SELECT * FROM (VALUES
    ('北京三里屯店',   116.4510, 39.9320),
    ('上海南京路店',   121.4730, 31.2300),
    ('广州天河路店',   113.3250, 23.1300),
    ('深圳华强北路',   114.0650, 22.5400),
    ('成都春熙路店',   104.0800, 30.6600),
    ('杭州西湖路店',   120.1500, 30.2800),
    ('武汉江汉路店',   114.2800, 30.5800),
    ('重庆解放碑店',   106.5800, 29.5600)
) AS t(name, longitude, latitude);

-- 创建竞品门店表
CREATE TABLE competitor_stores AS
SELECT * FROM (VALUES
    ('星巴克三里屯',   116.4530, 39.9340),
    ('瑞幸三里屯',     116.4490, 39.9310),
    ('星巴克南京路',   121.4750, 31.2320),
    ('瑞幸南京路',     121.4710, 31.2280),
    ('Manner天河路',   113.3270, 23.1320),
    ('瑞幸华强北',     114.0670, 22.5420)
) AS t(name, longitude, latitude);

-- 将经纬度转换为 WKT 几何对象
ALTER TABLE my_stores ADD COLUMN geom GEOMETRY;
UPDATE my_stores SET geom = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326);

ALTER TABLE competitor_stores ADD COLUMN geom GEOMETRY;
UPDATE competitor_stores SET geom = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326);

第三步:距离分析 —— 找到你的"安全距离"

最基础也最有价值的分析:我的门店和竞品之间隔多远?

-- 计算每对门店之间的距离(单位:米)
SELECT 
    m.name AS my_store,
    c.name AS competitor,
    ROUND(
        ST_Distance(
            ST_Transform(m.geom, 3857),  -- 转为 Web Mercator(米制坐标系)
            ST_Transform(c.geom, 3857)
        )::INTEGER
    ) AS distance_meters,
    CASE 
        WHEN ST_Distance(
            ST_Transform(m.geom, 3857),
            ST_Transform(c.geom, 3857)
        ) < 500 THEN '⚠️ 直接竞争'
        WHEN ST_Distance(
            ST_Transform(m.geom, 3857),
            ST_Transform(c.geom, 3857)
        ) < 1000 THEN '📊 潜在竞争'
        ELSE '✅ 安全距离'
    END AS competition_level
FROM my_stores m
CROSS JOIN competitor_stores c
WHERE ST_DWithin(
    ST_Transform(m.geom, 3857),
    ST_Transform(c.geom, 3857),
    1000  -- 1000米范围内
)
ORDER BY distance_meters;

业务洞察:

  • 北京三里屯店距离两家竞品都小于 500 米 → 激烈竞争区,需要差异化策略
  • 成都春熙路店没有竞品在 1km 内 → 蓝海市场,可考虑加大投放

第四步:缓冲区分析 —— 划定你的"辐射圈"

-- 为每家门店创建 500 米服务半径缓冲区
CREATE TABLE store_buffers AS
SELECT 
    name,
    ST_Buffer(ST_Transform(geom, 3857), 500) AS buffer_geom
FROM my_stores;

-- 查询每个缓冲区内有多少家竞品
SELECT 
    s.name AS store,
    COUNT(c.name) AS nearby_competitors
FROM store_buffers s
LEFT JOIN competitor_stores c 
    ON ST_Contains(s.buffer_geom, ST_Transform(c.geom, 3857))
GROUP BY s.name
ORDER BY nearby_competitors DESC;

变现建议: 这个分析可以直接做成 SaaS 产品——面向连锁品牌的"选址助手"。输入地址,输出竞品密度热力图,月费 299 元起。


第五步:最近邻搜索 —— 智能派单

-- 给定一个新订单位置,找到最近的 3 家门店
WITH order_location AS (
    SELECT ST_SetSRID(ST_MakePoint(116.4550, 39.9350), 4326)::GEOMETRY AS geom
)
SELECT 
    m.name,
    ROUND(ST_Distance(
        ST_Transform(m.geom, 3857),
        ST_Transform(o.geom, 3857)
    )) AS distance_m
FROM my_stores m, order_location o
ORDER BY distance_m
LIMIT 3;

第六步:从外部数据源加载真实地理信息

DuckDB 可以直接读取 GeoJSON 文件:

-- 加载城市商圈 GeoJSON
CREATE TABLE districts AS
SELECT 
    feature->>'name' AS district_name,
    feature->>'population' AS population,
    st_geomfromjson(feature->'geometry') AS geom
FROM read_geojson('https://example.com/china-districts.geojson');

-- 统计每个商圈内有多少门店
SELECT 
    d.district_name,
    d.population,
    COUNT(m.name) AS store_count,
    ROUND(d.population::DOUBLE / NULLIF(COUNT(m.name), 0), 0) AS per_store_population
FROM districts d
LEFT JOIN my_stores m ON ST_Contains(d.geom, m.geom)
GROUP BY d.district_name, d.population
ORDER BY per_store_population;

与传统方案对比

维度PostGIS + PostgreSQLGeoPandas (Python)DuckDB Spatial
安装难度高(需编译)低(一行 SQL)
学习成本低(SQL 语法)
大数据量差(内存限制)优秀(列式存储)
交互式分析一般极好
部署运维极轻
适合场景生产级 GIS地理可视化快速分析/原型

变现建议

地理空间分析是高价值 B 端服务的核心能力:

  1. 选址 SaaS:面向连锁品牌,输入候选地址,自动输出竞品密度、人流预测、租金性价比评分。参考定价:500-2000 元/月/企业。

  2. 物流优化 API:为电商平台提供"最近仓库/门店"查询接口,按调用量收费。单次查询成本几乎为零。

  3. 房地产估值辅助:结合房价数据和 POI 距离(地铁站、学校、商场),生成区域价值评分报告。

  4. 营销精准投放:基于用户 GPS 轨迹,分析消费偏好区域,为品牌方提供定向广告投放建议。

关键优势:DuckDB 的空间分析可以在单机上处理千万级地理要素,不需要分布式集群。这意味着你可以用极低的硬件成本(甚至树莓派)搭建完整的服务。


总结

DuckDB 的空间扩展让地理空间分析变得前所未有的简单:

  • 零安装LOAD spatial 即可使用
  • 标准 SQL:所有空间函数遵循 OGC 标准
  • 高性能:列式存储 + 向量化执行,比 Pandas 快 10-50 倍
  • 可扩展:支持 GeoJSON、WKT、WKB 等多种格式互转

对于数据分析师来说,这意味着你可以在同一个工作流中完成:数据采集 → 地理分析 → 报表生成 → 可视化导出,全部用 SQL 搞定。

💡 更多 DuckDB 地理空间分析案例和商业应用 → duckdblab.org

📺 Watch video tutorials → Olap Studio YouTube

Subscribe for more DuckDB & AI automation tutorials

使用 Hugo 构建
主题 StackJimmy 设计

⚠️ 本站为独立社区项目,与 DuckDB 基金会及 DuckDB 官方项目无任何从属、背书或赞助关系。

"DuckDB" 是 DuckDB 基金会的注册商标,本站仅以事实描述方式使用该名称。

本站内容仅供教育与社区推广用途,不构成任何商业服务。