主题:第 8 部分。数据源与 Schema Manifest
难度等级:中级
预计学习时间:2.5–3 小时
先决条件: 对 SQL 和 CSV 文件的基本理解
熟悉 ETL/ELT 概念和数据分层架构
理解原始层(raw)与数据集市层(mart)之间的区别
对 dbt 及其在数据转换中的作用的初步了解
对个人身份信息(PII)和数据治理的基本理解
学习目标: 解释在处理数据源时观察模式与设计模式的区别
按照给定的模板为至少两个数据源编写 Schema Manifest
在数据集中识别候选键、候选 PII 和空值,但不解读其业务含义
向数据源负责人提出至少五个开放性问题,以防止隐藏的臆测
论证为什么清单(manifest)和契约(contract)应作为单独的文件存在
概述:数据源剖析(profiling)是代理处理原始数据时首要且至关重要的一步。与设计阶段(代理在此创建模型和契约)不同,剖析阶段完全在观察模式下工作:代理记录实际进入原始层的状况,而不试图赋予其业务含义。此阶段的主要工具是 Schema Manifest。该文档描述可观察到的字段、其类型、空值、候选键、候选 PII 以及关于新鲜度的提示。清单的一个重要部分是开放性问题部分——它防止过早的解读。清单描述的是可观察到的内容,而契约描述的是承诺的内容。如果混合这两个层次,代理就会在人类批准策略之前开始「清理」数据源,从而导致重要数据质量信号的丢失以及报表错误。本节的目标是学会在处理原始数据时保持克制,并理解开放性问题不是弱点,而是对隐藏臆测的防御。
核心概念: 数据源剖析:一种对原始数据的观察模式,其中代理读取文件标题、前几行并计算简单统计。最重要的规则是不自行决定业务含义,也不在此阶段编写 dbt 模型。
Schema manifest:描述数据源中可观察内容的文档。由以下部分组成:可观察字段、候选键、候选 PII、质量说明和开放性问题。这是数据检查协议,而非数据转换设计。
观察模式 vs 设计模式:在观察模式下,代理仅描述所见。在设计模式下,代理创建模型、契约并做出架构决策。混合这两种模式会导致过早优化和上下文丢失。
清单 vs 契约:清单记录可观察到的内容(实际进入原始层的内容)。契约记录承诺的内容(数据源保证的内容以及在 mart 中允许使用的内容)。如果数据源中有 pii_email 字段,清单必须显示它,而契约可以禁止其进入 mart。
候选键:据代理观察看起来是稳定标识符的一个字段或字段组合。在得到人类批准之前,它只是候选键,而不是键。
候选 PII:根据其名称或内容看起来像个人数据的字段。在得到数据源负责人批准并制定正式处理策略之前,这只是怀疑,而不是事实。
数据新鲜度:关于数据时效性的提示:导出日期、是否存在时间戳、更新频率。这是一种可观察特征,而非契约保证。
开放性问题:清单的一个部分,记录所有无法在没有负责人的情况下解决的歧义和数据源的怪异之处。这是为了防止臆测成为事实。
代理的克制:一种原则上不在得到人类批准之前解读数据的立场。代理看到 risk_flag 不应立即赋予其业务含义——只需记录该字段的存在。
案发现场勘查协议:高质量清单的隐喻:就像犯罪现场的鉴证人员描述所发现的内容而不下关于犯罪嫌疑人的结论一样,代理描述数据而不下关于其含义的结论。
保护原始层:清单防止对原始数据进行过早的「清理」。如果存在异常,应先记录并提出问题,而不是修复,因为空白日期可能意味着三种不同的含义:错误、可接受的编码方式或数据丢失。
可观察类型:代理在数据源中看到的数据类型(例如,字符串、数字、字符串形式的日期)。不要与契约类型(数据源承诺或 mart 要求的类型)混淆。
数据源的粒度:数据的详细程度(一行 = 一笔交易、一个客户等)。即使答案看起来很明显,代理也不应在没有得到人类批准的情况下决定粒度。
重要日期: 课程背景:第 8 部分是在获取原始数据之后、在课程中设计模型之前的阶段,关于使用 dbt 和 LLM 代理的数据工程
工作顺序:先是 Schema Manifest(观察),然后是契约(设计),然后是模型(实现)
练习: 标题:为 card_transactions 编写清单
问题:打开 specs/source-manifests/card_transactions.md。研究可观察字段、候选键、候选 PII、质量说明和开放性问题。根据此模板,为虚构的原始数据源 raw/orders.csv 编写您自己的清单草稿,该文件包含以下列:order_id、customer_id、order_date、total_amount、status、risk_flag、promo_code。指出可观察的类型,标记空值,假设候选键和候选 PII,并提出至少四个开放性问题。
解决方案:步骤 1. 创建文件 specs/source-manifests/orders.md。步骤 2. 描述可观察字段及其类型,例如:order_id (int64)、customer_id (int64)、order_date (string 格式为 YYYY-MM-DD)、total_amount (float64)、status (string)、risk_flag (bool 或 string)、promo_code (string,有大量 null)。步骤 3. 候选键 — order_id(看起来是稳定标识符)。步骤 4. 候选 PII — customer_id(是合成的还是真实的?)。步骤 5. 质量说明 — promo_code 在大多数行中为空。步骤 6. 开放性问题:空的 promo_code 是什么意思?risk_flag 是数据源的标志还是反欺诈系统的结果?status 编码的是什么 — 最终状态还是当前状态?新鲜度 — 是否有 loaded_at 字段?
难度:中级
标题:分析关于 revoked_at 的开放性问题
问题:在数据源 open_api_consents.csv 中有一个 revoked_at 字段,经常为空。说明如果代理自行解决这个问题(不咨询数据源负责人)可能会出什么问题。描述空值的三种可能解释以及每种解释的后果。
解决方案:步骤 1. 阐述关于空 revoked_at 的三个假设:(a) 同意有效且从未被撤回,(b) 同意已被撤回,但由于数据源中的错误未记录日期,(c) 字段以特殊编码方式使用。步骤 2. 描述错误解释的后果:如果代理决定空的 revoked_at = 有效同意,而实际上这是一个错误,那么过时的同意将进入 mart,从而违反 GDPR/152-ФЗ 要求。步骤 3. 得出结论:清单中的开放性问题应明确指出这种歧义,并需要负责人的确认。
难度:中级
标题:清单与契约的分离
问题:给定一个数据源,其中包含字段:pii_email、pii_phone、customer_segment、lifetime_value、registration_date。编写两个单独的文件:Schema Manifest(可观察到的)和契约草稿(承诺的)。说明清单必须记录所有字段,包括 pii_email 和 pii_phone,而契约应明确指出其中哪些字段允许进入 mart。
解决方案:步骤 1. Schema Manifest 包括所有字段及其类型,将 pii_email 和 pii_phone 标记为候选 PII。步骤 2. 清单的开放性问题部分出现一个问题:「在进入 mart 之前是否有屏蔽 pii_email 和 pii_phone 的策略?」。步骤 3. 契约包含明确的允许和禁止:例如,pii_email — 在 mart 中禁止,仅在带屏蔽的受保护层中允许;customer_segment — 在 mart 中允许;lifetime_value — 在 mart 中允许。步骤 4. 得出结论:如果只有一个文件,代理可能会「忘记」pii_email,或者反过来,在策略批准之前开始激进地清理数据源。
难度:中级
标题:在自己的清单中寻找隐藏的臆测
问题:取练习 1 中您自己的清单草稿。仔细阅读它,找出至少三个您不知不觉中在人类批准之前就赋予字段业务含义的地方。以中性观察的形式重写这些地方。
解决方案:步骤 1. 典型的隐藏臆测 — 将 status 称为「订单状态」而不是「status 字段」。步骤 2. 第二个臆测 — 决定 risk_flag「意味着高风险」,尽管这只是字段名称。步骤 3. 第三个 — 写「customer_id 是客户」,尽管 customer_id 可能是会话、设备或账户的标识符。步骤 4. 以中性形式重写:「status 字段取自集合 {new, paid, cancelled, refunded} 中的值」,「risk_flag 字段具有 bool 类型,在 12% 的行中可观察到」,「customer_id 字段是数字标识符,含义未经确认」。步骤 5. 将这些歧义添加到开放性问题部分。
难度:中级
标题:为剖析编写 Qwen 提示
问题:为 Qwen(或其他 LLM 代理)编写一个正确设置剖析新数据源 raw/loan_applications.csv 任务的提示。提示必须明确禁止代理编写 dbt 模型并在没有批准的情况下决定粒度。
解决方案:步骤 1. 从明确的任务陈述开始:「读取 raw/loan_applications.csv 的标题和前 100 行」。步骤 2. 列出需要完成的内容:「编写 Schema Manifest:字段、可观察类型、候选键、候选 PII、新鲜度提示和开放性问题」。步骤 3. 明确禁止多余的操作:「不要编写 dbt 模型。不要在没有批准的情况下决定粒度。不要替换空值。不要解读字段的业务含义」。步骤 4. 指定输出格式:「结果 — 包含以下部分的 markdown 文档:可观察字段、候选键、候选 PII、质量说明、开放性问题」。步骤 5. 检查提示是否包含诱发解读的短语,例如「描述这些数据在业务中如何使用」。
难度:高级
案例研究: 标题:案例:GDPR 审计和同意字段的过早清理
情景:一家欧洲金融科技初创公司正在为营销分析准备 mart。代理收到一个包含字段 customer_id、consent_marketing、consent_at、revoked_at 的数据源。团队要求代理「清理数据并准备有效邮件订阅的橱窗」。
挑战:代理看到 revoked_at 经常为空,并决定这意味着「同意有效」。在不咨询数据负责人的情况下,他构建了一个将空 revoked_at 解释为有效同意的模型。六个月后,GDPR 审计到来,发现部分「有效」订阅实际上已被撤销,但由于上游系统的错误,revoked_at 未被记录。公司被处以罚款,并被迫通知所有受影响的客户。
解决方案:团队重做了该流程:引入了强制性的 Schema Manifest 步骤,其中开放性问题「空的 revoked_at 是什么意思?」被明确记录。在构建 mart 之前,代理必须获得数据源负责人的确认。在清单中明确指出 revoked_at 是有效同意编码的候选,但未经确认的事实。
结果:在流程更改后,此类错误在进入报告之前就被发现了。法务部门有机会在发布前批准解读。没有更多的罚款,新数据源的入职流程多花了 2–3 天,但事件数量减少了 80%。
经验教训: 代码中对数据的过早解读会导致开发和法律及声誉风险,这些风险在开发阶段是看不见的
Schema Manifest 不是一种形式,而是一种法律工件,可保护团队并表明解读已得到人类的批准
开放性问题是有据可查的谨慎,而不是代理工作的弱点
清单和契约的分离可以避免「清理过的」数据隐藏数据源的真实问题的情形
相关概念: 清单 vs 契约
开放性问题
代理的克制
候选 PII
保护原始层
标题:案例:反欺诈系统中可疑的 risk_flag 字段
情景:风险分析团队收到带有 risk_flag 字段的交易导出。两位初级分析人员对这一字段的解读不同:一个认为这是「反欺诈系统的最终决定」,另一个认为这是「规则的输入参数」。两人都在没有澄清的情况下开始构建报告。
挑战:三个月后发现,分析人员的报告相互矛盾。一个人的「有风险」交易比例为 4%,另一个为 11%。原因是同一字段的不同解读。没有 Schema Manifest,两位分析人员都没有记录其解读的依据,数据源负责人也无法快速解决争议。
解决方案:团队引入了针对每个新数据源强制使用 Schema Manifest 的做法。在交易的清单中,risk_flag 被记录为「具有 bool 类型的字段,出现在 100% 的行中,是风险标志业务含义的候选,但确切解读需要数据源负责人的确认」。向数据源负责人提出了开放性问题,一周后得到答复:「risk_flag 是应用 ML 模型之前规则引擎工作的结果,不能作为独立的风险特征使用」。
结果:在引入该做法后,对字段解读的争议减少了。团队新分析人员的入职时间从两周缩短到三天,因为 Schema Manifest 充当了数据源的「地图」。该团队还发现了另外两个具有歧义解读的字段,这些字段以前只是「照原样」使用。
经验教训: 字段名称不决定其含义 — 即使像 risk_flag 这样明显的名称也可能有不同的解读
Schema Manifest 记录歧义并使团队所有成员都能看到它们
没有答案的开放性问题比成为事实的臆测更好
记录原始数据是一项在任何解读争议中都能得到回报的投资
相关概念: 代理的克制
开放性问题
案发现场勘查协议
可观察类型
标题:案例:数据源迁移和清单中挽救的问题
情景:一家大型零售商将其忠诚度系统从一个 CRM 迁移到另一个 CRM。数据源 customer_profiles.csv 有 47 个字段,其中许多字段对新的团队来说是不理解的。前一个团队留下了一份包含 23 个开放性问题的 Schema Manifest。
挑战:新团队可能会忽略这些问题并开始「无论如何」构建 mart。但他们看到许多开放性问题涉及关键字段:is_vip、churn_score、lifetime_segment。没有答案,他们无法保证报告将与旧的匹配。
解决方案:新团队就 23 个开放性问题中的每一个联系了数据源负责人。14 个答案对报告至关重要。例如,发现 churn_score 是根据过时的公式计算的,如果不进行校正就在 mart 中使用,将导致与历史仪表板的差异达 18%。
结果:带有开放性问题的 Schema Manifest 为团队节省了至少 2 个月的故障排除时间,并防止了错误报告的发布。迁移后,团队将这一做法设为强制性的:每个数据源必须有一个最新的 Schema Manifest 和开放性问题部分,即使在创建清单时「一切都清楚」。
经验教训: 开放性问题具有长期价值 — 它们不仅有助于当前团队,也有助于将来加入的人员
Schema Manifest 是团队间知识传递的工件
即使看起来「一切都很明显」,记录歧义也可以在未来防止错误
迁移和数据源变化是 Schema Manifest 特别有价值的时刻
相关概念: 开放性问题
保护原始层
清单 vs 契约
数据源剖析
学习技巧: 练习克制:每次想写「这个字段意味着 X」时,请重新表述为「这个字段名为 X,其含义需要确认」。
维护您自己的「危险臆测」列表 — 您确信但未得到数据源负责人确认的字段。
将开放性问题表述为对负责人的问题,而不是修辞性或自明性的陈述。例如,不是「可能是有效同意」,而是「空的 revoked_at:它意味着什么 — 有效同意、数据源错误还是特殊编码?」。
不要在清单之后立即尝试编写 dbt 模型。首先向人类展示清单并获得对解读的确认。
过一天重新阅读您的清单 — 经常会发现一些起初看不到的隐藏解读。
对所有数据源使用统一的清单模板 — 这简化了审查和数据源之间的比较。
如果一个字段看起来「太明显」(例如 customer_id),这不是在清单中跳过它的理由。明显性是一个陷阱。
物理上分离可观察到的(manifest)和承诺的(contract) — 放在不同的文件中,由不同的负责人拥有,以不同的更新节奏。
在审查他人的清单时,请注意缺失的开放性问题。如果它们不存在,那就是您自己提出问题的理由。
请记住,清单的读者不仅是工程师,还有分析师、律师和经理。编写时使文档在没有深入技术背景的情况下也能被理解。
其他资源: Specs/source-manifests/card transactions.md:课程存储库中可用的交易数据源清单示例
Specs/source-manifests/open api consents.md:带有开放性问题示例的同意数据源清单示例
Dbt 文档:sources:https://docs.getdbt.com/docs/build/sources — 关于 dbt 中 sources 的官方文档,与清单的想法在逻辑上相关
Dbt-utils:source freshness checks:https://github.com/dbt-labs/dbt-utils — 用于检查数据源新鲜度的工具
Gdpr 官方文本:https://gdpr-info.eu — 解释为什么 PII 和同意需要在清单中特别关注的法规
Data quality fundamentals (o'reilly):一本揭示数据剖析原则和数据质量工作的书
Fundamentals of data engineering (joe reis, matt housley):一本详细描述分层架构和清单在其中位置的书
Data observability 课程 (monte carlo, bigeye):关于数据可观察性的一系列文章和视频,在概念上接近 Schema Manifest 的想法
总结:课程第 8 部分专门讨论 Schema Manifest — 记录原始数据可观察状态的关键文档。此阶段的主要原则是克制:代理描述所见,并在人类批准之前不决定业务含义。清单包括可观察字段、候选键、候选 PII、质量说明,以及特别重要的开放性问题。开放性问题不是弱点,而是对隐藏臆测的防御:空白字段可能意味着三种不同的含义,只有数据源负责人可以确认正确的解读。清单与契约在原则上是分开的:清单描述可观察到的,契约描述承诺的。混合这些层次会导致数据源的过早清理和数据质量信号的丢失。在学习了本部分之后,您将能够为真实的数据源编写 Schema Manifest、提出开放性问题、将观察与解读分开,并为清单和契约的架构分离提供理由。