# 数据契约 > 数仓与数据服务平台之间的数据接口与表结构约定。 | 项 | 内容 | |----|------| | 文档版本 | v1.0 | | 文档状态 | 待评审 | | 更新日期 | 2026-06-21 | ## 修订记录 | 版本 | 日期 | 修订内容 | |------|------|----------| | v1.0 | 2026-06-21 | 初版 | --- > **v2(2026-06-24)**:MVP 数据源改为预聚合宽表 `ads_trd_group_funnel`(见 §11)。 > §3–§9 描述的 bitmap 方案(`daily_event_bitmap` / `period_event_bitmap`)对应"泛用漏斗",MVP **暂不落地**,留作后续阶段。 ## 1. 边界说明 本文档定义数仓与数据服务平台之间的数据契约。 职责边界: - 数仓负责产出 bitmap 数据。 - PostgreSQL 是数据服务层存储。 - FastAPI 从 PostgreSQL 读取 bitmap 并计算查询结果。 - 数据服务平台不存储埋点明细。 - 数据服务平台不负责数仓侧的更新、重算和明细治理。 ## 2. 用户 ID 前提 bitmap 中的用户 ID 已经满足以下条件: - `user_id` 是自增数值。 - `user_id` 适合写入 roaring bitmap。 - 数据服务层不负责字符串用户 ID 到数值 ID 的映射。 ## 3. bitmap 存储约定 bitmap 使用 PostgreSQL `bytea` 存储。 格式约定: - `bitmap_payload` 存储 roaring bitmap 的二进制序列化结果。 - `bitmap_format` 标识 bitmap 格式,例如 `roaring32` 或 `roaring64`。 - 不使用 text/base64 存储 bitmap。 - 不使用 PostgreSQL bitmap 扩展。 ## 4. 每日 bitmap 表 每日 bitmap 用于支持自定义时间范围查询,自定义范围最大 15 天。 建议表名: ```text daily_event_bitmap ``` 字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | event_date | date | 事件日期 | | event_name | text | 事件名称 | | bitmap_payload | bytea | 该日期、该事件对应的用户 bitmap | | bitmap_format | text | bitmap 格式,例如 `roaring32` | | uv_count | integer | 该日期、该事件的 UV 冗余值 | | updated_at | timestamp | 数据更新时间 | 唯一键: ```text event_date + event_name ``` ## 5. 标准周期 bitmap 表 标准周期 bitmap 用于支持快捷时间查询。 支持周期: - 昨日。 - 近 7 天。 - 近 30 天。 建议表名: ```text period_event_bitmap ``` 字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | period_type | text | 周期类型:`yesterday`、`last_7d`、`last_30d` | | period_start | date | 周期开始日期 | | period_end | date | 周期结束日期 | | event_name | text | 事件名称 | | bitmap_payload | bytea | 该周期、该事件对应的用户 bitmap | | bitmap_format | text | bitmap 格式,例如 `roaring32` | | uv_count | integer | 该周期、该事件的 UV 冗余值 | | updated_at | timestamp | 数据更新时间 | 唯一键: ```text period_type + period_start + period_end + event_name ``` ## 6. 日期规则 日期规则: - 默认最大可选日期为昨日。 - 今天不纳入 MVP 查询范围。 - 自定义时间范围最大 15 天。 - 快捷时间范围由标准周期表提供。 周期定义: - `yesterday`:昨日。 - `last_7d`:截至昨日的近 7 天。 - `last_30d`:截至昨日的近 30 天。 ## 7. 缺失数据规则 数据缺失时,接口必须返回明确状态,不静默补零。 缺失场景包括: - 某日期没有对应事件 bitmap。 - 某标准周期没有对应事件 bitmap。 - bitmap 格式不被服务端支持。 - bitmap payload 无法解析。 建议状态: ```text ready # 数据完整 partial # 部分数据缺失 missing # 查询范围数据缺失 invalid # 数据格式错误 ``` ## 8. 查询使用规则 标准周期查询: - 如果请求时间范围命中昨日、近 7 天、近 30 天,优先读取 `period_event_bitmap`。 - 直接使用周期 bitmap 的 cardinality 或 `uv_count` 返回 UV。 自定义范围查询: - 读取 `daily_event_bitmap` 中对应日期和事件的 bitmap。 - 每个事件在时间范围内做 bitmap OR。 - OR 后取 cardinality 得到该事件 UV。 ## 9. 验收标准 - PostgreSQL 表中 bitmap 字段类型为 `bytea`。 - 数据服务层能区分 daily bitmap 和 period bitmap。 - 快捷时间查询可以命中标准周期数据。 - 自定义查询最大只需要组合 15 天 daily bitmap。 - 缺失数据不会被静默补零。 - 文档中不引入 Redis、PG 明细事件表或 PostgreSQL bitmap 扩展作为 MVP 依赖。 ## 10. 后续能力域产出表(非 MVP 数据源) MVP 仅依赖 §4 `daily_event_bitmap` 与 §5 `period_event_bitmap`。以下为其余能力域对应的数仓产出表,此处登记备查,本期**不接入**,字段以后续各域设计为准: | 表 | 能力域 | 用途 | | --- | --- | --- | | `ads_funnel_result_d` | 漏斗 | 固定漏斗的预计算结果 | | `ads_retention_matrix_d` | 埋点完整 | 留存矩阵 | | `ads_path_d` | 埋点完整 | 行为路径 | | `dws_user_tag_wide_d` | 用户画像 | 标签宽表 | | `dws_user_tag_long_d` | 用户画像 | 标签长表(按更新频率分层) | | `dim_user_segment_d` | 用户画像 | 人群包 | | `dwd_touch_record_d` | 营销触达 | 触达记录 | > `ads_funnel_result_d` 是固定漏斗的预计算结果,与 MVP 的事件级 bitmap 组合是**两种不同供给路径**:MVP 泛用漏斗(步骤用户自选、非递进)用 bitmap 两表,不依赖该表。两者关系(是否后续作为固定漏斗的加速层)留待后续定。 ## 11. MVP 数据源:拼团漏斗两张表(v3,2026-06-24) MVP 漏斗 = **拼团漏斗**,固定 5 步(漏斗顺序): 启动 `start` → 曝光 `show` → 拼团详情 `detail` → 下单 `order` → 成功 `paid`。 数据拆成**两张表**,因同步逻辑不同。两表 ADS↔PG 结构一致。数据为 **T+1**:今天的数据次日才产出,故**最大可查日始终为昨日**。 ### 11.1 `ads_trd_group_funnel_daily` —— 单日,留全历史 每日**增量 insert 新 `dt`**,逐日累积,可回溯任意历史单日。 | 字段 | 类型 | 说明 | | --- | --- | --- | | `dt` | varchar(8) | 快照日 `yyyyMMdd`(主键) | | `uv_start` | bigint | 启动 UV | | `uv_show` | bigint | 曝光 UV | | `uv_detail` | bigint | 拼团详情 UV | | `uv_order` | bigint | 下单 UV | | `uv_paid` | bigint | 成功 UV | | `etl_time` | timestamp | ETL 处理时间 | ### 11.2 `ads_trd_group_funnel_rolling` —— 近 7/30 天,只保留最新一行 每日**覆盖最新 1 行**(`as-of` 快照),**无历史**——只能取当前的近 7/30 天。 | 字段 | 类型 | 说明 | | --- | --- | --- | | `dt` | varchar(8) | as-of 快照日 `yyyyMMdd` | | `uv_start_7d` | bigint | 近 7 天 启动 UV | | `uv_show_7d` | bigint | 近 7 天 曝光 UV | | `uv_detail_7d` | bigint | 近 7 天 拼团详情 UV | | `uv_order_7d` | bigint | 近 7 天 下单 UV | | `uv_paid_7d` | bigint | 近 7 天 成功 UV | | `uv_start_30d` | bigint | 近 30 天 启动 UV | | `uv_show_30d` | bigint | 近 30 天 曝光 UV | | `uv_detail_30d` | bigint | 近 30 天 拼团详情 UV | | `uv_order_30d` | bigint | 近 30 天 下单 UV | | `uv_paid_30d` | bigint | 近 30 天 成功 UV | | `etl_time` | timestamp | ETL 处理时间 | ### 11.3 周期 → 取数路由 | period | 表 | 取行 | 列 | | --- | --- | --- | --- | | `day`(单日) | `..._daily` | 给 `snapshot_dt` → `WHERE dt=:dt`;否则 `ORDER BY dt DESC LIMIT 1` | `uv_start/show/detail/order/paid` | | `last_7d` | `..._rolling` | 唯一行 | `uv_*_7d` | | `last_30d` | `..._rolling` | 唯一行 | `uv_*_30d` | - **单日**支持历史:`snapshot_dt` 可选,省略=最新(昨日),给值=该天;上限昨日(T+1),今天及未来拒绝。 - **近 7/30 天**只有最新 as-of 行,不接受历史 `snapshot_dt`(忽略)。 - 响应 `snapshot_dt` 回显实际取数那行的 `dt`(单日=该天;7/30 天=rolling 的 as-of 日,即"数据截至"日)。 缺失规则:目标行不存在或对应列为 `NULL` → `data_status = missing`,不补零。