|
|
@@ -105,6 +105,7 @@ RDS PG / ES ──DataX──▶ RAW ──SparkSQL──▶ ODS ──▶ DWD
|
|
|
- **维度退化**:将常用维度属性冗余到事实表,减少运行时 JOIN。
|
|
|
- **一致性维度**:公共维度全局统一(见 `dim_pub_*` 系列)。
|
|
|
- **原子粒度优先**:最低粒度事实可以无限上卷,高粒度事实不可下钻。
|
|
|
+- **加工层框架字段**:DWD / DIM / DWS / TDM 表统一带 `etl_time TIMESTAMP` + 分区 `dt STRING` + `STORED AS ORC`;raw / ods 字段与类型约定见 `22-raw建模.md` §0。
|
|
|
|
|
|
### 5.3 建模示例
|
|
|
|
|
|
@@ -233,74 +234,16 @@ RDS PG / ES ──DataX──▶ RAW ──SparkSQL──▶ ODS ──▶ DWD
|
|
|
|
|
|
### 7.3 各层职责与设计要点
|
|
|
|
|
|
-各层基础职责见 §2 表格;本节聚焦每层的关键设计取舍。
|
|
|
+各层基础职责见 §2;写入模式 / 回算窗 / 选型等操作细则见各层建模文档,本节只留指针,不与层文档重复。
|
|
|
|
|
|
-#### Raw 层
|
|
|
-
|
|
|
-> 基础职责见 §2 + §8.1。
|
|
|
-
|
|
|
-- **写入窗口**:抽取窗口 `[day-start, day+1-stop)`(48 小时宽),所有抓到的记录统一落 `dt = start_date`(业务日)分区
|
|
|
-- **设计理由**:宽窗覆盖"零点漂移"和"覆盖式更新下的永久丢失",保证数据永不丢失
|
|
|
-- **代价**:分区里混有"未来时间"的记录 + 同 pk 可能重复出现,接受这两个代价换抽取逻辑简单
|
|
|
-
|
|
|
-#### ODS 层
|
|
|
-
|
|
|
-> 基础职责见 §2 + §8.2。
|
|
|
-
|
|
|
-- **写入**:Spark SQL 动态分区 `PARTITION (dt)`,按 `DATE(update_time)` 分发,把 Raw 漂移数据归位到正确分区
|
|
|
-- **两种写入模式**(可表级混用):
|
|
|
- - **方案 A(INSERT OVERWRITE)**:每次 ODS 跑批覆盖对应 dt 分区;数据不丢失,因为 Raw 最多漂一天,次日 Raw 必然抓到
|
|
|
- - **方案 B(INSERT INTO + 分区内 `(pk, max(update_time))` 去重)**:保留每日 ODS 跑时刻的 `dt=X` 版本轨迹,用于审计、回溯,防止覆盖后丢失中间快照
|
|
|
-- **关键约束**:**跨 dt 不去重**。同一 pk 允许在多个 dt 分区并存,每条代表一个"时间段状态快照"——是上层 DIM 拉链表(SCD Type 2)的必要基础
|
|
|
-
|
|
|
-#### DWD 层(事实明细)
|
|
|
-
|
|
|
-> 基础职责 + 事件 vs 状态拆分原则见 §5.5。
|
|
|
-
|
|
|
-- **分区**:业务时间(下单日、支付日、事件发生日),不是抽取日
|
|
|
-- **写入**:每天**冗余跑近 3 日**,兜底 ODS 漂移(虽然 ODS 已归位,但 ODS 漂移修正后 DWD 需要回算)
|
|
|
-
|
|
|
-#### DIM 层(维度)
|
|
|
-
|
|
|
-- **职责**:承载业务实体的状态
|
|
|
-- **建模**:按表特征选型,**不统一**
|
|
|
-
|
|
|
-| 表特征 | 建模方式 | 分区策略 | 写入模式 |
|
|
|
-|---|---|---|---|
|
|
|
-| 大 / 中维度表(用户、商品、商户) | **拉链表 SCD2** | 不分区(或 `is_current` 二级分区) | 当日变更 pk:原行 `end_date` 置昨天 + 新行 insert |
|
|
|
-| 小高频变更维表(类目、地区、配置) | **每日全量快照** | 业务时间分区 | 每日全量覆盖 `dt=today` 分区 |
|
|
|
-| 极小不变表(字典、枚举) | 单表全量 | 不分区 | 偶尔全量覆盖 |
|
|
|
-
|
|
|
-**选型判据:变更率 × 保留天数**
|
|
|
-
|
|
|
-- 变更率低(< 1% / 日)+ 保留长:拉链更优
|
|
|
-- 变更率高(> 20% / 日)+ 保留短:快照更优
|
|
|
-
|
|
|
-**拉链表分区的特殊性:**
|
|
|
-
|
|
|
-- 拉链表每行是"状态生效区间",不是"时间点",天然不适合按业务时间分区
|
|
|
-- 可以按 `is_current='Y'/'N'` 做二级分区加速"当前状态"查询
|
|
|
-- 大表可以按 `start_date` 年份 / 月份做粗粒度分区控制扫描范围
|
|
|
-
|
|
|
-#### DWS 层
|
|
|
-
|
|
|
-- **职责**:面向分析主题的轻度汇总,**用冗余存储换查询性能**
|
|
|
-- **组织方式**:`主题 × 粒度 × 统计周期` 一张表
|
|
|
- - `dws_user_order_1d`、`dws_user_order_7d`、`dws_user_order_30d`
|
|
|
- - `dws_shop_order_1d`、`dws_shop_order_7d`、`dws_shop_order_30d`
|
|
|
-- **分区语义**:业务截止日。每个分区自包含完整周期聚合(7 日表每天分区含过去 7 天完整聚合)
|
|
|
-- **分区间冗余是刻意设计**:滑动窗口天然重叠,换取"一次分区裁剪命中答案"的查询速度
|
|
|
-- **来源**:DWD 事实表 + DIM 维度表 join 聚合
|
|
|
-- **增量计算优化**:`7d = 今日 1d + 昨日 7d - 7 天前 1d`,减少 DWD 扫描压力
|
|
|
-
|
|
|
-#### ADS 层
|
|
|
-
|
|
|
-- **职责**:面向具体报表 / 应用,把多个统计周期拼成一行,BI 直接用
|
|
|
-- **组织方式**:`报表主题` 一张表,`一行多周期`
|
|
|
- - `user_id | order_cnt_1d | order_cnt_7d | order_cnt_30d | gmv_1d | ... | dt`
|
|
|
-- **分区语义**:报表快照日(历史报表不可被后续数据改动,保审计性)
|
|
|
-- **生成方式**:多张 DWS 同分区日 join 而来
|
|
|
-- **可重放性**:所有 ADS 数据都能从 DWS / DWD / DIM 重算;实务中用 TTL 定期删除历史分区,要查老报表就触发任务重放
|
|
|
+| 层 | 关键设计取舍 | 详见 |
|
|
|
+|---|---|---|
|
|
|
+| Raw | 48h 宽窗抓取、全落 `dt=start_date`、容忍漂移 + 重复 | `22-raw建模` §0.1 · `21-时间语义` §4 · ADR-03 |
|
|
|
+| ODS | 动态分区按 `update_time` 归位、双源 union、跨 dt 不去重、INSERT OVERWRITE | `22-raw建模` §0.2 · `21-时间语义` §5 · ADR-03 |
|
|
|
+| DWD | 业务时间分区、滚动 N=30 回算、事件 vs 状态拆分(见 §5.5) | `23-dwd建模` · ADR-09 / ADR-11 |
|
|
|
+| DIM | 状态承载、`ful_d` 默认 / `zip_d` 按需、拉链不按业务时间分区 | `24-dim建模` · ADR-08 |
|
|
|
+| DWS | 主题 × 粒度日聚合、冗余换查询性能、维度退化 | `25-dws建模` · ADR-10 |
|
|
|
+| ADS | 多周期拼一行、报表快照日分区、可从 DWS/DWD/DIM 重放 | (ADS 文档待建) |
|
|
|
|
|
|
### 7.4 分区与建模设计原则
|
|
|
|
|
|
@@ -343,81 +286,6 @@ RDS PG / ES ──DataX──▶ RAW ──SparkSQL──▶ ODS ──▶ DWD
|
|
|
- **DWS / ADS**:派生层,可重放(前提上游数据还在),用 TTL 控制存储成本
|
|
|
- **保留周期自下而上递减**(越接近派生数据的层,TTL 越短)
|
|
|
|
|
|
-## 8. raw 层与 ods 层的职责约定
|
|
|
-
|
|
|
-这是本数仓的核心数据契约,所有 raw / ods 层作业都必须遵守。
|
|
|
-
|
|
|
-### 8.1 raw 层:schema-on-read landing
|
|
|
-
|
|
|
-> schema-on-read = 数据写入时不解释类型,读取时再按需解析。这是小数仓 / 列存 / 数据湖共用的范式,与传统 RDBMS 的 schema-on-write 形成对照。
|
|
|
-
|
|
|
-**全 STRING 的设计理由:**
|
|
|
-
|
|
|
-1. **隔离源端类型变化**:源系统改字段类型(`int4` → `bigint`、`varchar` → `text`)raw 入库零影响;类型解释下移 ods,源端变化只动 ods CAST 表。raw 表 schema 长期稳定,避免反复 ALTER 触发 metastore 高频变更
|
|
|
-2. **同步阶段不可失败**:raw 是回源链路兜底层,类型转换中单条脏数据可能让任务整个失败(如某行 `int4` 字段含 `'N/A'` → CAST 异常);STRING 永不失败,全量入仓后再到 ods 拦截脏数据
|
|
|
-3. **保留原始精度与原文**:CAST 可能丢精度(`NUMERIC(38,18)` → `DECIMAL(20,4)` 截断)、丢时区(`timestamptz` 反序列化)、改格式(日期字符串 `'20260101'` 反序列化后再格式化可能不一致);STRING 原汁原味,ods 想怎么解析都行
|
|
|
-4. **脏数据可观测**:业务库历史脏数据(`'1900-00-00'` 日期、`'-1'` 状态、超长字段)必须先入仓再观测;类型化阶段静默丢弃 / 报错跳过就再也看不到。STRING 100% 入仓 + ods 显式标记 / 分流(见 §8.2 脏数据拦截线)
|
|
|
-5. **schema-on-read 范式契合**:小数仓 / 列存(ORC)读取时类型解析成本极低,所以 raw 做 schema-on-read landing + ods 做 schema-on-write 是标准分工;vs 传统 OLTP 的 schema-on-write 必须入库时定型,灵活性差
|
|
|
-
|
|
|
-**何时可破例**:上述理由是工程权衡,不是教条。某个 raw 表场景如果这 5 条 ≥3 条不适用,可单独评估破例方式(如:数据源本就是 self-describing 的 NDJSON / Parquet / Avro 时保留单列裸文本 / 自带类型直存;schema 由上游严控且无脏数据风险时直接 typed 列入仓)。破例必须在 PR / 设计稿明示理由,不是默认。
|
|
|
-
|
|
|
-**规则:**
|
|
|
-
|
|
|
-- **全字段 STRING**:raw 层所有表业务字段以及 `dt` 分区字段一律 `STRING` 类型
|
|
|
-- **同步任务不做类型转换**:DataX ini 里不写 `columnType` 的类型映射(或统一填 `string`),CSV 导入时 SparkSQL 读取后也不 `CAST`
|
|
|
-- **外部表兜底**:raw 层建表一律用 `CREATE EXTERNAL TABLE`,DROP TABLE 只删元数据,HDFS 数据保留;raw 作为链路兜底层,误删元数据时数据仍可 `MSCK REPAIR` / 重建元数据恢复,无需回源库重同步
|
|
|
-
|
|
|
-### 8.2 ods 层:类型转换与脏数据识别
|
|
|
-
|
|
|
-- **ods 是类型化的第一层**:从 raw 的 STRING 字段做 `CAST` / `TRY_CAST`,输出真正类型化的干净表
|
|
|
-- **ods 是脏数据拦截线**:转换失败的数据不能静默丢弃,必须有可观测的出口(打标记字段、落到 `_err` 分区、或写入专门的数据质量日志表,具体策略 TBD)
|
|
|
-- **ods 不做业务语义加工**:只做"把字符串变回正确类型 + 空值兜底 + 去重",不做字段合并、维度关联、指标计算等 dwd 才做的事
|
|
|
-
|
|
|
-### 8.3 其他框架字段
|
|
|
-
|
|
|
-raw 层是否需要 `etl_load_time` / `src_file` / `src_row_no` 等框架字段,暂不做统一要求,后续实际接入第一批表时再根据需要补充到本节。
|
|
|
-
|
|
|
-### 8.4 ods 层类型映射参考
|
|
|
-
|
|
|
-**总则**:raw 层一律 STRING 兜底同步;类型化在 ods 层完成。下表为 ods 层 `CAST` 目标类型的参考表,具体字段可按业务需要微调(如小金额字段可下沉到 `DECIMAL(16,2)`)。
|
|
|
-
|
|
|
-#### 8.4.1 PostgreSQL → Hive
|
|
|
-
|
|
|
-| PG 类型 | Hive 类型 |
|
|
|
-|---------|-----------|
|
|
|
-| `int2` / `smallint` | `BIGINT` |
|
|
|
-| `int4` / `integer` / `int` | `BIGINT` |
|
|
|
-| `int8` / `bigint` | `BIGINT` |
|
|
|
-| `serial` | `BIGINT` |
|
|
|
-| `bigserial` | `BIGINT` |
|
|
|
-| `numeric` / `decimal` | `DECIMAL(20,4)` |
|
|
|
-| `real` / `float4` | `DECIMAL(20,4)` |
|
|
|
-| `float8` / `double precision` | `DECIMAL(20,4)` |
|
|
|
-| `char` / `character` | `STRING` |
|
|
|
-| `varchar` / `character varying` | `STRING` |
|
|
|
-| `text` | `STRING` |
|
|
|
-| `timestamp` / `timestamp without time zone` | `STRING` |
|
|
|
-| `timestamptz` | `STRING` |
|
|
|
-| `date` | `STRING` |
|
|
|
-| `time` / `timetz` | `STRING` |
|
|
|
-| `boolean` / `bool` | `TINYINT` |
|
|
|
-| `uuid` | `STRING` |
|
|
|
-| `interval` | `STRING` |
|
|
|
-| `tsvector` | `STRING` |
|
|
|
-| `array` | `STRING`(保留 JSON/文本形态,dwd 按需解析) |
|
|
|
-| `hstore` | `MAP<STRING,STRING>` |
|
|
|
-
|
|
|
-**说明**:
|
|
|
-
|
|
|
-- 整数统一 `BIGINT`:避免上游扩位(`int4` → `int8`)时下游被动改表
|
|
|
-- 小数统一 `DECIMAL(20,4)`:覆盖绝大多数金额/比率场景;特殊精度需求(如高精度科学计算)单独评估
|
|
|
-- 布尔用 `TINYINT`(0/1):Hive 的 `BOOLEAN` 与 ORC/Spark 生态兼容性没有 TINYINT 稳定
|
|
|
-- 时间类型全部 `STRING`:保留源端字面量,dwd 层再按需 `to_timestamp` / `to_date`
|
|
|
-
|
|
|
-#### 8.4.2 Elasticsearch → Hive
|
|
|
-
|
|
|
-(待补,首批 ES 埋点库接入时落地)
|
|
|
-
|
|
|
## 9. 相关文档
|
|
|
|
|
|
- [命名规范](40-命名规范.md) — 表/字段命名五段式
|