Prechádzať zdrojové kódy

docs(kb): 加 27-dwd建模(pay 明细)+ 28-dim建模(user/cgroup + sport 清洗 + 跑批策略)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tianyu.chu 1 deň pred
rodič
commit
19c0ac6e13
4 zmenil súbory, kde vykonal 366 pridanie a 0 odobranie
  1. 2 0
      README.md
  2. 138 0
      kb/27-dwd建模.md
  3. 225 0
      kb/28-dim建模.md
  4. 1 0
      kb/92-重构进度.md

+ 2 - 0
README.md

@@ -89,6 +89,8 @@ PG/ES ──DataX(raw)──> RAW ──> ODS ──> DWD ──> DWS ──> TD
 | [24-raw 建模](kb/24-raw建模.md) | **raw 层字段裁剪决策**:各 raw 表三态标记(保留 / 明性裁 / 隐性裁)+ 决策理由溯源 |
 | [25-raw 接入流程](kb/25-raw接入流程.md) | **新表入仓标准 8 步**:sync 生成器 + mask 配置 + DDL 生成器 + raw 建模文档协同 |
 | [26-时间语义](kb/26-时间语义.md) | **时间变量约定**:T 任务日锚点 + DS 变量底层 + cdt/dt/tdt/pdt 项目参数 + raw/ods 各层 dt 语义 + 重跑幂等条件 |
+| [27-dwd 建模](kb/27-dwd建模.md) | **DWD 字段建模**:业务过程拆分 + 维度退化策略 + 单分区不回算 + 各业务过程字段表 |
+| [28-dim 建模](kb/28-dim建模.md) | **DIM 字段建模**:ful_d 优先选型 + ful→zip 触发条件 + 跑批策略(初始化 + 增量合并)+ 脏数据清洗位置 + 各实体字段表 |
 
 ### 3x 开发流程
 

+ 138 - 0
kb/27-dwd建模.md

