在前后端开发联调前 的提交20260223

This commit is contained in:
Neo
2026-02-23 23:02:20 +08:00
parent 254ccb1e77
commit fafc95e64c
1142 changed files with 10366960 additions and 36957 deletions

View File

@@ -51,7 +51,7 @@ graph LR
| 文档 | 说明 |
|------|------|
| [BaseTask 公共机制](base_task_mechanism.md) | 任务基类模板方法、TaskContext、时间窗口、注册表、Flow 执行 |
| [ODS 层任务](ods_tasks.md) | 23 个通用 ODS 任务的架构、配置结构、API 端点、目标表 |
| [ODS 层任务](ods_tasks.md) | 22 个通用 ODS 任务的架构、配置结构、API 端点、目标表 |
| [DWD 层任务](dwd_tasks.md) | DWD_LOAD_FROM_ODS 核心装载、SCD2 处理、质量校验 |
| [DWS 层任务](dws_tasks.md) | 助教业绩、会员分析、财务统计、运维任务共 13 个 DWS 任务 |
| [INDEX 层任务](index_tasks.md) | WBI/NCI/RS 指数算法 + ML 手动台账导入 |
@@ -88,7 +88,6 @@ graph LR
| `ODS_TABLE_FEE_DISCOUNT` | `OdsTableDiscountTask` | `ods.table_fee_discount_records` | 台费折扣/调账 | [查看](ods_tasks.md) |
| `ODS_STORE_GOODS_SALES` | `OdsGoodsLedgerTask` | `ods.store_goods_sales_records` | 门店商品销售流水 | [查看](ods_tasks.md) |
| `ODS_TENANT_GOODS` | `OdsTenantGoodsTask` | `ods.tenant_goods_master` | 租户商品档案 | [查看](ods_tasks.md) |
| `ODS_SETTLEMENT_TICKET` | `OdsSettlementTicketTask` | `ods.settlement_ticket_details` | 结账小票详情 | [查看](ods_tasks.md) |
| `ODS_SETTLEMENT_RECORDS` | `OdsOrderSettleTask` | `ods.settlement_records` | 结账记录 | [查看](ods_tasks.md) |
### DWD 层(明细数据)
@@ -280,6 +279,7 @@ Flow执行流程定义了多层任务的执行顺序。通过 `--flow` 参
| `--idle-start` | str | — | 闲时窗口开始HH:MM |
| `--idle-end` | str | — | 闲时窗口结束HH:MM |
| `--allow-empty-advance` | flag | `false` | 允许空结果推进窗口 |
| `--force-full` | flag | `false` | 强制全量处理:跳过 ODS hash 去重和 DWD 变更对比,无条件写入 |
### 已弃用参数

View File

