# DWS 建模 > 本数仓 DWS 层(汇总层)的字段建模与设计约定。建模方法论(主题宽表 / 维度退化原则 / 业界 OneData 范式)见 `20-数仓分层与建模.md` §5;命名规则见 `21-命名规范.md` §3.5;时间语义见 `26-时间语义.md`。 > > 本文档按"主题宽表一节"组织,每节包含主题定义 / 粒度 / 来源 / dt 锚点 / 度量字段说明 / 字段表。 ## 1. 通用约定 ### 1.1 框架字段 所有 DWS 表必带 `etl_time TIMESTAMP` + 分区 `dt STRING`,`STORED AS ORC`。 ### 1.2 单一职责:日聚合 DWS 只做 `_1d` 日聚合主题宽表,不爆窗口表(不建 `_30d` / `_y{年份}` 等多窗口物化)。跨周期窗口(30d / yYYYY 累计 / yYYYY 总额)由上层 TDM 跑批从 `dws_1d` 滚动聚合,TDM 按更新周期分 `_d`(日更)/ `_o`(一次性凝固)。 理由: - DWS 职责单一保持稳定,避免跨周期物化的实体表爆炸 - 跨周期物化由 TDM 表的更新周期分类(d/o)天然解决 - 1 期数据量级 dws_1d 单年扫描 Spark 可接受 ### 1.3 维度退化策略 业界主流(阿里 OneData)DWS 加强维度退化 + 宽表化以提升查询效率。本项目 1 期 scope 服务标签计算(仅用 `user_id × category × dt`),暂不冗余退化字段。后续触发条件评估扩展: - 上层 BI 直接查 DWS 做透视分析(按非主键维度聚合,如 cert_city / merchant) - 标签维度从 (user, category) 扩展到多维组合 - 跨域 join 频繁,DWS ← DIM 重复成本不可接受 补法: - 简单 = `ALTER TABLE ADD COLUMN` + 重刷历史分区(DWS 聚合层重刷代价小) - 复杂 = 新建第二张主题宽表(业界 1-3 张 / 主题,如 `dws_usr_user_demo_1d` 走人口学维度) ### 1.4 分区与写入 - 分区锚点:业务时间(与上游 DWD 对齐,如 `DATE(payment_success_time)`) - 写入策略:**回算近 2 日**(`dt IN (${dt}, ${pdt})`),与 DWD N=2 对齐(DWD 漂移连锁补偿,参 `93-架构决策.md` ADR-09) - 分区类型:动态分区 `PARTITION (dt)` - 重跑幂等:`INSERT OVERWRITE PARTITION (dt)` 项目默认 DYNAMIC mode(kb/26 §8)只覆盖 SELECT 出现的 dt,不动其他历史分区 - 调度依赖:DS DEPENDENT 同 dt DWD 跑完 --- ## 2. dws_usr_user_trade_1d(用户 × 品类 × 日 交易主题宽表) ### 2.1 主题 用户 × 品类粒度的日交易聚合,承载偏好标签(金额 / 次数 / 多窗口)的聚合基础。 ### 2.2 粒度 `(user_id, category, dt)` 在分区内唯一。`category` 取 `dim_trd_card_group_ful_d.category`(DIM 已清洗,叶子品类,权威源)。 ### 2.3 来源 `dwd_trd_order_pay_apd_d` 单源(A3 锁定 1 期不做 refund,2 期接退款时再补 refund / net 度量)。 DWD 已完成维度退化(`category` 来自 `dim_trd_card_group_ful_d`,DIM 已归一脏数据),DWS 直引 DWD 的 `category` 字段,不再二次 join DIM。 ### 2.4 dt 锚点 承袭 DWD:`DATE(payment_success_time)` 业务时间分区。 ### 2.5 度量字段说明 按业界 DWS 宽表化原则保留多度量混存,下游 BI / TDM 不再写减法、不再 join 明细。 **口径要点**: - `pay_amt_cny`(Net Revenue)= **偏好标签金额口径**。DWD 已内置 `mer_act%` 修正规则(mer_act% 时取 `point/100`,否则取 `actual_payment`),详见 kb/27 §2.5 - `payable_amt_cny`(GMV)= **业务通用 GMV 口径**,与偏好标签解耦(业务侧 SQL 常用) - `pay_order_cnt = COUNT(DISTINCT order_id)` = **偏好标签次数口径**(A2 锁定,不用份数) - `purchase_cnt`(份数)保留作 2 期备用 + 审计,1 期标签不用 **砍掉的字段**(违反"字段要全"原则但 1 期 scope 不扩张优先): - `card_price_cny` / `act_price_cny`(单价 SUM 无业务意义) - `discount_amount_amt_cny`(DWD 字段名未拍板,待业务侧澄清与 `merchant_discount` 语义区别) - `shipping_free_amt_cny`(运费券 SUM 业务意义不明) - `discount_point` / `give_cnt`(非偏好主流度量) ### 2.6 字段表 | 分组 | 字段 | 类型 | 来源 / 算法 | 说明 | |---|---|---|---|---| | 主键 | user_id | BIGINT | dwd | 用户 id | | 主键 | category | STRING | dwd | 叶子品类(DIM 已清洗)| | 度量-数量 | pay_order_cnt | BIGINT | `COUNT(DISTINCT order_id)` | 当日支付订单数(偏好次数口径)| | 度量-数量 | purchase_cnt | BIGINT | `SUM(purchase_cnt)` | 当日支付份数(备用)| | 度量-金额 | payable_amt_cny | DECIMAL(20,4) | `SUM(payable_amt_cny)` | GMV | | 度量-金额 | pay_amt_cny | DECIMAL(20,4) | `SUM(pay_amt_cny)` | Net Revenue(偏好金额口径)| | 度量-金额 | trade_amt_cny | DECIMAL(20,4) | `SUM(trade_amt_cny)` | 订单交易金额 | | 度量-金额 | settle_amt_cny | DECIMAL(20,4) | `SUM(settle_amt_cny)` | 结算金额 | | 度量-金额 | merchant_discount_amt_cny | DECIMAL(20,4) | `SUM(merchant_discount_amt_cny)` | 商家折扣 | | 度量-金额 | platform_discount_amt_cny | DECIMAL(20,4) | `SUM(platform_discount_amt_cny)` | 平台券折扣 | | 度量-金额 | member_discount_amt_cny | DECIMAL(20,4) | `SUM(member_discount_amt_cny)` | 会员折扣 | | 度量-金额 | act_discount_amt_cny | DECIMAL(20,4) | `SUM(act_discount_amt_cny)` | 活动折扣 | | 度量-金额 | point_deduct_amt_cny | DECIMAL(20,4) | `SUM(point_deduct_amt_cny)` | 积分抵扣金额 | | 度量-金额 | shipping_amt_cny | DECIMAL(20,4) | `SUM(shipping_amt_cny)` | 运费 | | 度量-积分 | point | BIGINT | `SUM(point)` | 当日消耗积分 | | 框架 | etl_time | TIMESTAMP | 派生 | ETL 处理时间 | | 分区 | dt | STRING | `DATE(payment_success_time)` | **业务时间分区**| ### 2.7 不带的字段说明 - **维度退化字段**(用户域 sex_cert / cert_city / level,商家域 merchant_id / merchant_name 等):1 期 scope 服务标签计算暂不冗余,触发条件见 §1.3 - **lv1 大类 `main_category`**(业务库原名 `first_sport`):业务侧 2026-05-08 拍板 1 期不引,2 期单独处理大类聚合时再补 - **refund / net 度量**:A3 锁定 1 期不做退款,2 期接 refund 时按业务诉求选择: - 业界主流(OneData / 字节):refund 度量聚到本表 + 加 `net_amt_cny` / `net_order_cnt` 冗余列 - 替代方案:单独新建 `dws_usr_user_refund_1d` + 上层 join