供应商改了返回结构怎么办?数据结构迁移的工程实践
采集系统的噩梦之一:依赖的第三方接口改了返回结构。要么字段改名,要么模块消失,要么必选变可选。慌不慌?如果提前做了迁移准备,这只是个「走流程」的活。这篇记录我怎么把「供应商结构变更」从事故变成常规工程:迁移策略、兼容期、双写验证、回滚。
先认清:结构变更挡不住
搜索数据接口的返回结构是「活文档」——谷歌展示什么,接口就返回什么(以我用 SerpBase(serpbase.dev)为例,很多字段标注 optional、随 SERP 变化)。你无法阻止供应商改结构,只能让「变更发生时自己不痛」。
关键认知:迁移的目标不是「不变」,而是「变的时候可控制、可回滚、可验证」。
一、日常就要做的:版本化隔离
把「供应商结构」和「内部使用」隔离,是迁移的前提。清洗层(之前写过的清洗思路)就是这道墙:
- 供应商字段 → 清洗层 → 内部标准 schema
- 供应商改结构,只改清洗层,内部 schema 不动
# 伪代码:供应商结构映射集中在清洗层
MAPPING_V2 = {
"url": lambda item: item.get("url") or item.get("link") or "",
"rank": lambda item: item.get("rank") or item.get("position"),
"snippet": lambda item: item.get("snippet") or "",
}
供应商改结构,就是改 MAPPING_V2 这张表,其他代码不碰。
二、结构变更时的迁移流程
当供应商真的改了(或你要换 schema),按下面流程走:
第 1 步:评估影响。 先搞清楚改动范围:
- 字段改名?模块消失?可选变必选?
- 用真实响应样本对比新旧结构,列出差异清单
第 2 步:双写(新旧并行)。 在过渡期,新结构写入新字段,旧结构继续兼容写入:
# 伪代码:双写期
def write_rec(rec_new, rec_old):
insert("records_new", rec_new) # 新结构
insert("records_legacy", rec_old) # 旧结构(兼容期保留)
第 3 步:影子比对。 双写的同时,对比新旧解析结果是否一致,不一致的地方就是迁移要修的:
# 伪代码:影子比对
diffs = compare(parse_new(raw), parse_old(raw))
for d in diffs:
print(f"差异: {d}") # 确认是「预期差异」还是「解析 bug」
第 4 步:切换 + 观察。 比对通过后,读路径切到新结构,保留旧结构读「只读影子」观察一段时间。
第 5 步:清理。 稳定后删旧代码、旧字段,迁移完成。
三、回滚方案:迁移的保险
迁移不能没有回滚。我的设计:切换是「配置开关」而不是「代码重写」:
# 伪代码:解析版本开关
PARSE_VERSION = "v2" # 配置项,回滚时改回 "v1"
def parse(raw):
if PARSE_VERSION == "v2":
return parse_v2(raw)
return parse_v1(raw) # 旧解析器保留,回滚即切回
好处:出问题改一行配置就能回滚,不用改代码重新部署。旧解析器保留一段时间再删,别追求「删得干净」。
四、验证:迁移没把数据搞坏
迁移的验证要量化,不能「感觉没问题」:
- 样本对比:用同一批真实响应,新旧解析结果字段级对比,差异率 < 0.1%
- 数量核对:迁移前后每天的记录数、字段完整度基本一致
- 质量指标:复用之前的质量监控(成功率、完整度),迁移期重点盯
- 历史回测:用旧历史数据跑新解析器,确认不崩
五、和测试的关系
迁移期最容易漏的是「历史数据」。新解析器要能解析旧格式的历史数据(或明确标记「不兼容历史」)。测试里加一组「旧格式 fixture」,确保回滚和迁移都有的测:
# tests/fixtures/legacy_format.json —— 旧格式样本
def test_parse_legacy():
data = load_fixture("legacy_format.json")
assert parse(data)["url"] # 旧格式也能解析
六、迁移清单沉淀
- 平时:清洗层隔离,供应商结构只在一处映射
- 变更时:评估 → 双写 → 影子比对 → 切换 → 清理
- 回滚:解析版本做成配置开关,旧解析器保留
- 验证:样本对比 + 数量核对 + 质量指标 + 历史回测
- 测试:旧格式 fixture 常备,迁移和回滚都有依据
供应商结构变更不可怕,可怕的是「没有准备的变更」。把清洗隔离、版本开关、影子比对三件事做好,迁移就是一次常规发布。
接口字段的完整定义(哪些可选、哪些别名)在 SerpBase 官方文档,做迁移对照时先看它。你们供应商改结构时都是怎么处理的?评论区聊聊各自的迁移流程。

浙公网安备 33010602011771号