@@ -14,8 +14,8 @@
|------|------|----------|
| Task 1 | 新增 `SnapshotMode` 枚举(`FULL_SET` / `TIME_WINDOW` / `NONE` | `tasks/ods/ods_tasks.py` |
| Task 2 | content_hash 算法从 MD5 改为 SHA-256 | `tasks/ods/ods_tasks.py` |
| Task 3 | ODS DDL 补齐 `content_hash` 列 + `is_delete` 列 + `(pk, fetched_at DESC)` 索引 | `db/etl_feiqiu/schemas/ods.sql` |
| Task 4 | 迁移脚本:为已有 ODS 表添加 `latest_version` 索引 | `db/etl_feiqiu/migrations/2026-02-17__add_ods_latest_version_indexes.sql` |
| Task 3 | ODS DDL 补齐 `content_hash` 列 + `is_delete` 列 + `(pk, fetched_at DESC)` 索引 | `docs/database/ddl/etl_feiqiu__ods.sql`(原 `db/etl_feiqiu/schemas/ods.sql`,已归档) |
| Task 4 | 迁移脚本:为已有 ODS 表添加 `latest_version` 索引 | `db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-17__add_ods_latest_version_indexes.sql`(已归档) |
| Task 5 | 软删除重构:`_mark_missing_as_deleted` 改为 INSERT 删除版本行 | `tasks/ods/ods_tasks.py` |
| Task 6 | 属性测试覆盖去重和软删除逻辑 | `tests/unit/test_ods_dedup_properties.py` |
| Task 7-9 | 文档同步、集成验证 | 多文件 |

View File

@@ -1480,3 +1480,107 @@ recharge_order_flag = (consume_money = 0 AND pay_amount > 0)
- `refreshed`:刷新的物化视图数量
- `cleaned`:清理的历史数据行数
---
## 库存汇总域
库存汇总域包含 3 个任务,围绕商品库存的日度、周度、月度汇总展开。数据流向为:
```
dwd_goods_stock_summary ──┬──► DWS_GOODS_STOCK_DAILY日度汇总
├──► DWS_GOODS_STOCK_WEEKLY周度汇总
└──► DWS_GOODS_STOCK_MONTHLY月度汇总
```
三个任务均依赖 `DWD_LOAD_FROM_ODS` 完成后的 `dwd.dwd_goods_stock_summary` 数据。
---
### DWS_GOODS_STOCK_DAILY — 库存日度汇总
| 属性 | 值 |
|------|-----|
| 任务代码 | `DWS_GOODS_STOCK_DAILY` |
| Python 类 | `GoodsStockDailyTask``tasks/dws/goods_stock_daily_task.py` |
| 目标表 | `dws.dws_goods_stock_daily_summary` |
| 主键 | `site_id`, `stat_date`, `site_goods_id` |
| 粒度 | 日期 + 门店 + 商品 |
| 更新策略 | upsertON CONFLICT DO UPDATE |
| 更新频率 | 每日更新 |
| 依赖 | `DWD_LOAD_FROM_ODS` |
#### 数据来源
| 来源表 | Schema | 用途 |
|--------|--------|------|
| `dwd_goods_stock_summary` | `dwd` | 库存汇总明细(按 fetched_at 日期聚合) |
#### 核心业务逻辑
-`fetched_at` 的日期部分分组,同一天同一商品可能有多条 DWD 记录
- 数值指标(入库/出库/销售等)取 SUM 聚合
- `range_start_stock` 取当日第一条记录的值(期初快照)
- `range_end_stock` / `current_stock` 取当日最后一条记录的值(期末快照)
- `stat_period = 'daily'`
---
### DWS_GOODS_STOCK_WEEKLY — 库存周度汇总
| 属性 | 值 |
|------|-----|
| 任务代码 | `DWS_GOODS_STOCK_WEEKLY` |
| Python 类 | `GoodsStockWeeklyTask``tasks/dws/goods_stock_weekly_task.py` |
| 目标表 | `dws.dws_goods_stock_weekly_summary` |
| 主键 | `site_id`, `stat_date`, `site_goods_id` |
| 粒度 | ISO 周 + 门店 + 商品 |
| 更新策略 | upsertON CONFLICT DO UPDATE |
| 更新频率 | 每周更新 |
| 依赖 | `DWD_LOAD_FROM_ODS` |
#### 数据来源
| 来源表 | Schema | 用途 |
|--------|--------|------|
| `dwd_goods_stock_summary` | `dwd` | 库存汇总明细(按 ISO 周聚合) |
#### 核心业务逻辑
- 按 ISO 周分组isocalendar`stat_date` = 该周的周一日期
- 同一周同一商品可能有多条 DWD 记录
- 数值指标取 SUM 聚合
- `range_start_stock` 取该周第一条记录的值(期初快照)
- `range_end_stock` / `current_stock` 取该周最后一条记录的值(期末快照)
- `stat_period = 'weekly'`
---
### DWS_GOODS_STOCK_MONTHLY — 库存月度汇总
| 属性 | 值 |
|------|-----|
| 任务代码 | `DWS_GOODS_STOCK_MONTHLY` |
| Python 类 | `GoodsStockMonthlyTask``tasks/dws/goods_stock_monthly_task.py` |
| 目标表 | `dws.dws_goods_stock_monthly_summary` |
| 主键 | `site_id`, `stat_date`, `site_goods_id` |
| 粒度 | 自然月 + 门店 + 商品 |
| 更新策略 | upsertON CONFLICT DO UPDATE |
| 更新频率 | 每日更新当月数据 |
| 依赖 | `DWD_LOAD_FROM_ODS` |
#### 数据来源
| 来源表 | Schema | 用途 |
|--------|--------|------|
| `dwd_goods_stock_summary` | `dwd` | 库存汇总明细(按自然月聚合) |
#### 核心业务逻辑
- 按自然月分组,`stat_date` = 该月的第一天(如 2026-01-01 代表 2026 年 1 月)
- 同一月同一商品可能有多条 DWD 记录
- 数值指标取 SUM 聚合
- `range_start_stock` 取该月第一条记录的值(期初快照)
- `range_end_stock` / `current_stock` 取该月最后一条记录的值(期末快照)
- `stat_period = 'monthly'`

View File

@@ -751,5 +751,5 @@ ORDER BY effective_from DESC
| `compression_mode` | 1 | 压缩模式(默认 log1p |
| `use_smoothing` / `ewma_alpha` | 1 / 0.2 | EWMA 平滑 |
> 种子数据脚本:`database/seed_index_parameters.sql`
> DDL 定义:`database/schema_dws.sql`(第 21 节)
> 种子数据脚本:`db/etl_feiqiu/seeds/seed_index_parameters.sql`
> DDL 定义:`docs/database/ddl/etl_feiqiu__dws.sql`

View File

@@ -1,6 +1,6 @@
# ODS 任务参数矩阵
> 本文档列举所有 23 个 ODS 任务的关键配置参数,说明每个参数在 ETL 处理流程中的作用,
> 本文档列举所有 22 个 ODS 任务的关键配置参数,说明每个参数在 ETL 处理流程中的作用,
> 并以通俗语言概述飞球 ETL 的 API → ODS 现状。
>
> 数据来源:`tasks/ods/ods_tasks.py` 中的 `ODS_TASK_SPECS` 声明。
@@ -12,7 +12,7 @@
### 从哪抓
从上游飞球 SaaS 平台的 REST API 抓取,共对接 22 个不同的 API 端点(加上小票的特殊接口共 23 个)。覆盖台球门店的核心业务:订单结账、支付退款、会员档案与余额、助教服务与废除、商品库存、台桌、团购套餐、台费折扣等。每个端点对应一个 ODS 任务。
从上游飞球 SaaS 平台的 REST API 抓取,共对接 22 个不同的 API 端点。覆盖台球门店的核心业务:订单结账、支付退款、会员档案与余额、助教服务与废除、商品库存、台桌、团购套餐、台费折扣等。每个端点对应一个 ODS 任务。
### 怎么解析
@@ -20,11 +20,11 @@ API 返回的 JSON 响应通过两级路径定位数据:先按 `data_path`
### 写到哪
全部写入 PostgreSQL 的 `ods.*` schema对应实际的 `ods` schema23 张表一一对应 23 个任务。
全部写入 PostgreSQL 的 `ods.*` schema对应实际的 `ods` schema22 张表一一对应 22 个任务。
### 怎么去重
所有 23 个任务默认开启 `skip_unchanged=True`:基于原始 payload + is_delete 计算 content_hashSHA-256若与数据库中该业务 ID 最新版本的 hash 相同则跳过写入,避免无意义的版本膨胀。
所有 22 个任务默认开启 `skip_unchanged=True`:基于原始 payload + is_delete 计算 content_hashSHA-256若与数据库中该业务 ID 最新版本的 hash 相同则跳过写入,避免无意义的版本膨胀。
冲突处理模式默认是 `update`(全字段对比,有变化才更新),也支持 `backfill`(只回填 NULL 列)和 `nothing`(跳过已存在记录),通过运行时配置 `run.ods_conflict_mode` 控制。
@@ -34,7 +34,7 @@ API 返回的 JSON 响应通过两级路径定位数据:先按 `data_path`
- 全表快照5 个任务API 返回全量数据,本次没返回但数据库里有的记录插入一条 `is_delete=1` 的删除版本行。适用于维度表/档案表,数据量小。
- 窗口快照8 个任务):只在指定时间列的窗口范围内做软删除。适用于流水表,数据量大,只能按时间段比对。
- 无快照(10 个任务):纯增量写入,不做软删除。
- 无快照(9 个任务):纯增量写入,不做软删除。
下游 DWD 层取数规约:`DISTINCT ON (id) ORDER BY id, fetched_at DESC`,再过滤 `is_delete = 0`
@@ -96,12 +96,10 @@ API 返回的 JSON 响应通过两级路径定位数据:先按 `data_path`
| `ODS_STORE_GOODS` | ❌ | 默认 | ❌ | ✅ | ✅ | `FULL_TABLE` | — |
| `ODS_TABLE_FEE_DISCOUNT` | ❌ | 默认 | ❌ | ✅ | ✅ | `WINDOW` | `create_time` |
| `ODS_TENANT_GOODS` | ❌ | 默认 | ❌ | ✅ | ✅ | `FULL_TABLE` | — |
| `ODS_SETTLEMENT_TICKET` | ❌ | — | ✅ | ✅ | ✅ | `NONE` | — |
> - "默认" `time_fields` 表示 `(startTime, endTime)`
> - "—" 表示该参数为 `None` 或不适用
> - `skip_unchanged` 所有任务均为 `True`(默认值),基于 payload + is_delete 计算 content_hash
> - `ODS_SETTLEMENT_TICKET` 的 `time_fields` 为 `—` 是因为它不走标准分页抓取流程,而是先收集 `orderSettleId` 再逐个调用小票接口
> - `ODS_RECHARGE_SETTLE` 是唯一手动映射 60+ 列的任务(其余任务按 DB schema 自动匹配)
@@ -109,7 +107,7 @@ API 返回的 JSON 响应通过两级路径定位数据:先按 `data_path`
## 去重策略
所有 23 个任务统一使用 `skip_unchanged=True`(默认值):
所有 22 个任务统一使用 `skip_unchanged=True`(默认值):
- content_hash 基于原始 payload`json.dumps(sort_keys=True, separators=(',',':'), ensure_ascii=False)`+ `is_delete` 值计算 SHA-256
- 写入时与数据库中该业务 ID 最新版本的 content_hash 比对,相同则跳过
@@ -121,6 +119,6 @@ API 返回的 JSON 响应通过两级路径定位数据:先按 `data_path`
|------|:---:|----------|------|
| 全表快照 | `FULL_TABLE` | `ODS_ASSISTANT_ACCOUNT``ODS_MEMBER_CARD``ODS_GROUP_PACKAGE``ODS_STORE_GOODS``ODS_TENANT_GOODS`5 个) | API 返回全量,不在返回集中的记录插入一条 `is_delete=1` 的删除版本行 |
| 窗口快照 | `WINDOW` | `ODS_TABLE_USE``ODS_ASSISTANT_LEDGER``ODS_STORE_GOODS_SALES``ODS_REFUND``ODS_PLATFORM_COUPON``ODS_MEMBER_BALANCE``ODS_GROUP_BUY_REDEMPTION``ODS_TABLE_FEE_DISCOUNT`8 个) | 仅在 `snapshot_time_column` 指定的时间列窗口范围内做软删除 |
| 无快照 | `NONE` | 其余 10 个 | 纯增量写入,不做软删除 |
| 无快照 | `NONE` | 其余 9 个 | 纯增量写入,不做软删除 |
软删除语义INSERT 一条 `is_delete=1` 的新版本行(而非 UPDATE 历史版本),保持 ODS 追加写入的一致性。若最新版本已是 `is_delete=1` 则跳过(幂等)。