@@ -0,0 +1,138 @@
+# DWD 建模
+
+> 本数仓 DWD 层(明细层)的字段建模与设计约定。建模方法论(事件 vs 状态拆分、维度建模五步、星型模型)见 `20-数仓分层与建模.md` §5;命名规则见 `21-命名规范.md` §3.4;时间语义见 `26-时间语义.md`。
+>
+> 本文档按"业务过程一节"组织,每节包含业务过程定义 / 粒度 / dt 锚点 / 维度退化策略 / 字段表。
+
+## 1. 通用约定
+
+### 1.1 框架字段
+
+所有 DWD 表必带 `etl_time TIMESTAMP` + 分区 `dt STRING`,`STORED AS ORC`。
+
+### 1.2 业务过程拆分
+
+按 `kb/20 §5.5`:每个业务过程一张 `_apd_d` 事件表(不可变事实,只追加)。订单履约的"下单 / 支付 / 发货 / 签收"各拆一张;拼团循环动作(发起 / 审核 / 拒绝 / 重提交)按需各拆一张。
+
+### 1.3 维度退化策略
+
+DWD 直引 DIM 层已清洗字段,**不在 DWD 二次清洗、不做空值兜底**。如 `cgi.sport` 脏数据归一在 `dim_trd_card_group_ful_d` 完成(见 `28-dim建模.md §3.2`),DWD pay 维度退化时直引 DIM 已清洗的 `sport`。
+
+### 1.4 分区与写入
+
+- 分区锚点:业务时间(事件发生日,如 `payment_success_time`),不是抽取日
+- 写入策略:默认单分区 `dt=T-1`,不回算(ODS 漂移已在 ODS 层归位,DWD 不二次兜底)
+- 重跑幂等:`INSERT OVERWRITE` 单分区
+
+---
+
+## 2. dwd_trd_order_pay_apd_d(订单支付明细)
+
+### 2.1 业务过程
+
+订单支付完成。源表 `ods_trd_card_group_order_info_inc_d` 中筛选支付成功的订单。
+
+支付成功判定:
+
+```sql
+WHERE order_type = 'group'
+  AND status IN (101, 103, 104, 105, 106, 301, 302)
+```
+
+### 2.2 粒度
+
+订单 id(一条 `card_group_order_info` 记录 = 一行)。
+
+### 2.3 dt 锚点
+
+`DATE(payment_success_time)`,业务时间分区。同一笔订单在 ODS 层(`update_time` 锚点)和 DWD 层(业务时间锚点)的分区位置不同,是建模设计的预期。
+
+### 2.4 维度退化
+
+| 字段来源 | 退化字段 |
+|---|---|
+| `dim_trd_card_group_ful_d`(拼团 → 品类)| `sport` / `manufacturer` / `sets` / `year` / `list_id` / `panini_list_id` / `group_name` |
+| `card_group_order_info` 自有 | 其他业务字段直存 |
+
+DWD 不二次清洗 sport(`dim_trd_card_group_ful_d` 已归一脏数据)。**不带大类 `first_sport`**(业务侧定:拼团大类即 `sport` 叶子,大类聚合按需在上层做)。
+
+### 2.5 accounts_payable_cny 派生规则
+
+业务库分/元单位混存,按 `point_type` 区分换算:
+
+```sql
+CASE
+    WHEN cgoi.point_type LIKE 'mer_act%' THEN ROUND(cgoi.accounts_payable / 100.00, 2)
+    ELSE cgoi.accounts_payable
+END AS accounts_payable_cny
+```
+
+`point_type LIKE 'mer_act%'` 时除 100,其他直取。**DWD 内置该规则,下游不再处理**。GMV 口径走该字段。
+
+### 2.6 字段表
+
+| 分组 | 字段 | 类型 | 来源 | 说明 |
+|---|---|---|---|---|
+| 主键 | order_id | BIGINT | order.id | 订单 id |
+| 标识 | order_no | STRING | order | 订单编码 |
+| 标识 | combination_no | STRING | order | 拆分订单关联编号 |
+| 标识 | give_order_id | BIGINT | order | 赠与关联订单 id |
+| 用户维度 | user_id | BIGINT | order | |
+| 商家维度 | merchant_id | BIGINT | order | |
+| 拼团维度 | group_info_id | BIGINT | order | |
+| 拼团维度退化 | group_name | STRING | dim_trd_card_group | 拼团名称 |
+| 拼团维度退化 | list_id | BIGINT | dim_trd_card_group | 商家上线 checklist id(业务库快照冗余)|
+| 拼团维度退化 | panini_list_id | BIGINT | dim_trd_card_group | 帕尼尼 list id(业务库快照冗余)|
+| 拼团维度退化 | sport | STRING | dim_trd_card_group | 运动品类(DIM 已清洗,权威源)|
+| 拼团维度退化 | manufacturer | STRING | dim_trd_card_group | 厂商 |
+| 拼团维度退化 | sets | STRING | dim_trd_card_group | 系列 |
+| 拼团维度退化 | year | STRING | dim_trd_card_group | 年份(赛季)|
+| 收货 | shipping_address_id | BIGINT | order | |
+| 数量 | purchase_count | BIGINT | order | 购买份数 |
+| 数量 | give_num | BIGINT | order | 赠送个数 |
+| 金额 | accounts_payable_cny | DECIMAL(20,4) | 派生(见 §2.5)| **GMV 字段** |
+| 金额 | actual_payment_cny | DECIMAL(20,4) | order.actual_payment | 实付款(GMV 不用此字段,保留作冗余)|
+| 金额 | trade_amount_cny | DECIMAL(20,4) | order | 订单交易金额 |
+| 金额 | settlement_amount_cny | DECIMAL(20,4) | order | 结算金额(实付-退款)|
+| 金额 | card_price_cny | DECIMAL(20,4) | order | 应付款(拼团时点价)|
+| 金额 | act_price_cny | DECIMAL(20,4) | order | 应付款(活动价)|
+| 金额 | discount_cny | DECIMAL(20,4) | order | 折扣 |
+| 金额 | discount_amount_cny | DECIMAL(20,4) | order | 折扣金额 |
+| 金额 | platform_discount_cny | DECIMAL(20,4) | order | 平台券折扣 |
+| 金额 | member_discount_cny | DECIMAL(20,4) | order | 会员折扣 |
+| 金额 | act_discount_cny | DECIMAL(20,4) | order | 活动折扣 |
+| 金额 | point_deduct_cny | DECIMAL(20,4) | order | 积分抵扣金额 |
+| 金额 | shipping_cost_cny | DECIMAL(20,4) | order | 运费 |
+| 金额 | shipping_free_amount_cny | DECIMAL(20,4) | order | 运费券金额 |
+| 积分 | point | BIGINT | order | 消耗积分 |
+| 积分 | discount_point | BIGINT | order | 折扣积分 |
+| 优惠券 | coupon | BIGINT | order | 优惠券 id |
+| 优惠券 | platform_coupon | BIGINT | order | 平台券 id |
+| 优惠券 | shipping_free_id | BIGINT | order | 运费券 id |
+| 支付 | payment_type | STRING | order | 支付方式-交易类型 |
+| 支付 | payment_sub_type | STRING | order | 支付子分类 |
+| 支付 | payment_status | STRING | order | 交易状态 |
+| 支付 | payment_status_desc | STRING | order | 交易状态描述 |
+| 支付 | payment_time | TIMESTAMP | order | 支付时间 |
+| 支付 | **payment_success_time** | TIMESTAMP | order | **支付完成时间(dt 锚点)**|
+| 支付 | pay_record | TINYINT | order | 是否重复支付 |
+| 业务标记 | order_type | STRING | order | 订单类型 |
+| 业务标记 | order_sub_type | STRING | order | 订单子类型(含赠与)|
+| 业务标记 | give_user_code | STRING | order | 赠与人 |
+| 业务标记 | status | BIGINT | order | 订单状态 |
+| 业务标记 | serve_status | BIGINT | order | 业务状态 |
+| 业务标记 | refuse_status | TINYINT | order | 是否接受累积发货 |
+| 业务标记 | invoice_id | BIGINT | order | 发票记录 id |
+| 业务标记 | anonymous | BOOLEAN | order | 是否匿名 |
+| 业务标记 | pick_up_type | STRING | order | 提货方式 |
+| 业务标记 | point_type | STRING | order | 使用积分类型 |
+| 业务标记 | open_self | TINYINT | order | 是否商家代拆 |
+| 业务标记 | goods_allocate | TINYINT | order | 卡密是否分配 |
+| 风控 | waring_type | STRING | order | 风险异常类型 |
+| 风控 | waring_status | TINYINT | order | 风险异常状态 |
+| 时间 | order_create_time | TIMESTAMP | order.create_time | 下单时间 |
+| 时间 | order_update_time | TIMESTAMP | order.update_time | 订单最近更新时间 |
+| 时间 | expire_time | TIMESTAMP | order | 过期时间 |
+| 软删 | is_deleted | BOOLEAN | order | 软删归一 |
+| 框架 | etl_time | TIMESTAMP | 派生 | ETL 处理时间 |
+| 分区 | dt | STRING | `DATE(payment_success_time)` | **业务时间分区**|

