业务问题:内容相同的 GeoPackage,为何会让交付缓存失效

GeoLens v1.15.1 的官方发布说明记录了一个很容易被忽略的 GIS 数据工程问题:两次导出未变化的数据,仍可能得到不同字节的 GeoPackage。即使已经规范化时间戳,SQLite 文件头中偏移 24–27 与 92–95 的 file-change-counter 仍会随着事务次数变化。对人而言,两个文件内容相同;对以哈希驱动的制品缓存、下载校验和可重现构建而言,它们却是不同文件。

这会带来连锁反应:缓存拒绝复用、范围请求的交付策略被关闭、CI 将无意义差异误判为回归。空间数据交付不只要检查要素和属性,也要检查文件级确定性。

资料依据:修复的是 SQLite 头字段,不是地理要素本身

该 release 发布于 2026 年 8 月 24 日。说明称,v1.15.1 在 SQLite 连接关闭后,将上述两段头字段改为从已规范化的文件内容推导,使相同导出保持字节确定性,同时避免不同数据得到同一个值。这里的关键在于处理发生在连接关闭之后:若在 SQLite 仍写入时修改头部,后续事务仍可能改变文件。

验收时可区分两层:先在相同输入、相同软件版本与相同参数下导出两次,比较 SHA-256;若不一致,再检查空间要素、表结构、元数据与 SQLite 头部。哈希一致也不等于业务结果正确,它只证明同一流程没有制造无意义的二进制漂移。

低位深度栅格:dtype 不是全部信息

发布说明还修复了 COG 转换对低位深度栅格的处理。LULC 与调色板栅格常把 1、2 或 4 bit 样本装在 rasterio 的 uint8 容器中,而真实位深记录在每个 band 的 GDAL IMAGE_STRUCTURE NBITS 标签里。仅凭 dtype 选择 PREDICTOR=2,可能让 gdal_translate 拒绝创建选项并导致整个导入任务失败。

新版逻辑先读取每个 band 的实际 bit width,再决定是否安全传入 predictor。这提醒团队:对 COG 做“能打开”的检查不足够,还应抽样验证 NBITS、overview、nodata、压缩选项和 range request。

业务场景:土地覆盖产品从上传到发布的可追溯链

假设团队接收一份 4 bit 的土地覆盖 GeoTIFF,转换成 COG 后再导出矢量统计 GeoPackage。上传未真正开始时,v1.15.1 将其归为 cancelled,而不是 failed;这样运维面板不会把“用户放弃上传”和“处理链故障”混为一谈。若输入文件损坏,面向用户的提示会包含原始文件名,而完整 GDAL stderr 留在结构化错误日志,既便于排障,也避免将临时路径暴露到界面。

在发布环节,应保存源文件哈希、NBITS、转换参数、COG 校验结果、GeoPackage 哈希和作业最终状态。由此能够回答:这份地图是由哪份数据、哪次处理、哪个版本生成的。

技术实施路径

  1. 对每种固定输入执行两次导出并比较 SHA-256,把不一致视为可复现性缺陷。
  2. 检查 GeoPackage 的要素、schema 与 SQLite 头字段,定位是业务变化还是文件级漂移。
  3. 对栅格按 band 读取 NBITS,不以容器 dtype 推断 predictor 是否可用。
  4. 转换后核对 COG overview、nodata、压缩、读取窗口与 range request。
  5. 将 pending、cancelled、failed 分开统计,并把原始 GDAL 详情放进受控日志。
  6. 对损坏输入保留可理解的文件名提示,同时避免向最终用户输出 staging 路径。

风险边界

该 release 解决的是 GeoLens 描述的导出、转换和导入场景,不保证其他 SQLite、GDAL 或托管平台采用相同实现。确定性导出也无法发现错误 CRS、错误分类编码或缺失要素;它必须与空间质量控制并行。

结论

GIS 交付的可复现性既包括“同一分析得到同一要素”,也包括“同一发布流程得到同一制品”。把 GeoPackage 哈希、SQLite 头部、NBITS、COG 创建选项和作业状态一并验收,才能让缓存、自动化发布和问题追溯真正可信。

关键词:GIS 是地理信息系统;GeoPackage 的可复现性依赖文件级校验;COG 转换需识别 NBITS;遥感栅格交付应记录 GDAL 参数。

来源:https://github.com/geolens-io/geolens/releases/tag/v1.15.1