第07章 - 空间分析实战
本章通过演示方案 01(01-school-service-area.json)讲解如何用 OpenGIS DAF 完成一条完整的空间分析流水线:坐标转换 → 缓冲 → 裁剪 → 字段标注 → 空值填充。
7.1 业务场景
“新星市”有 8 所学校(点要素)与一个城市边界(面要素)。业务需求是:为每所学校生成 800 米服务区,裁剪到城市边界内,并为每个服务区标注所属学校名称、补全缺失的校长信息。
7.2 方案设计
方案 01 是一个 6 步 DAG,前两步无依赖可并行:
transform-schools ──→ buffer-schools ──→ clip-service-area ──→ label-zones ──→ fill-principal
transform-boundary ────────────────────────↗
完整方案配置:
{
"id": "demo-01-school-service-area",
"name": "学校服务区分析(坐标转换 → 缓冲 → 裁剪 → 字段标注 → 空值填充)",
"version": "1.0.0",
"group": "demo",
"items": [
{
"id": "transform-schools",
"operatorId": "coordinate_transform",
"inputs": { "source": { "type": "external", "sourceId": "data/schools.geojson" } },
"parameters": { "source_epsg": 4326, "target_epsg": 3857 },
"output": { "adapterType": "console", "isIntermediate": true }
},
{
"id": "transform-boundary",
"operatorId": "coordinate_transform",
"inputs": { "source": { "type": "external", "sourceId": "data/city_boundary.geojson" } },
"parameters": { "source_epsg": 4326, "target_epsg": 3857 },
"output": { "adapterType": "console", "isIntermediate": true }
},
{
"id": "buffer-schools",
"operatorId": "buffer",
"inputs": { "source": { "type": "upstream", "sourceId": "transform-schools" } },
"parameters": { "distance": 800 },
"output": {
"adapterType": "geojson",
"targetPath": "output/demo01/school-buffer-800m.geojson",
"isIntermediate": true
},
"executionPolicy": { "timeout": "00:05:00", "maxRetries": 1, "retryInterval": "00:00:02" }
},
{
"id": "clip-service-area",
"operatorId": "clip",
"inputs": {
"source": { "type": "upstream", "sourceId": "buffer-schools" },
"clip": { "type": "upstream", "sourceId": "transform-boundary" }
},
"output": {
"adapterType": "geojson",
"targetPath": "output/demo01/school-service-area.geojson",
"isIntermediate": true
}
},
{
"id": "label-zones",
"operatorId": "field_calculator",
"inputs": { "source": { "type": "upstream", "sourceId": "clip-service-area" } },
"parameters": {
"target_field": "zone_label",
"expression": "\"服务区-{school_name}\"",
"field_type": "String"
},
"output": {
"adapterType": "geojson",
"targetPath": "output/demo01/school-service-area-labeled.geojson",
"isIntermediate": true
}
},
{
"id": "fill-principal",
"operatorId": "null_value_filler",
"inputs": { "source": { "type": "upstream", "sourceId": "label-zones" } },
"parameters": {
"target_field": "principal",
"default_value": "(未登记)",
"field_type": "String"
},
"output": {
"adapterType": "geojson",
"targetPath": "output/demo01/school-service-area-final.geojson"
}
}
],
"executionPolicy": { "failurePolicy": "stopOnAny", "maxParallelism": 4 }
}
7.3 逐步解读
7.3.1 坐标转换(transform-schools / transform-boundary)
输入数据是 EPSG:4326(经纬度)。缓冲距离 800 在经纬度下没有意义(800 度),因此先转换到 EPSG:3857(Web 墨卡托,米制单位),使 distance: 800 表示 800 米。
两个转换项互不依赖,在 maxParallelism: 4 下可并行执行。
7.3.2 缓冲区(buffer-schools)
对转换后的学校点生成 800 米缓冲区。此处理项配置了 item 级执行策略:
"executionPolicy": { "timeout": "00:05:00", "maxRetries": 1, "retryInterval": "00:00:02" }
timeout:单步超时 5 分钟;maxRetries:失败重试 1 次;retryInterval:重试间隔 2 秒。
7.3.3 裁剪(clip-service-area)
用城市边界(clip 输入)裁剪学校缓冲区(source 输入)。位于城市边界外的学校缓冲区被裁剪掉——演示数据中 s08 学校在界外,因此 8 个缓冲区裁剪后剩 7 个服务区。
7.3.4 字段标注(label-zones)
用 field_calculator 拼接字符串生成服务区标签:
表达式:"服务区-{school_name}" → 结果:服务区-新星一中
7.3.5 空值填充(fill-principal)
用 null_value_filler 将 principal 字段的 2 个 null 值填充为”(未登记)”。这是方案的最终输出(未标记 isIntermediate)。
7.4 中间结果与 isIntermediate
方案前 5 步的输出都标记了 isIntermediate: true。这表示:
- 结果是中间产物,供下游算子复用;
- 框架可缓存中间结果,避免重复计算;
- 只有最后一步
fill-principal未标记,是方案的最终产物。
7.5 运行与产物
daf run --plan plans/01-school-service-area.json
运行产物位于 output/demo01/:
| 文件 | 说明 |
|---|---|
school-buffer-800m.geojson |
学校 800 米缓冲区 |
school-service-area.geojson |
裁剪到城市边界内的服务区 |
school-service-area-labeled.geojson |
标注学校名称的服务区 |
school-service-area-final.geojson |
最终结果(含空值填充) |
CRS 传播:
school-buffer-800m.geojson头部带crs: urn:ogc:def:crs:EPSG::3857,说明坐标系随数据流传播到了输出。
7.6 动手练习
- 改缓冲距离:把
buffer-schools的distance从 800 改为 2000,观察 s08 的缓冲区是否与城市边界相交,clip输出是否从 7 变 8; - 加质检前置:在方案开头插入一个
geometry_validity_checker处理项,先检查学校数据质量再分析; - 改输出格式:把最终输出从
geojson改为shapefile,观察生成的五件套文件。
7.7 本章小结
- 空间分析流水线由多个算子通过
upstream绑定串联成 DAG; - 缓冲距离单位取决于坐标系,经纬度数据需先转米制坐标系;
- 无依赖的处理项可并行执行(
maxParallelism); isIntermediate标记中间结果,供下游复用;- 坐标系随数据流传播到输出(GeoJSON 写
crs,Shapefile 写.prj)。