+ 225 - 0
kb/28-dim建模.md

@@ -0,0 +1,225 @@
+# DIM 建模
+
+> 本数仓 DIM 层(维度层)的字段建模与设计约定。建模方法论(拉链表 SCD2 vs 全量快照选型、拉链表分区特殊性)见 `20-数仓分层与建模.md` §5.5 / §7.3;命名规则见 `21-命名规范.md` §3.3。
+>
+> 本文档按"实体一节"组织,每节包含实体范围 / 关键设计 / 字段表。
+
+## 1. 通用约定
+
+### 1.1 框架字段
+
+所有 DIM 表必带 `etl_time TIMESTAMP` + 分区 `dt STRING`,`STORED AS ORC`。
+
+### 1.2 选型策略
+
+默认 `_ful_d`(每日全量快照)。`_zip_d`(SCD2 拉链)按需评估。
+
+**ful_d → zip_d 触发条件**(满足任一即评估迁 zip):
+
+- 出现"看历史属性变化"的标签 / 报表需求
+- 全量快照存储 > 100 GB 或保留期 > 3 年
+- 业务侧明确要回放某历史 dt 的实体状态
+
+**双轨共存**:迁 zip 时不替换 ful_d,新建 `_zip_d` 并存:
+
+| 表 | 用途 |
+|---|---|
+| `_ful_d` | 保留近 7 天热快照,下游 join 单分区即可 |
+| `_zip_d` | 全量历史 SCD2 拉链,属性变化分析 / 历史回放 |
+
+### 1.3 跑批策略
+
+ODS 跨 dt 不去重 → 同 pk 多分区并存 → DIM 取每个 pk 的最新有效行。
+
+- **初始化**:扫 ODS 全量分区 + `ROW_NUMBER OVER (PARTITION BY pk ORDER BY update_time DESC)` 取每 pk 最新行落 DIM 首日分区
+- **日常增量**:用「昨日 DIM + 今日 ODS 增量」按 pk 合并去重(同 pk 取较新 `update_time`),避免每日全量扫 ODS
+
+### 1.4 脏数据清洗位置
+
+源端字段值脏数据(如同一概念多种写法 `mlb` / `MLB`)的归一清洗放 **DIM 层**完成;DWD 维度退化时直引 DIM 已清洗字段,下游 DWS / TDM 不再清洗。
+
+---
+
+## 2. dim_usr_user_ful_d(用户维度)
+
+### 2.1 实体
+
+`app_base_user` 主表 LEFT JOIN `app_user_cert_info`(按 `user_id`),用户主信息 + 证件实名信息合一。
+
+### 2.2 性别 / 生日来源
+
+只取 `cert_info.cert_sex` / `cert_birthday`,**实名才有标签**,未实名用户对应字段为空。
+
+不冗余 `app_base_user.sex` / `birthday`:业务库里几乎全空 + 双源会引出收敛规则的复杂度。下游标签生成时 `is_cert=true` 才输出实名相关标签,否则空值。
+
+### 2.3 字段表
+
+| 分组 | 字段 | 类型 | 来源 | 说明 |
+|---|---|---|---|---|
+| 标识 | user_id | BIGINT | base_user.id | PK |
+| 标识 | appid | STRING | base_user | 所属程序 |
+| 标识 | username | STRING | base_user | 账号 |
+| 标识 | code | STRING | base_user | 会员码 |
+| 实名 | sex_cert | TINYINT | cert_info.cert_sex | 证件性别 |
+| 实名 | birthday_cert | STRING | cert_info.cert_birthday | 证件生日 |
+| 实名 | cert_province | STRING | cert_info | 证件所在省 |
+| 实名 | cert_city | STRING | cert_info | 证件所在市 |
+| 实名 | is_cert | BOOLEAN | 派生 | cert_info 命中即 true |
+| 实名 | id_card | STRING | base_user.id_card | 身份证号(已 md5)|
+| 实名 | face_verify | TINYINT | base_user | 人脸识别通过标志 |
+| 实名 | cancel_verify_num | BIGINT | base_user | 重置实名次数 |
+| 注册 | register_channel | STRING | base_user | 注册渠道 |
+| 注册 | register_addr | STRING | base_user | 注册省区 |
+| 注册 | register_ip_addr | STRING | base_user | 注册 IP |
+| 注册 | reg_create_time | TIMESTAMP | base_user.create_time | 注册时间 |
+| 登录 | login_addr | STRING | base_user | 上次登陆省区 |
+| 登录 | login_ip_addr | STRING | base_user | 上次登陆 IP |
+| 会员 | level | BIGINT | base_user.level | 会员等级 |
+| 会员 | member_level | BIGINT | base_user.member_level | 会员等级(业务库重复字段,先全保留待澄清)|
+| 会员 | member_name | STRING | base_user | 会员等级名称 |
+| 会员 | growth_num | BIGINT | base_user | 成长值 |
+| 会员 | current_month_growth | BIGINT | base_user | 当月成长值 |
+| 会员 | member_keep_growth | BIGINT | base_user | 保级所需成长值 |
+| 会员 | member_init_flag | TINYINT | base_user | 月初初始化标志 |
+| 会员 | point | BIGINT | base_user | 积分 |
+| 业务库冗余 | consume_amount_cny | DECIMAL(20,4) | base_user.consume_amount | 业务库后端自带消费总额,口径未对齐数仓;保留作审计对账 |
+| 业务库冗余 | order_total_num | BIGINT | base_user | 业务库后端自带订单总数,同上 |
+| 状态 | status | TINYINT | base_user | 用户状态 |
+| 状态 | blacklist | TINYINT | base_user | 黑名单标记 |
+| 偏好 | refuse_pick_up | TINYINT | base_user | 是否拒绝自提 |
+| 偏好 | notify_flag | TINYINT | base_user | 推送是否接受 |
+| 偏好 | open_invoice | TINYINT | base_user | 开票权限 |
+| 偏好 | open_psd | TINYINT | base_user | 支付开关 |
+| 限额 | daily_limit | BIGINT | base_user | 每日限额提醒 |
+| 限额 | weekly_limit | BIGINT | base_user | 每周限额提醒 |
+| 限额 | monthly_limit | BIGINT | base_user | 每月限额 |
+| 时间 | last_update_time | TIMESTAMP | base_user.update_time | 最近更新时间 |
+| 软删 | is_deleted | BOOLEAN | base_user | 软删归一 |
+| 框架 | etl_time | TIMESTAMP | 派生 | ETL 处理时间 |
+| 分区 | dt | STRING | 控制 | T-1,`yyyyMMdd` |
+
+---
+
+## 3. dim_trd_card_group_ful_d(拼团维度)
+
+### 3.1 实体
+
+`card_group_info`(拼团信息),承载"商家上架的拼团活动"实体。订单 → 品类的归属通过本表 `sport` 字段取得。
+
+### 3.2 sport 脏数据清洗
+
+**业务依据**:拼团可上单个产品,也可组合多个产品(可能跨类);以商家设置的拼团大类(`cgi.sport`)为准聚合最贴近业务侧分析口径,因此 `sport` 取自拼团表本身,不通过底层产品表(panini / checklist)反查。
+
+**清洗规则**(DIM 内置,下游直引):
+
+| 原值 | 清洗后 |
+|---|---|
+| `mlb` | `MLB` |
+| `Boxing` | `UFC` |
+| `other` | NULL(聚合时 `WHERE sport IS NOT NULL` 过滤)|
+| 其他 | 原值保留 |
+
+### 3.3 字段表
+
+| 分组 | 字段 | 类型 | 来源 | 说明 |
+|---|---|---|---|---|
+| 标识 | group_info_id | BIGINT | id | PK |
+| 标识 | code | STRING | | 编码 |
+| 标识 | appid | STRING | | 所属程序 |
+| 标识 | name | STRING | | 拼团名称 |
+| 标识 | display_name | STRING | | 系列别名(显示名)|
+| 标识 | group_show_name | STRING | | 精美卡片名称 |
+| 商家关联 | merchant_id | BIGINT | | 商家 id |
+| 商家关联 | mer_name | STRING | | 商户名称(冗余)|
+| 商品关联 | list_id | BIGINT | | 商家上线 checklist id |
+| 商品关联 | list_code | STRING | | checklist code |
+| 商品关联 | panini_list_id | BIGINT | | 帕尼尼 list id(业务库快照冗余)|
+| 分类 | sport | STRING | | 运动类型(含 §3.2 脏数据清洗)|
+| 分类 | year | STRING | | 年份(赛季)|
+| 分类 | manufacturer | STRING | | 厂商 |
+| 分类 | sets | STRING | | 系列 |
+| 销售配置 | type | STRING | | 组团方式 |
+| 销售配置 | sub_type | STRING | | 组队方式子方式 |
+| 销售配置 | random_type | STRING | | 随机方式 |
+| 销售配置 | specs | STRING | | 商品规格 |
+| 销售配置 | total_price_cny | DECIMAL(20,4) | total_price | 商品总价 |
+| 销售配置 | unit_price_cny | DECIMAL(20,4) | unit_price | 单份售价 |
+| 销售配置 | act_price_cny | DECIMAL(20,4) | act_price | 私域分享优惠价 |
+| 销售配置 | copies | BIGINT | | 商品份数 |
+| 销售配置 | total_num | BIGINT | | 总数量 |
+| 销售配置 | weight | BIGINT | | 重量 |
+| 销售配置 | order_quota_min | BIGINT | | 每笔订单最少购买 |
+| 销售配置 | order_quota_max | BIGINT | | 每笔订单最多购买 |
+| 销售配置 | user_quota_max | BIGINT | | 用户最多购买 |
+| 销售配置 | min_card_num | BIGINT | | 免运费达标数量 |
+| 销售配置 | mix_copies | TINYINT | | 组合加倍 |
+| 销售配置 | change_type | STRING | | 买对玩法改变后组队方式 |
+| 销售状态 | status | BIGINT | | 状态 |
+| 销售状态 | sold_copies | BIGINT | | 售出份数 |
+| 销售状态 | real_sold_num | BIGINT | | 实际销售数量 |
+| 销售状态 | sold_end_time | TIMESTAMP | | 售卖结束时间 |
+| 销售状态 | finished_time | TIMESTAMP | | 结束时间 |
+| 销售状态 | release_time | STRING | | 发布时间(源是字符串)|
+| 销售状态 | start_time | TIMESTAMP | | 计划开售时间 |
+| 销售状态 | cycle | STRING | | 销售周期 |
+| 团生命周期 | group_full_time | TIMESTAMP | | 组齐时间 |
+| 团生命周期 | review_hold_time | TIMESTAMP | | 组队提交审核时间 |
+| 团生命周期 | review_approval_time | TIMESTAMP | | 组队审核通过时间 |
+| 团生命周期 | review_num | BIGINT | | 审核驳回次数 |
+| 团生命周期 | confirm_send_time | TIMESTAMP | | 确认发货日期 |
+| 团生命周期 | close_payment_time | TIMESTAMP | | 打款日期 |
+| 团生命周期 | close_payment_status | TINYINT | | 结算状态 |
+| 团生命周期 | group_sets_no | BIGINT | | 同商家同系列序号 |
+| 直播 | live_create_time | TIMESTAMP | | 直播创建时间 |
+| 直播 | live_start_time | TIMESTAMP | | 直播开播时间 |
+| 直播 | live_end_time | TIMESTAMP | | 直播结束时间 |
+| 报告 | report_start_time | TIMESTAMP | | 报告开始时间 |
+| 报告 | report_end_time | TIMESTAMP | | 报告结束时间 |
+| 报告 | report_review_num | BIGINT | | 报告审核次数 |
+| 报告 | report_review_first_time | TIMESTAMP | | 报告首次审核时间 |
+| 报告 | report_review_end_time | TIMESTAMP | | 报告末次审核时间 |
+| 营销 | act_id | BIGINT | | 关联活动 id |
+| 营销 | act_type | STRING | | 活动标签 |
+| 营销 | act_point_type | STRING | | 额外积分类型 |
+| 营销 | free_flag | TINYINT | | 免单标记 |
+| 营销 | exclusive | TINYINT | | 是否专属支付通道 |
+| 营销 | has_bg | TINYINT | | 是否有背景图 |
+| 营销 | team_first | TINYINT | | 包队优先玩法 |
+| 营销 | use_member_discount | TINYINT | | 会员折扣参与方式 |
+| 营销 | use_coupon | TINYINT | | 是否可用优惠券 |
+| 营销 | user_level | TINYINT | | 用户可看等级 |
+| 营销 | merchant_open | TINYINT | | 是否支持商家代开卡密 |
+| 营销 | merchant_sort | BIGINT | | 商家自定义排序 |
+| 营销 | custom | TINYINT | | 是否自定义 |
+| 营销 | gift_card_id | BIGINT | | 关联精美卡片 id |
+| 营销 | open_card | TINYINT | | 开卡动作 |
+| 营销 | goods_type | TINYINT | | 卡密类型 |
+| 积分 | point_rate | TINYINT | | 积分转换比例 |
+| 积分 | point_max | BIGINT | | 积分兑换最大值 |
+| 积分 | point_min | BIGINT | | 积分兑换最小值 |
+| 积分 | point_type | STRING | | 兑换积分类型 |
+| 营销支付 | payment_method | TINYINT | | 打款方式 |
+| 营销支付 | payment_total_price_cny | DECIMAL(20,4) | payment_total_price | 打款总金额 |
+| 营销支付 | payment_commission_cny | DECIMAL(20,4) | payment_commission | 佣金金额 |
+| 营销支付 | payment_finished_price_cny | DECIMAL(20,4) | payment_finished_price | 已打款金额 |
+| 营销支付 | payment_remain_price_cny | DECIMAL(20,4) | payment_remain_price | 剩余打款金额 |
+| 营销支付 | payment_online_price_cny | DECIMAL(20,4) | payment_online_price | 线上打款金额 |
+| 营销支付 | commission_rate | STRING | | 佣金比例(百分比)|
+| 业务标记 | hot_type | STRING | | 查询 type |
+| 业务标记 | report_flag | TINYINT | | 强制使用新版报告 |
+| 业务标记 | banner_end_time | TIMESTAMP | | banner 结束时间 |
+| 风控 | waring_type | STRING | | 风险异常类型 |
+| 风控 | compensation_status | TINYINT | | 赔付状态 |
+| 业务标记 | reviewmsg | STRING | | 审核描述 |
+| 业务标记 | review_account | STRING | | 审核账号 |
+| 业务标记 | lock | BOOLEAN | | 锁定状态 |
+| 业务标记 | marketing_info | STRING | | 营销信息 |
+| 业务标记 | msg | STRING | | 详情描述 |
+| 业务标记 | title | STRING | | 商品子标题 |
+| 业务标记 | remark | STRING | | 备注 |
+| 时间 | create_time | TIMESTAMP | | 创建时间 |
+| 时间 | last_update_time | TIMESTAMP | update_time | 最近更新时间 |
+| 时间 | del_time | TIMESTAMP | | 删除时间 |
+| 软删 | is_deleted | BOOLEAN | | 软删归一 |
+| 框架 | etl_time | TIMESTAMP | 派生 | ETL 处理时间 |
+| 分区 | dt | STRING | 控制 | T-1,`yyyyMMdd` |

