# 埋点之前先定义数据的用途与边界

原文: https://yishto.com/learn/data-practice/data-events-and-governance/

作者: [Yishto](https://yishto.com/about/)

围绕课程完成事件定义用途、最小字段、版本与迟到规则，追踪重复、缺失和删除对指标的影响。

首次发布: 2026-11-10
内容更新: 2026-11-10

学习页面准备记录“完成练习”事件，用来发现哪些步骤容易中断。收集之前要确定数据服务于什么决策：检查某一步的完成比例，通常不需要上传用户写下的整段答案，更不需要保存所有输入与设备信息。

案例把 E-1 等事件 ID 作为虚构数据，事件 completed 只表示程序观察到既定完成条件。它不证明读者掌握了知识。本文设计一份最小事件契约，再说明版本、重复、时间与删除责任怎样影响后续分析。

## 先定义事件发生的条件

点击提交按钮、答案通过检查、结果成功保存是不同时间点。若指标研究练习完成，应选择明确的业务条件，并在权威位置产生事件。前端点击可以用于研究交互，但不能替代后端确认的保存结果。

事件字典应给出名称、触发条件、生产组件、字段、单位和用途。例如 completed 在结果保存后产生，lesson_id 指向公开课程，schema_version 描述字段契约，event_id 标识一次事件。需要观察用户级转化时，应再评估标识的必要性与使用范围。

给每个字段写出实际用途。无法说明用途的字段先不收集。自由文本、模型 prompt、上传内容和真实账号信息不应成为默认埋点。即便用于排错，也需要更窄的权限、保留期与明确处理条件，避免分析系统变成业务资料的另一份副本。

## 时间与到达顺序要分开

事件时间描述动作何时发生，摄入时间描述服务何时收到记录。断网重试可能让昨天的事件今天到达，客户端时钟也可能不准确。按摄入时间统计与按事件时间统计回答不同问题，应在指标定义中标注使用哪个时间。

至少一次传输可能产生重复记录。稳定的 event_id 让接收端识别重试，去重窗口与存储期限也要设计。若同一 ID 带着不同内容再次出现，应记为冲突或进入调查，不能随机覆盖后让数据含义变化。

乱序到达会影响按窗口聚合。可以允许有限迟到并更新窗口结果，或者把迟到数据放入单独统计。选择取决于业务是否要求实时显示、是否允许修正与资源成本。统计报告应注明何时达到完整度要求，避免把尚未收齐的最近窗口与完整历史直接比较。

## 版本和形状检查只是第一道门

新增或重命名字段应升级契约并安排兼容，消费者不能假定所有生产者一起更新。JSON Schema 可以验证类型、必需字段与允许值，但无法证明事件真实发生，也无法证明采集拥有适当依据。

下面的离线模型只接受版本 1、名称 completed 和三个固定字段。它去掉 E-1 的重复记录，拒绝未知版本与缺少 kind 的记录，并拒绝把布尔值当作版本整数。

```python
events = [
    {"id": "E-1", "version": 1, "kind": "completed"},
    {"id": "E-1", "version": 1, "kind": "completed"},
    {"id": "E-2", "version": 2, "kind": "clicked"},
    {"id": "E-3", "version": 1},
]
def valid(event):
    return (isinstance(event, dict) and set(event) == {"id", "version", "kind"}
            and isinstance(event["id"], str) and bool(event["id"])
            and type(event["version"]) is int and event["version"] == 1
            and event["kind"] == "completed")
seen = set()
accepted = []
for event in events:
    if valid(event) and event["id"] not in seen:
        seen.add(event["id"])
        accepted.append(event)
assert len(accepted) == 1
assert not valid({"id": "E-4", "version": True, "kind": "completed"})
print(len(accepted))
```

实际输出是 `1`。只有第一份 E-1 被接纳；第二份是重复；E-2 版本不受支持；E-3 字段不完整。代码没有使用 JSON Schema 库，没有验证时间、保存数据或处理内容冲突，是最小契约模型。

真实采集可以将不合法数据隔离到受控错误队列，并记录错误分类与生产版本。不要因为解析失败就在普通日志里打印整份事件。兼容失败需要能追溯到哪个发布引入了字段变化，才能恢复或修复生产端。

## 最小化不等于只给标识做哈希

W3C 隐私原则强调限制数据传输到实现用户目标所需范围，并提供适当控制。哈希一个用户标识仍可能允许跨记录关联；如果原值容易猜测，还可能被枚举还原。去掉姓名也不能自动让一组行为轨迹成为匿名数据。

设计中应区分真正不需要身份的聚合分析、需要关联的业务运营和敏感排错。各用途不一定能共用同一套标识或保留期。不要把“以后可能有用”作为无限采集的理由，也不要通过同意界面替代对必要性的判断。

具体的数据处理依据、同意要求与用户权利要根据适用规则和场景确认，本文不提供法律充分性结论。技术实现能帮助限制字段、访问与保留，但合法或合规判断不能由一个 schema 函数自动完成。

## 治理责任要覆盖数据生命周期

给事件指定负责人，记录从产生、队列、存储到指标表的路径。字段发生变化时，需要知道哪些下游报表受影响。血缘信息与指标版本能解释同一份事件怎样变成结果，并支持修正错误计算。

设置原始数据、聚合数据和排错数据的访问范围与保留期。删除流程要覆盖副本、导出、备份与派生表的适用规则；只删主表可能留下可关联副本。对于无法立即删除的备份，应写明恢复后怎样避免把已删除数据重新导入。

OpenTelemetry 适合描述运行过程的信号，不意味着业务分析字段可以无限添加。把每个用户 ID 放进指标标签会造成高基数和隐私负担。请求关联 ID、业务事件与聚合维度应按不同用途管理，保留有助于调查的必要关联即可。

## 检查质量时保留缺失原因

数据质量包括字段有效、重复率、迟到比例与生产覆盖范围。一次采集任务成功不代表所有事件都到达。按版本、生产组件和时间段查看拒绝率，可以发现某个客户端版本突然漏发字段。

不要把缺失课程 ID 的记录补成任意课程，也不要把未知完成状态当成失败。修复时应保留原始错误分类与修正规则，必要时重新计算受影响窗口。数据仪表盘还应区分“零次完成”和“没有有效数据”，让使用者知道何时不能下判断。

## 练习：让采集用途与验收一致

设计一个课程完成事件，逐字段说明用途与保留期。准备正常、重复、缺字段、未知版本、同 ID 内容冲突与迟到记录，规定接纳、拒绝和隔离规则。再画出它到转化指标的路径。

验收时，重复不会增加完成次数；未知版本不会悄悄混入统计；最近窗口能标注迟到影响；普通日志不含正文或凭据。写出一次用户相关记录删除如何传到派生数据，并明确练习不能验证的法规与备份条件。测试应同时检查错误分类和统计分母，避免只验证最终计数为一。

## 资料来源与延伸阅读

- [OpenTelemetry concepts](https://opentelemetry.io/docs/concepts/)
- [Privacy principles](https://www.w3.org/TR/privacy-principles/)
- [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/)

资料核验：2026-11-10。教学示例不代表线上实测。

## 相关文章

- [AI 应用怎么观测：首字延迟、总耗时与成本](https://yishto.com/learn/production/latency-cost-observability/)
- [把个人站做成可持续维护的内容产品](https://yishto.com/learn/product-building/personal-sites-content-and-release/)
