你搬进了一个新小区,物业发你一本《用水公约》:自来水公司每天早上6点前供水,水质达到国家饮用水标准,水压不低于某个数值;而你作为住户,每月20号前交水费,不得私改管道。有了这本公约,双方都清楚“什么时候送、送来什么标准、不合规找谁”。数据世界里,数据生产方和数据消费方之间,也需要这样一本“公约”——它就是 Data Contract(数据契约)。没有它,上游数据说改就改,下游报表某天突然变红,两拨人互相甩锅;有了它,数据从“口头约定”变成“白纸黑字”,从“随缘”变成“可验证”。这篇文章用“小区供水公约”这个比喻贯穿始终,帮你把数据契约的定义、Schema约束、版本管理、生产者-消费者协议、质量保障一次讲透。

岗位关联

对数据工程师和治理团队而言,掌握 Data Contract 意味着能把“数据接口”从隐形的口头默契升级为可执行、可验证、可追溯的工程规范,大幅降低跨团队沟通成本,让数据管道在多人协作下依然稳定可靠。

目录
  1. 可视化演示
  2. 契约定义与作用
  3. Schema约束白纸黑字
  4. 版本管理机制
  5. 生产者消费者协议
  6. 数据质量保障
  7. 工程落地实践
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

三步交互演示数据契约核心机制:Schema字段级约束校验、语义化版本管理兼容性、生产者-消费者协议与质量门禁。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Schema字段级约束 字段类型与值域校验 不合规字段自动拦截 Schema = {field, type, constraint} 声明式数据接口规范

契约定义与作用

小区交付的那本《用水公约》,本质上是一份生产方(自来水公司)与消费方(住户)之间的服务承诺。它回答了三个问题:水从哪来?以什么标准来?不合规时谁负责?数据世界里,Data Contract 就是数据生产方(数仓团队、埋点团队、算法特征组)与数据消费方(BI 报表、推荐系统、数据科学团队)之间的同类承诺。它把“你应该给我一份好数据”这种模糊的期望,变成“字段有哪些、类型是什么、多久更新一次、质量指标达到多少”这种白纸黑字的条款。

从治理视角看,Data Contract 处在数据血缘与质量管理的交叉点上。血缘回答“数据从哪来、到哪去”,而契约回答“这条链路上每一跳的交接标准是什么”。它像一个接口规范层:血缘图描绘管道拓扑,契约则规定每个接口的语义。传统做法是建数据字典、开会对齐口径,但这些文档往往躺在 wiki 里没人看,而契约是“活”的——它被校验代码引用,被 CI 流程检查,被监控系统盯住。

回到小区比喻:没有公约时,住户嫌水压不稳,水厂嫌住户乱改管道,双方各执一词。有了 Data Contract,生产方知道“我要交付什么”,消费方知道“我能依赖什么”,出了质量问题也能快速定位是水厂没达标还是住户管道老化——沟通成本从“吵架”降到“查条款”。

Data Contract=(Schema 约束, 版本号, 交付协议, 质量指标)\text{Data Contract} = (\text{Schema 约束},\ \text{版本号},\ \text{交付协议},\ \text{质量指标})
一个完整的数据契约由四要素组成:结构、版本、交付方式与质量要求。公式说明契约不是单点文档,而是四类信息捆在一起的可执行产物。
  1. Schema 约束规定数据长什么样——字段名、类型、是否必填、取值范围,是契约的“水质标准”。
    Schema 约束={字段,类型,必填,取值范围}\text{Schema 约束} = \{字段, 类型, 必填, 取值范围\}
  2. 版本号契约本身也是会演变的代码,用语义化版本标识每次变更,是契约的“修订记录”。
    版本号:vmajor.vminor.vpatch\text{版本号} : v_{major}.v_{minor}.v_{patch}
  3. 交付协议约定生产方什么时候推、推多少、失败如何重试,是契约的“供水时间表”。
    交付协议=(频率, 时效, 重试策略)\text{交付协议} = (\text{频率},\ \text{时效},\ \text{重试策略})
  4. 质量指标用完整率、可用率等数值度量数据好坏,并设定阈值,是契约的“水质检测报告”。
    质量指标=(指标, 阈值, 统计口径)\text{质量指标} = (\text{指标},\ \text{阈值},\ \text{统计口径})

Schema约束白纸黑字