+ 1 - 0
kb/92-重构进度.md

@@ -177,6 +177,7 @@
 | 2026-04-21 | **下线"阶段 3:业务 SQL 从零开发" + 取消 UDF 注释补齐 + kb/31 首批登记 13 个通用 UDF**:(a) 业务 SQL 从零开发属于新开发、不属于重构 scope:kb/92 总览表删阶段 3 行、阶段 3 整节删除、阶段 5 前置条件从"阶段 3 稳定"改为"新业务 SQL 稳定";kb/90 §〇 聚簇表删 E 行、DAG 图删 E 节点、关键依赖边 "A+B+C→E" 与 "E→F" 合并为 "新业务 SQL 生产稳定→F"、§八 聚簇 E 整节删除、当前推进建议"等待前置"里 E 行改为 F 行。(b) 通用 UDF 注释已由开发者手动补完(`spark_common_udf.py` 13 个 `@udf` 函数均带 `UDF-XX` 顺序编号 + 分节注释),kb/90 §2.12 删"5 段模板 + 5 批 commit"规划、"40 函数"更正为"13 个注册 UDF"、标题从"注释完整化 + 自查表"改为"自查表"。(c) `kb/31-UDF手册.md` §1 通用 UDF 表从空壳填入 13 行(UDF-01/02/21/22/23/31/32/33/41/42/51/52/53),分类按代码中分节注释(JSON / ARRAY / STRING / NUMERIC-DATE-HASH / CROSS-TYPE),函数编号按代码中 `UDF-XX` 注释;§2 业务 UDF 保持占位;非 `@udf` 普通 `def`(18 个辅助 / 工具函数)不登记 | — |
 | 2026-04-21 | **聚簇 B.1 `__init__.py` 瘦身(修剪式,不拆 `core/`)**:`dw_base/__init__.py` 从 127 行 → 83 行。三处删除:(a) `import findspark` + `findspark.init()` —— 查证 3 条事实后安全删:findspark 全仓仅此 2 处引用;入口全走 `python3 xxx.py`(非 `spark-submit`),`SPARK_HOME` 从未被代码注入,findspark 在 CDH 节点上 `which spark-submit → readlink -f` 反推出 parcel `$SPARK_HOME` 把 `$SPARK_HOME/python` 前插进 sys.path,但 pip pyspark 2.4.0 和 parcel pyspark 2.4.0 同版本,业务表现零差异(见里程碑 `datax+spark-smoke-2026-04-20` 冒烟链路,HMS 真正入口是 `SPARK_CONF_DIR=/etc/spark/conf/hive-site.xml`,与 findspark 无关);(b) 删 21 个外部零引用的颜色常量 —— `CHG_BOLD` / `NORM_BLU` / `NORM_WHT` / 7×`BOLD_*` / 7×`BGRD_*`(if/else 两分支同步删),保留实际被引用的 6 个(`DO_RESET` / `NORM_RED` / `NORM_GRN` / `NORM_YEL` / `NORM_MGT` / `NORM_CYN`);(c) 删 `IS_RUN_BY_NORMAL_USER` 状态变量(两处赋值外部无引用,仅内部 `elif` 分支走到时为 `True`,无消费者)。**不拆 `core/*` 的理由**:findspark 去掉后"懒加载"诉求大半消失,拆分需改 11 处调用点 import,ROI 低;py/sh 颜色双份是运行时分家的必然(跨 runtime 单源化要加 subprocess 解析,得不偿失),真冗余只是 py 侧定义超过实际被用的部分。联动:`requirements.txt:3` 删 `findspark==2.0.1`;`tests/README.md:26` findspark 段改写为 HMS 入口说明;`kb/00 §1` `__init__.py` 行注释去 findspark;`kb/90 §三` 改写为"已完成 · 修剪式"并附未拆 `core/` 的理由;`kb/90 §7.1` KEEP 行去 findspark + 末尾 TODO 行改写为"已删除" | — |
 | 2026-04-22 | **勘误:移除 "SQL SET 资源类参数不生效" 的错误表述**:A.4 落地时误把 "`SparkSession.conf.set()` 对已启动 session 不改变资源" 这条 Spark 固有行为类推到"SQL 里的 SET"。实际 `spark_sql.py:query()` L433-440 对 SQL 内 `SET spark.*` 做预扫描,在 session 启动前塞进 `_final_spark_config`,`__init_spark_session` 通过 `builder.config()` 写入后才 `getOrCreate()`——**资源类 SET 同样生效**。清理 4 处错误:`dw_base/spark/spark_sql.py:155` 注释、`conf/spark-tuning.conf` L6-7 注意段、`kb/90 §2.3` "落地坑"段 + L2 行括号、本文 L74 基于错误前提的验证项 | — |