View File

@@ -40,7 +40,7 @@ ODS 层采用**声明式配置**驱动的通用任务模式:由 `BaseOdsTask`
| `ODS_STORE_GOODS` | `OdsStoreGoodsTask` | `/TenantGoods/GetGoodsInventoryList` | `store_goods_master` | 门店商品档案 |
| `ODS_TABLE_FEE_DISCOUNT` | `OdsTableDiscountTask` | `/Site/GetTaiFeeAdjustList` | `table_fee_discount_records` | 台费折扣/调账 |
| `ODS_TENANT_GOODS` | `OdsTenantGoodsTask` | `/TenantGoods/QueryTenantGoods` | `tenant_goods_master` | 租户商品档案 |
| `ODS_SETTLEMENT_TICKET` | `OdsSettlementTicketTask` | `/Order/GetOrderSettleTicketNew` | `settlement_ticket_details` | 结账小票详情 |
| `ODS_STAFF_INFO` | `OdsStaffInfoTask` | `/PersonnelManagement/SearchSystemStaffInfo` | `staff_info_master` | 员工档案(含在职/离职) |
> 所有目标表均位于 `ods` schema 下。
@@ -228,7 +228,7 @@ execute(cursor_data)
### content_hash 去重机制
`content_hash` 是通用 ODS 任务的核心去重手段,所有 23 个任务默认开启(`skip_unchanged=True`)。
`content_hash` 是通用 ODS 任务的核心去重手段,所有 22 个任务默认开启(`skip_unchanged=True`)。
#### 计算方式
@@ -295,8 +295,6 @@ ORDER BY id, fetched_at DESC;
| `ODS_STORE_GOODS` | 否 | `FULL_TABLE` | — | 门店商品档案 |
| `ODS_TABLE_FEE_DISCOUNT` | 否 | `WINDOW` | `create_time` | 台费折扣/调账 |
| `ODS_TENANT_GOODS` | 否 | `FULL_TABLE` | — | 租户商品档案 |
| `ODS_SETTLEMENT_TICKET` | 否 | `NONE` | — | 结账小票详情(专用实现,见下文) |
| `ODS_STAFF_INFO` | 否 | `FULL_TABLE` | — | 员工档案,全量快照 |
> 所有 23 个任务默认 `skip_unchanged=True`(去重开启)。
> **特殊任务**`ODS_SETTLEMENT_TICKET` 虽然在 `ODS_TASK_SPECS` 中声明,但其 `ODS_TASK_CLASSES` 条目被 `OdsSettlementTicketTask` 专用实现覆盖。该任务不走标准分页抓取流程,而是先从 `payment_transactions` 表或支付 API 收集 `orderSettleId`,再逐个调用小票接口获取详情。