公约里写着“水质须达到国家饮用水标准”,但什么叫达标?必须细化成可检测的指标:浊度不超过1NTU,余氯不低于0.05mg/L。数据契约里的 Schema 就是这种“可检测的水质标准”。它把“给我一份干净的订单数据”翻译成机器可读的规则:order_id 是字符串且必填,amount 是浮点数且大于0,status 只能是 paid/pending/cancelled 三者之一。

Schema 约束通常分四类。字段级约束规定每个字段的存在性、类型和是否允许为空;取值约束规定范围或枚举;结构约束规定嵌套层级、数组长度;依赖约束规定字段间的逻辑关系(如 end_time >= start_time)。在实际落地时,最常用的是 JSON Schema 或 Protobuf 定义,它们既能描述规则,又能被校验库直接执行。

有了 Schema,数据接入时就像小区门口的水质检测仪——每一批数据流入前先自动“化验”,不合格的直接拦截并告警,而不是等消费方用到一半才发现数据是坏的。校验通过才放行,这是 Schema 约束最核心的价值。

Schema(f)={type(f)∈{string,int,float,bool,object}required(f)∈{true,false}value(f)∈[min,max] 或 ∈{e1,e2,…,ek}\text{Schema}(f) = \left\{\begin{array}{ll}\text{type}(f) \in \{\text{string}, \text{int}, \text{float}, \text{bool}, \text{object}\} \\\text{required}(f) \in \{\text{true}, \text{false}\} \\\text{value}(f) \in [\text{min}, \text{max}]\ \text{或}\ \in \{e_1, e_2, \dots, e_k\}\end{array}\right.
每个字段 f 都要回答三个问题:它的类型是什么?是否必须出现?允许的取值范围或枚举是什么?这三个条件同时满足,字段才算“合规”。
  1. 类型规定字段的数据类型限定在若干种基础类型中,防止“日期传成字符串”这类低级错误。
    type(f)∈{string,int,float,bool,object}\text{type}(f) \in \{\text{string}, \text{int}, \text{float}, \text{bool}, \text{object}\}
  2. 必填性规定标记字段是否必须出现,required=false 的字段缺失时校验通过,为 true 时缺失即报错。
    required(f)∈{true,false}\text{required}(f) \in \{\text{true}, \text{false}\}
  3. 取值范围规定数值型字段设定上下界,枚举型字段列出合法取值集合,越界即违规。
    value(f)∈[min,max] 或 ∈{e1,e2,…,ek}\text{value}(f) \in [\text{min}, \text{max}]\ \text{或}\ \in \{e_1, e_2, \dots, e_k\}

版本管理机制

公约不是一成不变的:小区扩建了,水压标准要调整;水质检测标准升级了,检测频率要提高。但公约不能今天改完明天又改,每次修订都要有版本号、有生效日期、有变更说明。数据契约同理:数据 schema 会随业务演进不断变化,如果没有版本管理,消费方凌晨醒来发现字段没了,只能对着断裂的管道欲哭无泪。

语义化版本号 major.minor.patch 是业界公认的约定。大版本号(major) 代表不兼容变更,比如删除字段、修改字段类型,消费方必须配合改造;小版本号(minor) 代表向后兼容的新增,比如新增一个可选字段,旧消费方不受影响;补丁号(patch) 代表修复和微调,如修正枚举拼写错误。版本管理的关键不只是“记个版本号”,而是把兼容性语义写进契约,让消费方能判断“我能不能直接升级”。

回到供水公约:水厂发布“修订版2.0”时,会提前 30 天通知住户,列明变更条款;住户据此决定要不要改造自家管道。契约版本管理做的正是这件事——把“哪天半夜偷偷改了数据”变成“发布新版本、评估兼容性、协商升级窗口”的规范流程。消费方可以按自己的节奏升级,不必再被上游的突发变更打得措手不及。

兼容性(va→vb)={兼容 ,va.major=vb.major破坏 ,va.major≠vb.major\text{兼容性}(v_a \rightarrow v_b) = \left\{\begin{array}{ll}\text{兼容}\ , & v_a.\text{major} = v_b.\text{major} \\\text{破坏}\ , & v_a.\text{major} \neq v_b.\text{major}\end{array}\right.
两个契约版本之间的兼容性由大版本号决定:大版本相同则向后兼容,消费方可以无损升级;大版本变化则视为破坏性变更,消费方必须评估改造。
  1. 比较大版本号先看两个版本的大版本数字是否相同,这是兼容性的总开关。
    va.major=vb.majorv_a.\text{major} = v_b.\text{major}
  2. 判定结果若大版本相同,升级是安全的;不同则必须走变更评审流程,通知所有消费方。
    兼容 或 破坏\text{兼容}\ \text{或}\ \text{破坏}

生产者消费者协议

公约的本质是双向承诺:水厂承诺按时按质供水,住户承诺合规用水、及时缴费。数据契约也必须是双向协议,而不是单方面的“数据说明书”。生产方(Producer)承诺交付物:数据以什么格式、什么频率、什么时效送达,失败重试几次,质量指标达到多少。消费方(Consumer)承诺使用方式:只读取自己订阅的版本、不绕过契约直接访问底层表、发现异常时按约定通道反馈。

协议中最容易忽略的是异常责任归属。数据延迟了,是生产方管道故障,还是消费方查询压垮了接口?数据内容错了,是生产方逻辑 bug,还是消费方理解错了字段语义?契约里写清楚“谁负责什么、出问题找谁”,相当于给双方上了保险。常见的责任划分方式是:生产方对“交付的数据是否符合契约定义”负责,消费方对“是否按契约使用数据”负责,中间的传输延迟和可用性由平台方或双方共担。

小区里,水厂不能因为“我水是干净的”就对管道漏水撒手不管;住户也不能因为“我家水龙头坏了”就怪水厂水质差。双向协议的意义,就是让每一条数据从生产到消费的路径上,每个环节都有明确的责任人。出了问题,先查契约,再定责任,最后谈赔偿——治理从此有了依据。

责任矩阵=[生成正确性传输可用性生产方✓△消费方−△平台方−✓]\text{责任矩阵} = \left[\begin{array}{ccc}& \text{生成正确性} & \text{传输可用性} \\\text{生产方} & \checkmark & \triangle \\\text{消费方} & - & \triangle \\\text{平台方} & - & \checkmark\end{array}\right]
责任矩阵说明:数据生成是否正确由生产方负责;传输链路是否可用由平台方负责;消费方不参与生成,但在传输可用性上承担协同责任(如重试、降级)。
  1. 生成正确性数据的字段值是否符合 Schema 和质量阈值,由生产方全权负责,消费方默认信任。
    生成正确性←负责生产方\text{生成正确性} \xleftarrow{\text{负责}} \text{生产方}
  2. 传输可用性管道是否稳定、是否在 SLA 内送达,由平台方负责,双方配合监控。
    传输可用性←负责平台方\text{传输可用性} \xleftarrow{\text{负责}} \text{平台方}
  3. 协同责任消费方需实现重试、降级等容错措施,不能把平台故障完全甩给生产方。
    协同责任←配合消费方\text{协同责任} \xleftarrow{\text{配合}} \text{消费方}

数据质量保障

公约里“水质达标”不能是一句空话,必须配套检测指标和检测频率。数据契约对质量的保障同样要落地为可量化的指标 + 阈值。最常用的两个指标是完整性(completeness)和可用率(availability)。完整性衡量“该有的数据有没有”,比如一天应有 1000 万条订单明细,实际只有 950 万条,完整率就是 95%;可用率衡量“数据在需要时是否可读可用”,比如每天 24 小时中接口可正常响应 23 小时,可用率就是 95.8%。

契约不只定义指标,还定义统计口径和阈值。口径必须精确到“按事件时间还是按到达时间统计”“重复数据是否去重”,否则双方会对数字各执一词。阈值则要分等级:软阈值触发告警(如完整率低于 99% 发 warning),硬阈值触发阻断(如低于 95% 暂停消费方拉取)。质量监控系统持续计算这些指标,一旦跌破阈值,自动通知生产方并记录问题工单。

供水公约的执行逻辑是:水厂自检 + 第三方抽检 + 住户投诉反馈。数据契约的质量保障同样需要三方联动——生产方在发布前自检、平台在消费入口统一校验、消费方在使用中反馈异常。质量指标让“数据好不好”从主观感受变成客观数字,也让质量问题的追溯有了数据支撑:是哪个批次没达标、哪个环节丢数据,一查便知。

Q完整率=N实际到达N契约承诺×100%,Q达标=Q完整率≥99.5%Q_{\text{完整率}} = \frac{N_{\text{实际到达}}}{N_{\text{契约承诺}}} \times 100\%,\qquad Q_{\text{达标}} = Q_{\text{完整率}} \geq 99.5\%
完整率=实际到达记录数 ÷ 契约承诺记录数 × 100%。数据契约通常约定一个基线阈值(如99.5%),低于该值即触发质量告警。
  1. 分子分母定义实际到达记录数由消费侧统计,契约承诺记录数由生产侧在契约中声明,双方对同一数字负责。
    N实际到达N契约承诺\frac{N_{\text{实际到达}}}{N_{\text{契约承诺}}}
  2. 百分比转换乘以 100% 得到可读的百分比,便于对比和设定阈值。
    ×100%\times 100\%
  3. 阈值比较将算出的完整率与契约约定的阈值比较,决定质量是否达标。
    ≥99.5%\geq 99.5\%

工程落地实践

公约写得再完备,锁在抽屉里也没用;数据契约同样要嵌入工程体系才能发挥价值。落地的第一步是把契约当成唯一事实源(Single Source of Truth):所有关于数据格式、版本、质量的口径都以契约为准,数据字典、wiki、邮件通知都是它的投影,而不是另起炉灶。契约文件存放在独立仓库里,每次修改走代码评审流程,像管理 API 一样管理它。

第二步是流水线自动化校验。在数据接入的入口部署校验服务,每批数据先过 Schema 校验再入库;在 CI/CD 中加入契约兼容性检查,防止生产方提交破坏性变更而不自知;在监控系统中注册契约指标,质量跌破阈值自动告警。自动化让契约从“文档”变成“代码”——它是可执行的,不是可翻阅的。

最后一步是治理透明、责任到人。每个契约都要有 owner(通常是对应数据表的生产方负责人),质量告警自动抄送 owner;契约的每一版变更都留下审计记录,谁改的、为什么改、影响了谁,全程可追溯。像小区公约的修订要公示一样,数据契约的变更要透明——透明带来信任,信任让协作变快。

执行链路:契约仓库→CI 检查校验服务→质量指标监控告警\text{执行链路}:\quad \text{契约仓库} \xrightarrow{\text{CI 检查}} \text{校验服务} \xrightarrow{\text{质量指标}} \text{监控告警}
契约的执行链路是:契约变更先过 CI 兼容性检查,校验服务在数据入口执行 Schema 校验,监控系统持续上报质量指标并触发告警。
  1. CI 检查每次契约变更提交时,自动运行兼容性检查,防止大版本变更被悄悄合入。
    契约仓库→CI 检查\text{契约仓库} \xrightarrow{\text{CI 检查}}
  2. 校验服务数据到达时,校验服务读取当前生效的契约版本并逐条验证。
    →校验服务\xrightarrow{\text{校验服务}}
  3. 监控告警质量指标持续上报,跌破阈值时通知相关责任人。
    →质量指标监控告警\xrightarrow{\text{质量指标}} \text{监控告警}

AI 应用场景

场景一:跨团队数据交接的“免责声明”

阶段:数据集成与质量管理

解决的问题:业务方自建的数据表交给算法团队做特征工程时,字段定义全靠群聊确认,上游改字段类型后模型训练直接报错。通过 Data Contract 定义 schema、版本、完整率承诺,交接时自动校验,不达标的数据根本进不了特征库。

具体案例:某电商公司的埋点团队与推荐算法团队对峙数月。引入契约后,埋点团队发布 click_log.v2,算法团队升级到新版本,CI 自动检查字段兼容性,上线后数据质量监控显示完整率从92%升到99.6%,“数据又坏了”的群消息减少了八成。

场景二:RAG 知识库的“保鲜协议”

阶段:数据准备与检索增强生成

解决的问题:RAG 系统依赖文档分块后的结构化数据,但上游文档库频繁增删字段,导致向量化任务产出过期片段。用 Data Contract 约束“文档必须包含 content/author/update_time 三个字段,更新频率为每日”,过期数据在入口被拦截。

具体案例:某智能客服团队维护 10 万篇业务文档,新版本文档改用了新模板但旧字段未删。契约校验发现 summary 字段填充率跌破 80%,自动回滚到上一版文档集,同时向生产方发出告警,避免了线上机器人引用残缺摘要的尴尬。

场景三:特征平台与模型训练的版本对齐

阶段:MLOps 特征工程

解决的问题:特征存储中特征定义与训练代码各说各话,模型上线后离线在线不一致。将特征列表声明为数据契约,每个特征绑定 schema 和版本,模型训练和在线推理读取同一份契约文件,保证“训练什么特征,上线就吃什么特征”。

具体案例:某金融风控团队特征从 300 个增加到 450 个,引入契约后,每次特征变更自动生成新的契约版本,训练代码锁定 features.v5,线上服务同步升级,离线在线 AUC 差异从 0.08 降到 0.02。

Python 演示

python74 行
"""A minimal Data Contract validator: schema + semantic versioning."""import refrom datetime import datetime  def validate_contract(rule, payload):    errors = []    for f, spec in rule.get("fields", {}).items():        if spec.get("required") and f not in payload:            errors.append("missing field: {}".format(f))            continue        if f not in payload:            continue        val = payload[f]        expected = spec["type"]        type_ok = isinstance(val, expected)        if expected is int and isinstance(val, bool):            type_ok = False        if not type_ok:            errors.append("field {} type error".format(f))            continue        if "enum" in spec and val not in spec["enum"]:            errors.append("field {} not in enum".format(f))        if "min" in spec and isinstance(val, (int, float)) and val < spec["min"]:            errors.append("field {} below min".format(f))        if "max" in spec and isinstance(val, (int, float)) and val > spec["max"]:            errors.append("field {} above max".format(f))        if "pattern" in spec and isinstance(val, str) and not re.search(spec["pattern"], val):            errors.append("field {} pattern mismatch".format(f))    return errors  def bump_major(version):    mj, mn, pt = parse_version(version)    return "{}.{}.{}".format(mj + 1, 0, 0)  def bump_minor(version):    mj, mn, pt = parse_version(version)    return "{}.{}.{}".format(mj, mn + 1, 0)  def compat_check(consumer, published):    cmj, _, _ = parse_version(consumer)    pmj, _, _ = parse_version(published)    return cmj == pmj  def parse_version(text):    m = re.match(r"^(\d+)\.(\d+)\.(\d+)$", text.strip())    if not m:        raise ValueError("bad semantic version: {}".format(text))    return int(m.group(1)), int(m.group(2)), int(m.group(3))  CONTRACT = {    "version": "1.0.0",    "fields": {        "user_id": {"type": str, "required": True, "pattern": r"^u_\d{4,}$"},        "age": {"type": int, "required": True, "min": 0, "max": 120},        "plan": {"type": str, "required": False, "enum": ["free", "pro", "enterprise"]},        "pay_amount": {"type": float, "required": True, "min": 0.0},    },} if __name__ == "__main__":    good = {"user_id": "u_1001", "age": 28, "plan": "pro", "pay_amount": 19.9}    bad = {"user_id": "abc", "age": 200, "plan": "vip", "pay_amount": "xx"}    print("good errors:", validate_contract(CONTRACT, good))    print("bad errors:", validate_contract(CONTRACT, bad))    print("bump_minor:", bump_minor(CONTRACT["version"]))    print("compat v1.2 vs v1.0:", compat_check("1.2.0", CONTRACT["version"]))    print("compat v2.0 vs v1.0:", compat_check("2.0.0", CONTRACT["version"]))    print("checked at:", datetime.now().strftime("%Y-%m-%d %H:%M"))
目的:实现一个最小可用的数据契约校验器,演示 Schema 约束(必填、类型、枚举、范围、正则)与语义化版本管理(大版本兼容性判断)。
  1. validate_contract(rule, payload)核心校验函数:把契约规则和待检数据都传进来,逐字段检查,返回违规列表。像小区门口的水质检测仪。
  2. spec.get("required") and f not in payload必填字段缺失直接记为错误,这是 Schema 约束中最先执行的检查。
  3. isinstance(val, expected)检查字段类型,注意用 expected is int and isinstance(val, bool) 排除“布尔值被当作整数”这个 Python 经典坑。
  4. "enum" in spec and val not in spec["enum"]枚举约束:字段值必须在约定集合内,对应契约中 status 只能是固定几个值。
  5. "pattern" in spec and re.search(...)正则约束:用模式串检查字符串格式,如 user_id 必须以 u_ 开头。
  6. parse_version解析语义化版本号,返回主次补丁三元组,版本号不合法直接抛错,防止乱写版本。
  7. compat_check(consumer, published)兼容性判断:只看大版本号是否相同,这就是公式 major 相等的代码实现。
  8. bump_minor小版本号递增并清零补丁位,模拟“新增可选字段”这种向后兼容的变更。

常见误区

误区“数据契约不就是把字段名、字段类型整理成一张表吗?我们已经有数据字典了,不用搞什么契约。”

正解数据字典是“名词解释”,它告诉你 user_id 是什么意思;数据契约是“法律条款”,它规定 user_id 必须是什么类型、必须出现、取值格式如何,并且这些规则要被校验代码强制执行。字典描述世界,契约约束行为。如果只做字典不做契约,就像小区只在墙上贴了水质标准却从不检测——标准是有了,执行为零。

为何常见:两者长得像(都是字段清单),且数据字典的产出成本低、可视化好看,容易让人误以为“已经做了治理”。

误区“我们给契约标了 v1.0、v2.0,版本管理做得很好,消费方应该不会出问题了吧?”

正解版本号只是“通知”,兼容性检查才是“保护”。如果生产方发 v2.0 时没有跑兼容性校验,消费方也没做升级检查,那版本号只是一串标记,等于公约改了版却没通知住户。必须把版本兼容性检查写进 CI,发布时自动比对新旧契约,发现破坏性变更直接拦截并通知所有订阅方,版本管理才算真正生效。

为何常见:人容易把“标记了变更”等同于“管理了变更”,忽略了版本机制背后需要校验和通知这两个执行动作。

误区“我们上线了 schema 校验,坏数据进不来了,数据质量问题应该解决了吧?”

正解Schema 校验只管“结构对不对”,管不了“内容好不好”。一条 user_id 格式正确但其实是重复数据、一条 age 类型正确但来源小区已经搬迁,Schema 都拦不住。数据的完整性、时效性、业务正确性要靠质量指标监控来兜底。水质检测仪只测浊度和余氯,测不了水里的重金属——那需要另一套检测体系。

为何常见:Schema 校验是最容易自动化的环节,上线后立刻见效,容易让人误以为它是质量保障的全部。

误区“数据契约就是上游用来约束下游的,要求我们按他们的版本升级、按他们的格式使用,太麻烦了。”

正解契约是双向协议,保护双方。它约束下游“不要绕过契约乱用数据”,也约束上游“不能悄无声息地破坏兼容性”。更重要的是,契约界定了责任边界:下游按契约使用,出了问题可以理直气壮找上游;上游按契约交付,也可以拒绝下游的“加字段”随口需求。公约约束住户,同样约束水厂。

为何常见:人天然反感被约束,且容易只看到契约限制自己的一侧,忽略它同时给了自己追责的权利。

面试题

Q1. 数据契约与数据字典最本质的区别是什么?

单选题 · easy

  • A.数据契约更详细,数据字典比较简略
  • B.数据契约是可执行可校验的接口规范,数据字典只是描述性文档← 正确答案
  • C.数据契约只给程序员看,数据字典给业务人员看
  • D.数据字典有版本号,数据契约没有版本号

答案:B。数据字典回答“这个字段是什么”,数据契约回答“这个字段必须满足什么规则并被自动验证”——前者是描述,后者是可执行的约束。类比供水公约:描述“水是透明液体”是字典,规定“浊度不超过1NTU并检测”才是契约。

Q2. 语义化版本 2.1.0 中,哪一位变化表示不兼容变更?

单选题 · easy

  • A.第一位,从 2 变到 3← 正确答案
  • B.第二位,从 1 变到 2
  • C.第三位,从 0 变到 1
  • D.任意一位变化都不兼容

答案:A。语义化版本中 major(第一位)变化代表破坏性变更,消费方必须评估改造;minor(第二位)是向后兼容的新增;patch(第三位)是修复。像公约修订:改动一页说明是 minor,改动供水时间表就是 major,必须提前通知住户。

Q3. 以下哪些变更应当触发数据契约的大版本号升级?

多选题 · mid

  • A.删除一个已有字段← 正确答案
  • B.把日期字段从字符串改为时间戳← 正确答案
  • C.新增一个可选字段
  • D.调整字段在 JSON 中的排列顺序

答案:AB。删除字段会破坏消费方的读取逻辑,修改字段类型会导致解析失败,两者都是破坏性变更,必须升大版本。新增可选字段是向后兼容的,升小版本即可;JSON 对象的字段顺序与解析无关,属于补丁级甚至无需发版。

Q4. 数据契约中 Schema 约束一般不包含以下哪一项?

单选题 · mid

  • A.字段是否必填
  • B.字段的取值范围
  • C.字段的业务含义描述← 正确答案
  • D.字段的数据类型

答案:C。Schema 约束是机器可执行的规则:必填性、类型、取值范围、枚举都是校验逻辑能判断的。字段的业务含义描述属于数据字典的职责,校验器无法自动判断“这段描述是否正确”。契约负责“可验证”,释义负责“可理解”。

Q5. 消费方订阅了数据契约 v1.2,生产方发布了 v2.0 并已上线。下列说法正确的是?

单选题 · mid

  • A.消费方的数据流会立即断裂,必须马上升级
  • B.生产方应同时维护 v1 与 v2 两套兼容输出,消费方按节奏升级← 正确答案
  • C.消费方无需任何操作,v2.0 会自动兼容 v1.2
  • D.生产方无需通知消费方,发现问题再说

答案:B。破坏性版本发布后,老消费方不能自动适配新版,生产方需要在一段时间内同时发布新旧两个版本的数据,给消费方升级窗口。这就像水厂改造管道:不能先挖路再通知住户,得给住户一段备水时间。否则消费方数据流断裂就是事故。

Q6. 完整率指标计算中,分母“N契约承诺”通常由谁定义、在哪里声明?

单选题 · hard

  • A.消费方在代码里硬编码
  • B.生产方在数据契约的交付协议中声明← 正确答案
  • C.监控系统根据历史数据推算
  • D.数据平台自动采集得出

答案:B。契约承诺的记录数是生产方对“我应当交付多少数据”的承诺,写在契约的交付协议部分,是后续质量考核的基准。消费方硬编码缺乏权威性,推算和自动采集都缺少“契约”属性。好比水厂承诺日供水量,住户才能据此判断今天是不是缺水了。

Q7. 关于生产方与消费方在数据契约中的责任,下列说法正确的是?

单选题 · mid

  • A.生产方只对数据生成正确性负责,不管传输
  • B.消费方只负责使用数据,不承担任何异常责任
  • C.生产方对交付数据的契约符合性负责,消费方对按契约使用负责← 正确答案
  • D.所有责任都由平台方承担

答案:C。契约是双向协议:生产方保证交付的数据符合 schema 和质量承诺,消费方保证按约定版本、约定方式使用,并实现必要的容错。传输链路通常由平台方兜底,但消费方的重试和降级是协同责任。三方各司其职,才能定位问题不扯皮。

Q8. 以下哪些举措属于数据契约工程落地的正确做法?

多选题 · mid

  • A.把契约文件放入独立仓库并走代码评审← 正确答案
  • B.在 CI 中加入契约兼容性检查← 正确答案
  • C.在数据入口部署 schema 校验服务← 正确答案
  • D.把契约打印出来贴在会议室墙上

答案:ABC。契约落地的关键是“可执行”:仓库管理保证变更可追溯,CI 检查防止破坏性变更悄悄合入,入口校验让坏数据进不来。贴在墙上只是仪式感,没有任何校验能力。公约要生效靠的是严格执行,不是公示本身。

Q9. 一个字段在 v1.0 中是必填的,在 v2.0 中改为可选。从兼容性角度看,这个变更属于?

单选题 · hard

  • A.破坏性变更,必须升大版本← 正确答案
  • B.向后兼容,升小版本即可
  • C.无法判定,需要看数据类型
  • D.补丁级变更,升补丁号即可

答案:A。必填改成可选会破坏旧消费方的假设——它们可能写死了“该字段一定存在”的逻辑,收到缺字段的数据会报错。契约兼容性判断的标准是“老消费方能否无感运行”,违反此标准即为破坏性变更,必须升大版本并走变更通知流程。

Q10. 数据契约中质量指标(如完整率 99.5%)的主要作用是什么?

单选题 · easy

  • A.给生产方设定考核目标,与责任追溯无关
  • B.让数据质量从主观感受变成可度量、可告警、可追溯的数字← 正确答案
  • C.代替 schema 校验去拦截字段类型错误
  • D.仅供消费方参考,没有执行机制

答案:B。质量指标把“数据好不好”量化成完整率、可用率等可监控的数字,跌破阈值即告警,质量责任可追溯到具体批次和负责人。但它管的是“整体质量水位”,管不了单个字段的类型错误——那是 schema 校验的职责。指标让治理有据可依。