+| 2026-05-09 | **kb/27-dwd建模.md + kb/28-dim建模.md 新建(用户标签 1 期建模落地)**:基于 tdm.md 标签清单(用户属性 7 个 + 16 品类 × 3 窗口 × 2 度量)倒推得 3 张表。kb/27 含 `dwd_trd_order_pay_apd_d`(订单支付明细,业务过程定义 / 粒度 / `payment_success_time` 业务时间分区 / 维度退化字段来源 / `accounts_payable_cny` 含 `point_type LIKE 'mer_act%'` 时除 100 的换算规则 / 字段表);kb/28 含 `dim_usr_user_ful_d`(base_user LEFT JOIN cert_info,性别/生日仅取 cert)与 `dim_trd_card_group_ful_d`(拼团维度,`sport` 内置脏数据清洗 mlb→MLB / Boxing→UFC / other→NULL,下游直引)。通用约定:DWD 单分区 `dt=T-1` 不回算(ODS 漂移已在 ODS 层归位);DIM 跑批初始化扫全量 + ROW_NUMBER 取最新行、日常增量"昨日 dim + 今日 ods"按 pk 合并去重;脏数据清洗位置统一放 DIM 层。**关键决策点**:1 期品类直取 `cgi.sport`(推翻早先"panini 是品类权威源"的草稿结论),不引产品表(panini / checklist / version_config 1 期不建对应 dim 表),业务依据是拼团可单品/组合品跨类,按拼团大类聚合贴近业务侧分析口径;C3 字段圈定 `id_card`(已 md5)/ `code` 纳入,`live_anonymous` / 通知三件套 / `live_config_json` 不纳入。**不入 kb 的**:1 期不实施的 `dwd_trd_order_refund_apd_d`(A3 锁不做退款扣减,2 期实施时再补 kb 章节)+ `dim_prd_checklist_ful_d`。设计稿留 `workspace/20260508/dwd_dim_draft.md`(含 1 期倒推链路 / refund 字段草稿 / 待办依赖等过程性内容,2 期实施时回查)。README §2x 数仓建模索引加 27 / 28 两行 | — |
 | 2026-04-22 | **仓库改名 `tendata-warehouse-release` → `poyee-data-warehouse` 收尾**:项目根目录由用户手动改名完成;代码侧 `dw_base/utils/file_utils.py:9` + `dw_base/utils/hdfs_merge_small_file.py:7` 两处 `re.sub(r"tendata-warehouse.*", ...)` 字面量同步更新。`.idea/*.iml` / `modules.xml` / `workspace.xml` 因 `.idea` + `*.iml` 在 `.gitignore`,属本地 IDE 状态,不入库亦不影响运行(老 `tendata-warehouse-release.iml` + modules.xml / workspace.xml 里的 module name 残留不处理)。联动 kb/90 §1.1 L88 表格行打勾 + §2.3 末尾"与仓库改名的联动"段压缩为一行记录 | — |
 | 2026-04-21 | **聚簇 A.4 Spark 参数外配 + `spark_sql.py` 三级覆盖**:按业务调整频率拆两文件入库 —— `conf/spark-defaults.conf`(12 条底层行为/开关类,初始化后少改:`spark.sql.adaptive/broadcastTimeout/codegen/arrow*/files/statistics.*` + `spark.dynamicAllocation.enabled` + `spark.files.ignoreCorruptFiles` + `spark.debug.maxToStringFields` + `spark.port.maxRetries` + `hive.exec.orc.default.block.size`)+ `conf/spark-tuning.conf`(10 条资源/并行度/队列,业务早期常改:`spark.{driver,executor}.{memory,cores}` + `spark.executor.instances` + `spark.executor.memoryOverhead` + `spark.driver.maxResultSize` + `spark.default.parallelism` + `spark.sql.shuffle.partitions` + `spark.yarn.queue`)。`dw_base/spark/spark_sql.py` 改造:(a) 模块级新增 `_load_spark_conf_file(path)`,读 Spark 原生 `key value` 格式,支持 `#` 注释与空行,文件缺失返回 `{}` 容错单测;(b) `__init__` 10 个 tuning 相关构造参数默认值 `'2g' / 200 / ...` → `Optional[...] = None` sentinel,不破坏既有调用点显式传参;(c) `__init_spark_session` 原 22 条硬编码 `.config(...)` 链替换为三段:L1 先 `spark-defaults.conf` 后 `spark-tuning.conf`(相同 key tuning 覆盖 defaults)→ L2 `self._final_spark_config`(SQL 内 SET)→ L3 构造参数非 None 项 + `extra_spark_config`(L3 内 extra 覆盖 named),保持原"extra > SQL SET > named" 的向后兼容;日志分层打 `L1/L2/L3` 前缀便于排查。联动:`kb/90 §2.2` conf 结构加 `spark-tuning.conf` + `§2.3` 改写为两文件模型(去单文件草案)+ 删"坑 2"(B1 → A2 依赖边)+ 聚簇 L59 依赖边删 | — |
 | 2026-04-22 | **datasource 扁平化 + db_type 按父目录段判定(方向反转)**:反转 2026-04-15 起立项的"一套代码跑多环境"设计(kb/90 原 §2.5:`-env` 参数 + `datasource/{db_type}/{env}/{instance}.ini` 分层 + env 注入)。实际前期跨环境同步是常态(test 业务库 → prod HDFS),"全局 env"概念不成立。新方案:(a) source ini 落位 `datasource/{db_type}/{env}-{实例简称}.ini`,env 写进文件名(env ∈ dev/test/prod),扁平组织;(b) sync ini 内 `dataSource = {db_type}/{env}-{实例简称}`(强制带 db_type 前缀;旧裸名 `hdfs-ha` 不再支持);(c) 代码侧 `dw_base/datax/plugins/plugin.py:37` + `plugin_factory.py:34` 的 db_type 提取从"文件名按 `-` 切首词"改为"按 `/` 切首段"(父目录名)—— 旧算法在新文件名出现 `-` 时会把 `env` 误判为 db_type,必须改。联动:kb/00 §1 目录树重绘(去 env 子目录,加样例 `prod-hobby.ini` / `test-hobby.ini` / `prod-ha.ini` 等 + sync ini 引用形式说明段)+ §6.1 配置分类表落位描述、kb/02 §4 同步、kb/21 §3.9 过时 3 行修正(废 `-env` 注入表述;引用形式 `{db_type}/{env}-{实例简称}`;JSON 输出路径去 `{env}/` 层)、kb/90 §2.1 硬编码表合并 3 行为 1 行 + §2.5 大幅压缩(三阶段设计整段删,保留路径解耦部分)+ §2.8 末尾表行更新 + §八 状态表合并、kb/92 L90 checklist 落位改扁平。conf/templates/datasource/\*.template.ini × 3 头注释补"落位"+"dataSource 引用"两行。`bin/datax-job-config-generator.py` L5/L114/L115 的路径注释讲的是另一个 `conf/datax/config/` 作业分组层级,与本次 datasource 扁平化无关,不动;`dw_base/datax/plugins/reader/mysql_reader.py:178` `{group}/mysql-{database}` 生成逻辑是非活跃代码(批量采集未启动),留到 §2.7 重构时对齐 | — |