View File

@@ -52,8 +52,11 @@ load()
| DDL 文件 | 创建的 Schema | 主要内容 |
|----------|--------------|----------|
| `database/schema_etl_admin.sql` | `meta` | `etl_task`(任务注册表)、`etl_cursor`(游标表)、`etl_run`(运行记录表) |
| `database/schema_ODS_doc.sql` | `ods` | 20+ 张 ODS 原始表member_profiles、settlement_records、payment_transactions 等) |
| meta DDL代码默认 `database/schema_etl_admin.sql` | `meta` | `etl_task`(任务注册表)、`etl_cursor`(游标表)、`etl_run`(运行记录表) |
| ODS DDL代码默认 `database/schema_ODS_doc.sql` | `ods` | 20+ 张 ODS 原始表member_profiles、settlement_records、payment_transactions 等) |
> 注:模块内 `database/` 目录下的旧 DDL 文件已不存在。INIT 任务通过配置参数 `schema.ods_file` / `schema.etl_admin_file` 指定 DDL 路径。
> 当前 DDL 基线统一维护在 `docs/database/ddl/`(如 `etl_feiqiu__ods.sql`、`etl_feiqiu__meta.sql`),使用时需通过配置参数指向正确路径。
### ODS DDL 清洗逻辑
@@ -75,8 +78,8 @@ ODS DDL 文件可能包含头部说明文本和 `COMMENT ON` 语句CamelCase
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `schema.ods_file` | `database/schema_ODS_doc.sql` | ODS DDL 文件路径 |
| `schema.etl_admin_file` | `database/schema_etl_admin.sql` | meta DDL 文件路径 |
| `schema.ods_file` | `database/schema_ODS_doc.sql`(⚠️ 旧路径,需配置为实际 DDL 位置) | ODS DDL 文件路径 |
| `schema.etl_admin_file` | `database/schema_etl_admin.sql`(⚠️ 旧路径) | meta DDL 文件路径 |
| `io.log_root` | — | 日志目录 |
| `io.export_root` | — | 导出目录 |
| `pipeline.fetch_root` | — | 抓取数据目录 |
@@ -115,7 +118,9 @@ load()
| DDL 文件 | 创建的 Schema | 主要内容 |
|----------|--------------|----------|
| `database/schema_dwd_doc.sql` | `dwd` | 维度表dim_*,含 SCD2 约束、事实表dwd_*、fact_*)、扩展表(*_ex |
| DWD DDL代码默认 `database/schema_dwd_doc.sql` | `dwd` | 维度表dim_*,含 SCD2 约束、事实表dwd_*、fact_*)、扩展表(*_ex |
> DDL 基线见 `docs/database/ddl/etl_feiqiu__dwd.sql`,使用时需通过 `schema.dwd_file` 配置参数指向正确路径。
DWD DDL 的特殊处理:
- 自动为含 `scd2_start_time` 列的表设置 SCD2 默认值(`scd2_start_time=now()``scd2_end_time='9999-12-31'``scd2_is_current=1``scd2_version=1`
@@ -126,7 +131,7 @@ DWD DDL 的特殊处理:
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `schema.dwd_file` | `database/schema_dwd_doc.sql` | DWD DDL 文件路径 |
| `schema.dwd_file` | `database/schema_dwd_doc.sql`(⚠️ 旧路径,需配置为实际 DDL 位置) | DWD DDL 文件路径 |
| `dwd.drop_schema_first` | `False` | 是否先 DROP 再重建(危险操作,会丢失所有 DWD 数据) |
### CLI 示例
@@ -166,7 +171,9 @@ load()
| DDL 文件 | 创建的 Schema | 主要内容 |
|----------|--------------|----------|
| `database/schema_dws.sql` | `dws` | 配置表5 张 cfg_*、助教域5 张、会员域2 张、财务域7 张、订单汇总1 张) |
| DWS DDL代码默认 `database/schema_dws.sql` | `dws` | 配置表5 张 cfg_*、助教域5 张、会员域2 张、财务域7 张、订单汇总1 张) |
> DDL 基线见 `docs/database/ddl/etl_feiqiu__dws.sql`,使用时需通过 `schema.dws_file` 配置参数指向正确路径。
DWS Schema 包含的配置表:
@@ -182,7 +189,7 @@ DWS Schema 包含的配置表:
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `schema.dws_file` | `database/schema_dws.sql` | DWS DDL 文件路径 |
| `schema.dws_file` | `database/schema_dws.sql`(⚠️ 旧路径,需配置为实际 DDL 位置) | DWS DDL 文件路径 |
| `dws.drop_schema_first` | `False` | 是否先 DROP 再重建(危险操作) |
### CLI 示例
@@ -231,7 +238,7 @@ load()
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `schema.seed_dws_file` | `database/seed_dws_config.sql` | 种子数据 SQL 文件路径 |
| `schema.seed_dws_file` | `database/seed_dws_config.sql`(⚠️ 旧路径,种子数据现位于 `db/etl_feiqiu/seeds/seed_dws_config.sql` | 种子数据 SQL 文件路径 |
### CLI 示例
@@ -290,7 +297,6 @@ execute()
| `platform_coupon_redemption_records` | `ods.platform_coupon_redemption_records` |
| `group_buy_redemption_records` | `ods.group_buy_redemption_records` |
| `group_buy_packages` | `ods.group_buy_packages` |
| `settlement_ticket_details` | `ods.settlement_ticket_details` |
| `store_goods_master` | `ods.store_goods_master` |
| `tenant_goods_master` | `ods.tenant_goods_master` |
| `store_goods_sales_records` | `ods.store_goods_sales_records` |