路网分析服务最容易被忽视的故障,往往不是最短路算法算错,而是一个不存在的节点或负数阈值让 API 给出崩溃、空结果或前后不一致的响应。pgRouting 4.0.2 的官方发布聚焦这类边界:修复 pgr_dijkstraVia 与 pgr_withPointsVia 的 bad_alloc,并把 pgr_drivingDistance、pgr_withPointsDD 对负 distance 的处理统一为抛错。对以 PostGIS 提供路径、等时圈或服务覆盖分析的团队,这是一份很具体的提醒:路由的输入语义、错误结构和零值边界,都应成为版本升级的验收对象。
本文依据 pgRouting 4.0.2 的 GitHub Release 与关联 issue #3110、#3091 整理。文中给出的测试路径是工程建议,不能替代团队对自身图数据、成本字段、权限和业务口径的验证。
可核查事实
-
pgRouting 4.0.2 在 GitHub 上发布于 2026 年 9 月 5 日,发布包同时提供英文与西班牙文文档压缩包,以及源码 tar.gz 与 zip。
-
Release 记录
pgr_dijkstraVia的bad alloc修复,并将问题关联到 #3110。 -
#3110 的复现条件是:传给
pgr_dijkstraVia的节点数组中有一个节点不存在于图中;报告曾得到std::bad_alloc,而提案的期望是不要抛出该异常。 -
4.0.2 同时修复
pgr_withPointsVia的bad alloc。 -
Release 表明
pgr_drivingDistance与pgr_withPointsDD对distance < 0改为抛异常,并采用统一的错误消息和 hint。 -
#3091 记录了 4.0.1 中四类 catchment 函数的差异:
pgr_primDD与pgr_kruskalDD已对负数报错,pgr_drivingDistance曾只给 NOTICE 后返回 0 行,pgr_withPointsDD使用不同错误且错误拒绝distance = 0。 -
#3091 的期望行为是:负 distance 报错,
distance = 0合法并只返回根节点;该 issue 在与发布相同的 2026 年 9 月 5 日关闭。
这些事实说明,此版本的价值不在于引入新路线算法,而在于让异常输入更可预测。对调用者来说,“0 行”“NOTICE”“数据库内部异常”和结构化参数错误是完全不同的控制流。
核心机制
路网服务至少有三层合同。第一层是图合同:edge SQL 返回的 id、source、target、cost 与 reverse_cost 是否满足建图假设,节点是否确实存在。第二层是参数合同:起终点、途经点、distance、方向和点位投影是否处于函数可接受的范围。第三层是响应合同:非法请求应当产生稳定、可分类的错误;合法但没有可达结果才应产生空集合。
4.0.2 所处理的问题正处于后两层的交界。若一个不存在节点把服务带到 std::bad_alloc,调用方无法区分“查询无路径”和“服务异常”。若负的 catchment 阈值静默返回空行,业务系统又可能把参数错误解释为“附近没有设施”。统一拒绝负数、接受零值的语义,能让客户端把输入校验、重试和用户提示建立在明确的状态上。
GIS 场景
设想应急调度系统要返回指定医院在 15 分钟或 5 公里网络阈值内的补给点。请求到达后,服务先核查医院映射的图节点是否仍在当前网络版本中,再验证阈值非负。阈值为 0 时,应把它当作可复现的边界请求:结果只允许包含起点本身或业务规则明确允许的同位实体;不能把它误报成系统故障。阈值为负时,应在 API 边界直接返回明确的 4xx 参数错误,而非把负数送入数据库等待不同函数各自处理。
路径经由多个站点时,同样要覆盖不存在的中间节点。应用可先根据网络版本查节点表,再调用 pgr_dijkstraVia;即使数据库升级后已避免特定的 bad_alloc,前置校验仍能给用户指出哪个 ID 不存在,并防止把基础设施异常暴露为业务错误。对历史路线重跑,应记录图版本、edge SQL 哈希、节点数组和 pgRouting 版本,否则无法解释同一请求为什么在更新后得到不同结果。
技术路径
把回归集按“有效输入、无可达路径、缺失节点、负阈值、零阈值”分类。每个用例固定一个最小 edge 表、请求参数和期望的 HTTP/SQL 结果类别。升级前后分别运行 pgr_dijkstraVia、pgr_withPointsVia、pgr_drivingDistance 与 pgr_withPointsDD:至少断言缺失节点不会转化为进程级异常、负 distance 不会被默认为空结果、零 distance 的处理与业务口径一致。
服务层不要依赖数据库错误文本来承担全部产品语义。对可提前发现的输入,返回机器可读的错误码,如 node_not_found、invalid_distance;同时保留数据库错误类别、pgRouting/PostGIS 版本和请求追踪 ID 到受控日志。对于合法的无路径响应,单独返回 no_route 或空 FeatureCollection,并明确与参数错误区分。这样客户端的地图提示、批处理重试和监控告警都不会把三种情况混在一起。
发布时,把网络数据更新与扩展更新拆开验收。先在副本图上跑最小回归集,再以固定城市区域的真实 OD 样本比较命中、总 cost、边数与响应时间。若 edge SQL、方向字段或 cost 的单位发生改变,就把它视为图合同改变,而不是将差异归因于 pgRouting 小版本。
风险边界
4.0.2 的发布说明覆盖的是列出的函数和问题,不保证所有 routing、turn restriction、拓扑构建或自定义 edge SQL 都具有相同表现。一个节点存在也不表示它与目标可达;空结果仍可能来自方向、成本、孤岛、过滤条件或图版本。统一负数检查也不能替代业务阈值上限、坐标系检查、输入授权和查询资源限制。生产升级必须在实际 PostgreSQL、PostGIS、数据规模和并发条件下复验。
检查清单
-
固定图版本、edge SQL、PostgreSQL、PostGIS 与 pgRouting 版本,并随路由结果记录。
-
对起终点和途经点先做节点存在性检查,再调用路线函数。
-
为负 distance 返回稳定的参数错误;明确验证 0 distance 的结果只含允许的根节点语义。
-
分别测试合法无路径、缺失节点、负阈值与零阈值,禁止把它们都解释为空结果。
-
升级后覆盖
pgr_dijkstraVia、pgr_withPointsVia、pgr_drivingDistance与pgr_withPointsDD的最小复现用例。 -
用真实 OD 样本比较升级前后的命中、cost、边数与时延,并保留差异证据。
-
在 API 与日志中区分
node_not_found、invalid_distance、no_route和数据库故障,避免错误重试。
结论
可靠的网络分析不是只验证一条路线能否画在地图上,而是让异常节点、负阈值、零阈值和不可达结果都拥有稳定含义。pgRouting 4.0.2 提供了可复核的边界修复;团队把这些边界写入回归合同,才能让版本升级真正降低路由服务的不确定性。
参考来源
-
pgRouting v4.0.2 Release:https://github.com/pgRouting/pgrouting/releases/tag/v4.0.2
-
pgRouting issue #3110:https://github.com/pgRouting/pgrouting/issues/3110
-
pgRouting issue #3091:https://github.com/pgRouting/pgrouting/issues/3091