init: 项目初始提交 - NeoZQYY Monorepo 完整代码

This commit is contained in:
Neo
2026-02-15 14:58:14 +08:00
commit ded6dfb9d8
769 changed files with 182616 additions and 0 deletions

View File

@@ -0,0 +1,591 @@
# 工具类任务详解
> 本文档说明飞球 ETL 系统中所有工具类Utility和校验类Verification任务。
> 这些任务不属于 ODS/DWD/DWS/INDEX 四层业务管线,而是为系统初始化、
> 数据灌入、归档、截止时间检查和完整性校验等运维场景服务。
---
## 概述
工具类任务共 8 个(含 1 个校验类任务),注册于 `orchestration/task_registry.py`
| 任务代码 | Python 类 | 用途 | task_type | requires_db_config |
|----------|-----------|------|-----------|-------------------|
| `INIT_ODS_SCHEMA` | `InitOdsSchemaTask` | 执行 ODS + etl_admin DDL创建必要目录 | utility | `False` |
| `INIT_DWD_SCHEMA` | `InitDwdSchemaTask` | 执行 DWD DDL | utility | `False` |
| `INIT_DWS_SCHEMA` | `InitDwsSchemaTask` | 执行 DWS DDL | utility | `False` |
| `MANUAL_INGEST` | `ManualIngestTask` | 从本地 JSON 文件手动入库到 ODS | utility | `False` |
| `ODS_JSON_ARCHIVE` | `OdsJsonArchiveTask` | 在线抓取 ODS 接口数据并落盘 JSON | utility | `False` |
| `CHECK_CUTOFF` | `CheckCutoffTask` | 检查各任务/表的数据截止时间 | utility | `False` |
| `SEED_DWS_CONFIG` | `SeedDwsConfigTask` | 初始化 DWS 配置种子数据 | utility | `True`(默认) |
| `DATA_INTEGRITY_CHECK` | `DataIntegrityTask` | API → ODS → DWD 数据完整性校验 | verification | `False` |
> 典型执行顺序(首次部署):`INIT_ODS_SCHEMA` → `INIT_DWD_SCHEMA` → `INIT_DWS_SCHEMA` → `SEED_DWS_CONFIG`
---
## 1. INIT_ODS_SCHEMA — ODS + etl_admin Schema 初始化
| 属性 | 值 |
|------|-----|
| 任务代码 | `INIT_ODS_SCHEMA` |
| Python 类 | `tasks.utility.init_schema_task.InitOdsSchemaTask` |
| 继承 | `BaseTask` |
| 用途 | 创建 ODS 层和 etl_admin 调度元数据的数据库结构,并准备运行时目录 |
### 执行流程
```
extract()
├── 读取 DDL 文件路径schema_ODS_doc.sql、schema_etl_admin.sql
├── 收集需创建的目录列表
└── 返回 SQL 文本 + 目录列表
load()
├── 创建必要目录log_root、export_root、fetch_root、ingest_dir
├── 执行 etl_admin DDLschema_etl_admin.sql
└── 执行 ODS DDLschema_ODS_doc.sql清洗后
```
### 执行的 DDL 文件
| DDL 文件 | 创建的 Schema | 主要内容 |
|----------|--------------|----------|
| `database/schema_etl_admin.sql` | `etl_admin` | `etl_task`(任务注册表)、`etl_cursor`(游标表)、`etl_run`(运行记录表) |
| `database/schema_ODS_doc.sql` | `billiards_ods` | 20+ 张 ODS 原始表member_profiles、settlement_records、payment_transactions 等) |
### ODS DDL 清洗逻辑
ODS DDL 文件可能包含头部说明文本和 `COMMENT ON` 语句CamelCase 未加引号会导致执行失败),因此 `load()` 阶段会做轻量清洗:
1. 定位第一个 `DROP SCHEMA` 语句,丢弃之前的非 SQL 文本
2. 逐行过滤掉以 `COMMENT ON` 开头的行
### 创建的目录
| 配置路径 | 说明 |
|----------|------|
| `io.log_root` | 日志输出根目录 |
| `io.export_root` | 数据导出根目录 |
| `pipeline.fetch_root` | API 抓取数据落盘目录 |
| `pipeline.ingest_source_dir` | 手动入库数据源目录(默认同 fetch_root |
### 配置参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `schema.ods_file` | `database/schema_ODS_doc.sql` | ODS DDL 文件路径 |
| `schema.etl_admin_file` | `database/schema_etl_admin.sql` | etl_admin DDL 文件路径 |
| `io.log_root` | — | 日志目录 |
| `io.export_root` | — | 导出目录 |
| `pipeline.fetch_root` | — | 抓取数据目录 |
| `pipeline.ingest_source_dir` | 同 fetch_root | 入库数据源目录 |
### CLI 示例
```bash
python -m cli.main --tasks INIT_ODS_SCHEMA --pg-dsn "$PG_DSN"
```
---
## 2. INIT_DWD_SCHEMA — DWD Schema 初始化
| 属性 | 值 |
|------|-----|
| 任务代码 | `INIT_DWD_SCHEMA` |
| Python 类 | `tasks.utility.init_dwd_schema_task.InitDwdSchemaTask` |
| 继承 | `BaseTask` |
| 用途 | 创建 DWD 明细数据层的数据库结构 |
### 执行流程
```
extract()
├── 读取 DDL 文件路径schema_dwd_doc.sql
└── 读取 drop_first 配置
load()
├── [可选] DROP SCHEMA billiards_dwd CASCADE
└── 执行 DWD DDLschema_dwd_doc.sql
```
### 执行的 DDL 文件
| DDL 文件 | 创建的 Schema | 主要内容 |
|----------|--------------|----------|
| `database/schema_dwd_doc.sql` | `billiards_dwd` | 维度表dim_*,含 SCD2 约束、事实表dwd_*、fact_*)、扩展表(*_ex |
DWD DDL 的特殊处理:
- 自动为含 `scd2_start_time` 列的表设置 SCD2 默认值(`scd2_start_time=now()``scd2_end_time='9999-12-31'``scd2_is_current=1``scd2_version=1`
- 自动创建 SCD2 排他约束(`EXCLUDE USING gist`,防止同一业务主键的生效区间重叠)
- 自动创建当前版本唯一索引(`WHERE scd2_is_current = 1`
### 配置参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `schema.dwd_file` | `database/schema_dwd_doc.sql` | DWD DDL 文件路径 |
| `dwd.drop_schema_first` | `False` | 是否先 DROP 再重建(危险操作,会丢失所有 DWD 数据) |
### CLI 示例
```bash
# 常规初始化
python -m cli.main --tasks INIT_DWD_SCHEMA --pg-dsn "$PG_DSN"
# 重建(先删后建,慎用)
python -m cli.main --tasks INIT_DWD_SCHEMA --pg-dsn "$PG_DSN" --extra dwd.drop_schema_first=true
```
---
## 3. INIT_DWS_SCHEMA — DWS Schema 初始化
| 属性 | 值 |
|------|-----|
| 任务代码 | `INIT_DWS_SCHEMA` |
| Python 类 | `tasks.utility.init_dws_schema_task.InitDwsSchemaTask` |
| 继承 | `BaseTask` |
| 用途 | 创建 DWS 数据服务层的数据库结构 |
### 执行流程
```
extract()
├── 读取 DDL 文件路径schema_dws.sql
└── 读取 drop_first 配置
load()
├── [可选] DROP SCHEMA billiards_dws CASCADE
└── 执行 DWS DDLschema_dws.sql
```
### 执行的 DDL 文件
| DDL 文件 | 创建的 Schema | 主要内容 |
|----------|--------------|----------|
| `database/schema_dws.sql` | `billiards_dws` | 配置表5 张 cfg_*、助教域5 张、会员域2 张、财务域7 张、订单汇总1 张) |
DWS Schema 包含的配置表:
| 配置表 | 说明 |
|--------|------|
| `cfg_performance_tier` | 绩效档位配置(阈值、抽成比例、假期天数) |
| `cfg_assistant_level_price` | 助教等级定价 |
| `cfg_bonus_rules` | 奖金规则配置 |
| `cfg_area_category` | 台区分类映射 |
| `cfg_skill_type` | 技能课程类型映射 |
### 配置参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `schema.dws_file` | `database/schema_dws.sql` | DWS DDL 文件路径 |
| `dws.drop_schema_first` | `False` | 是否先 DROP 再重建(危险操作) |
### CLI 示例
```bash
python -m cli.main --tasks INIT_DWS_SCHEMA --pg-dsn "$PG_DSN"
```
---
## 4. SEED_DWS_CONFIG — DWS 配置种子数据初始化
| 属性 | 值 |
|------|-----|
| 任务代码 | `SEED_DWS_CONFIG` |
| Python 类 | `tasks.utility.seed_dws_config_task.SeedDwsConfigTask` |
| 继承 | `BaseTask` |
| 用途 | 向 DWS 配置表插入初始数据(绩效档位、等级定价、奖金规则等) |
### 前置条件
- `billiards_dws` schema 已创建(需先执行 `INIT_DWS_SCHEMA`
- 配置表(`cfg_*`)已存在
### 执行流程
```
extract()
└── 读取 seed_dws_config.sql 文件内容
load()
└── 执行 SQLTRUNCATE + INSERT 配置数据)
```
### 执行的种子文件
| 文件 | 目标表 | 说明 |
|------|--------|------|
| `database/seed_dws_config.sql` | `cfg_performance_tier` | 绩效档位(含历史口径:旧方案至 2026-02-28新方案 2026-03-01 起) |
| | `cfg_assistant_level_price` | 助教等级定价 |
| | `cfg_bonus_rules` | 奖金规则 |
| | `cfg_area_category` | 台区分类映射 |
| | `cfg_skill_type` | 技能课程类型映射 |
### 配置参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `schema.seed_dws_file` | `database/seed_dws_config.sql` | 种子数据 SQL 文件路径 |
### CLI 示例
```bash
# 通常与 INIT_DWS_SCHEMA 一起执行
python -m cli.main --tasks INIT_DWS_SCHEMA,SEED_DWS_CONFIG --pg-dsn "$PG_DSN"
```
---
## 5. MANUAL_INGEST — 手动 JSON 入库
| 属性 | 值 |
|------|-----|
| 任务代码 | `MANUAL_INGEST` |
| Python 类 | `tasks.utility.manual_ingest_task.ManualIngestTask` |
| 继承 | `BaseTask` |
| 用途 | 从本地 JSON 文件批量灌入 ODS 表,用于离线回放或示例数据导入 |
### 执行流程概览
```
execute()
├── 确定数据目录manual.data_dir / pipeline.ingest_source_dir / tests/testdata_json
├── 遍历目录下所有 .json 文件(按文件名排序)
│ ├── [可选] 按 include_files 过滤
│ ├── 读取并解析 JSON
│ ├── 提取记录列表(兼容多层 data/list 包装)
│ ├── 按文件名关键字匹配目标 ODS 表
│ └── 批量入库INSERT ON CONFLICT
└── 返回统计计数fetched/inserted/updated/skipped/errors
```
### 文件匹配规则
`MANUAL_INGEST` 通过 `FILE_MAPPING` 将文件名关键字映射到目标 ODS 表。匹配逻辑:**文件名中包含关键字即匹配**(大小写敏感)。
| 文件名关键字 | 目标 ODS 表 |
|-------------|------------|
| `member_profiles` | `billiards_ods.member_profiles` |
| `member_balance_changes` | `billiards_ods.member_balance_changes` |
| `member_stored_value_cards` | `billiards_ods.member_stored_value_cards` |
| `recharge_settlements` | `billiards_ods.recharge_settlements` |
| `settlement_records` | `billiards_ods.settlement_records` |
| `assistant_cancellation_records` | `billiards_ods.assistant_cancellation_records` |
| `assistant_accounts_master` | `billiards_ods.assistant_accounts_master` |
| `assistant_service_records` | `billiards_ods.assistant_service_records` |
| `site_tables_master` | `billiards_ods.site_tables_master` |
| `table_fee_discount_records` | `billiards_ods.table_fee_discount_records` |
| `table_fee_transactions` | `billiards_ods.table_fee_transactions` |
| `goods_stock_movements` | `billiards_ods.goods_stock_movements` |
| `stock_goods_category_tree` | `billiards_ods.stock_goods_category_tree` |
| `goods_stock_summary` | `billiards_ods.goods_stock_summary` |
| `payment_transactions` | `billiards_ods.payment_transactions` |
| `refund_transactions` | `billiards_ods.refund_transactions` |
| `platform_coupon_redemption_records` | `billiards_ods.platform_coupon_redemption_records` |
| `group_buy_redemption_records` | `billiards_ods.group_buy_redemption_records` |
| `group_buy_packages` | `billiards_ods.group_buy_packages` |
| `settlement_ticket_details` | `billiards_ods.settlement_ticket_details` |
| `store_goods_master` | `billiards_ods.store_goods_master` |
| `tenant_goods_master` | `billiards_ods.tenant_goods_master` |
| `store_goods_sales_records` | `billiards_ods.store_goods_sales_records` |
### JSON 解析逻辑
`_extract_records()` 方法兼容多种 JSON 包装格式:
1. **顶层数组**`[{...}, {...}]` → 直接作为记录列表
2. **data 包装**`{"data": [...]}``{"code": 0, "data": [...]}` → 展开 `data` 字段
3. **嵌套 list**`{"data": {"someKey": [{...}]}}` → 自动查找第一个 list 类型的值
4. **settleList 特殊处理**:充值/结算记录的 `data.settleList` 结构会被展开,内层 `settleList` 提取为独立记录,并保留外层 `siteProfile` 供字段补充
### 入库流程
对每张目标表,入库过程如下:
1. **查询表结构**:通过 `information_schema.columns` 获取目标表的列名、数据类型
2. **构建 SQL**:生成 `INSERT INTO ... VALUES %s ON CONFLICT ...` 语句
-`content_hash` 列:`ON CONFLICT (pk, content_hash) DO NOTHING`(内容去重)
-`content_hash` 列:`ON CONFLICT (pk) DO UPDATE SET ...`upsert 覆盖)
3. **值映射**:逐列匹配 JSON 字段(忽略大小写),特殊列处理:
- `payload`:存储原始 JSON 记录
- `source_file`:填入文件名
- `fetched_at`:取记录中的值或当前时间
- `content_hash`:基于记录内容计算 SHA-256排除 `fetched_at``payload` 等 ETL 元数据字段)
- JSON 类型列:自动包装为 `psycopg2.extras.Json`
- 整数/浮点/时间戳列:自动类型转换
4. **批量执行**:使用 `psycopg2.extras.execute_values` 分批提交(默认 chunk_size=50最大 500
5. **降级处理**:批量执行失败时,降级为逐行 + `SAVEPOINT` 模式,跳过异常行继续处理
6. **事务粒度**:每个文件一次 `commit`,避免长事务
### 特殊处理
- **充值/结算记录**`recharge_settlements``settlement_records`):自动从 `siteProfile` 补齐 `tenantid``siteid``sitename`
- **空值规范化**:空字符串 `""`、空 JSON `"{}"` / `"[]"` 统一转为 `None`
- **主键校验**:主键值为 `None` 或空字符串的记录直接跳过
### 配置参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `manual.data_dir` | — | JSON 数据文件目录(优先级最高) |
| `pipeline.ingest_source_dir` | — | 入库数据源目录(次优先) |
| — | `tests/testdata_json` | 兜底默认目录 |
| `manual.include_files` | `[]`(全部) | 限定处理的文件名列表(不含扩展名,小写匹配) |
| `manual.execute_values_page_size` | `50` | 批量插入每批行数1-500 |
### CLI 示例
```bash
# 从默认目录灌入所有 JSON
python -m cli.main --tasks MANUAL_INGEST --pg-dsn "$PG_DSN"
# 指定数据目录
python -m cli.main --tasks MANUAL_INGEST --pg-dsn "$PG_DSN" \
--extra manual.data_dir=/path/to/json_files
# 只灌入指定文件
python -m cli.main --tasks MANUAL_INGEST --pg-dsn "$PG_DSN" \
--extra manual.include_files=member_profiles,settlement_records
```
---
## 6. ODS_JSON_ARCHIVE — ODS 接口数据归档
| 属性 | 值 |
|------|-----|
| 任务代码 | `ODS_JSON_ARCHIVE` |
| Python 类 | `tasks.ods.ods_json_archive_task.OdsJsonArchiveTask` |
| 继承 | `BaseTask` |
| 用途 | 在线抓取所有 ODS 相关 API 接口数据,落盘为简化 JSON 文件,供后续离线回放/入库 |
> 注意:虽然注册为 `task_type="utility"`,但该任务的源文件位于 `tasks/ods/` 目录下,因为它本质上是 ODS 数据的抓取归档。
### 归档策略
- **输出格式**:每页一个 JSON 文件,格式为 `{"code": 0, "data": [...records...]}`,与 `MANUAL_INGEST` 的解析逻辑兼容
- **文件命名**`{endpoint_stem}__p{page_no:04d}.json`(如 `GetAllOrderSettleList__p0001.json`
- **小票文件**:按 `orderSettleId` 分文件写入(`GetOrderSettleTicketNew__{orderSettleId}.json`
- **清单文件**:抓取完成后生成 `manifest.json`,记录窗口、端点、记录数等元信息
### 抓取的 API 端点
任务内置 22 个端点配置(`ENDPOINTS`),按窗口参数风格分类:
| 窗口风格 | 参数 | 端点示例 |
|----------|------|----------|
| `site` | `siteId` | `/MemberProfile/GetTenantMemberList``/Table/GetSiteTables` 等 |
| `start_end` | `siteId` + `startTime` / `endTime` | `/MemberProfile/GetMemberCardBalanceChange``/TenantGoods/GetGoodsSalesList` 等 |
| `range` | `siteId` + `rangeStartTime` / `rangeEndTime` | `/Site/GetAllOrderSettleList``/Site/GetRechargeSettleList` |
| `pay` | `siteId` + `StartPayTime` / `EndPayTime` | `/PayLog/GetPayLogListPage` |
此外,还有一个特殊端点 `/Order/GetOrderSettleTicketNew`(小票详情),按支付日志中提取的 `orderSettleId` 逐单抓取。
### 执行流程
```
extract()
├── 验证 API 客户端类型(必须为 APIClient即在线模式
├── 确定输出目录api.output_dir / pipeline.fetch_root
├── 遍历 ENDPOINTS逐端点分页抓取
│ ├── 构建请求参数(按 window_style 选择参数格式)
│ ├── 调用 iter_paginated() 分页获取
│ ├── 每页落盘为独立 JSON 文件
│ └── 从支付日志中收集 orderSettleId用于小票抓取
├── 按 orderSettleId 逐单抓取小票详情
└── 生成 manifest.json 清单文件
```
### 配置参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `pipeline.fetch_root` | — | JSON 文件输出目录 |
| `api.page_size` | `200` | API 分页大小 |
| `io.write_pretty_json` | `False` | 是否格式化输出 JSON |
### CLI 示例
```bash
# 在线抓取并归档
python -m cli.main --tasks ODS_JSON_ARCHIVE --pg-dsn "$PG_DSN" \
--store-id "$STORE_ID" --api-token "$API_TOKEN"
```
---
## 7. CHECK_CUTOFF — 数据截止时间检查
| 属性 | 值 |
|------|-----|
| 任务代码 | `CHECK_CUTOFF` |
| Python 类 | `tasks.utility.check_cutoff_task.CheckCutoffTask` |
| 继承 | `BaseTask` |
| 用途 | 报告各任务的游标截止时间和各层数据表的最新时间戳,用于运维监控 |
### 执行流程
该任务不走标准的 extract → transform → load 流程,而是直接在 `execute()` 中完成所有逻辑:
```
execute()
├── 1. 查询 etl_admin 游标截止时间
│ ├── 关联 etl_task + etl_cursor 表
│ ├── 筛选当前门店已启用的任务
│ ├── [可选] 按 task_codes 过滤
│ └── 计算总体截止时间(排除 INIT_* 任务的最小 last_end
├── 2. 探测 ODS 表抓取时间
│ ├── 遍历 DwdLoadTask.TABLE_MAP 中的 ODS 表
│ ├── 查询每张表的 MAX(fetched_at) 和 COUNT(*)
│ └── 计算 ODS 截止时间(最小 max_fetched_at
└── 3. 探测 DWD/DWS 关键时间列
├── DWD: max(pay_time) from dwd_settlement_head / dwd_payment / dwd_refund
└── DWS: max(order_date) / max(updated_at) from dws_order_summary
```
### 校验逻辑
- **游标截止时间**:从 `etl_admin.etl_cursor.last_end` 获取每个任务的最后成功窗口结束时间,排除 `INIT_*` 任务后取最小值作为总体截止时间
- **ODS 抓取时间**:查询每张 ODS 表的 `MAX(fetched_at)`,取最小值作为 ODS 层截止时间
- **DWD/DWS 业务时间**:探测关键业务时间列(`pay_time``order_date``updated_at`),反映数据实际覆盖范围
### 输出
任务通过日志输出检查结果,同时在返回值的 `report` 字段中包含结构化数据:
```python
{
"rows": [...], # 每个任务的游标信息
"overall_cutoff": datetime, # 总体截止时间
"ods_fetched_at": {...}, # 每张 ODS 表的 max_fetched_at
"dw_max_times": {...}, # DWD/DWS 关键时间列
}
```
### 配置参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `app.store_id` | — | 门店 ID必填 |
| `run.cutoff_task_codes` | `None`(全部) | 逗号分隔的任务代码列表,限定检查范围 |
### CLI 示例
```bash
# 检查所有任务的截止时间
python -m cli.main --tasks CHECK_CUTOFF --pg-dsn "$PG_DSN" --store-id "$STORE_ID"
# 只检查指定任务
python -m cli.main --tasks CHECK_CUTOFF --pg-dsn "$PG_DSN" --store-id "$STORE_ID" \
--extra run.cutoff_task_codes=ORDERS,PAYMENTS,MEMBERS
```
---
## 8. DATA_INTEGRITY_CHECK — 数据完整性校验
| 属性 | 值 |
|------|-----|
| 任务代码 | `DATA_INTEGRITY_CHECK` |
| Python 类 | `tasks.utility.data_integrity_task.DataIntegrityTask` |
| 继承 | `BaseTask` |
| 注册 task_type | `verification`(非 utility但在本文档中一并说明 |
| 用途 | 检查 API → ODS → DWD 全链路数据完整性,支持自动回填缺失数据 |
### 两种运行模式
#### 1. 历史模式(`history`,默认)
从指定起始日期到结束日期,按月分段检查全量历史数据的完整性。
```
execute() [mode=history]
├── 解析 history_start / history_end 时间范围
├── 调用 run_history_flow()
│ ├── 按月分段执行完整性检查
│ ├── 对比 API 记录数 vs ODS 记录数
│ ├── [可选] 对比内容一致性content_hash
│ └── [可选] 自动回填缺失数据
└── 生成 JSON 报表
```
#### 2. 窗口模式(`window`
检查指定时间窗口内的数据完整性,当提供 CLI 窗口覆盖参数时自动切换到此模式。
```
execute() [mode=window]
├── 获取时间窗口(支持 CLI 覆盖)
├── 构建窗口分段build_window_segments
├── 调用 run_window_flow()
│ ├── 逐段执行完整性检查
│ ├── 汇总缺失/不一致/错误计数
│ └── [可选] 自动回填 + 复查
└── 生成 JSON 报表
```
### 校验逻辑
核心校验由 `quality/integrity_service.py``quality/integrity_checker.py` 实现:
1. **记录数对比**API 返回的记录数 vs ODS 表中的记录数
2. **内容一致性**(可选):抽样对比 API 记录与 ODS 记录的 `content_hash`
3. **缺失检测**:识别 API 中存在但 ODS 中缺失的记录
4. **不一致检测**:识别 API 与 ODS 中内容不匹配的记录
### 自动回填
`auto_backfill=True` 时,检测到缺失或不一致数据后会自动触发回填:
1. 调用 `scripts/repair/backfill_missing_data.run_backfill()` 重新抓取缺失数据
2. 回填完成后可选复查(`recheck_after_backfill`),验证回填效果
### 配置参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `integrity.mode` | `history` | 运行模式:`history`(历史全量)/ `window`(时间窗口) |
| `integrity.history_start` | `2025-07-01` | 历史模式起始日期 |
| `integrity.history_end` | —(当前时间) | 历史模式结束日期 |
| `integrity.include_dimensions` | `False` | 是否包含维度表检查 |
| `integrity.ods_task_codes` | —(全部) | 限定检查的 ODS 任务代码 |
| `integrity.auto_backfill` | `False` | 是否自动回填缺失数据 |
| `integrity.compare_content` | `True` | 是否对比内容一致性 |
| `integrity.content_sample_limit` | — | 内容对比抽样上限 |
| `integrity.backfill_mismatch` | `True` | 是否回填不一致数据(仅 auto_backfill 时生效) |
| `integrity.recheck_after_backfill` | `True` | 回填后是否复查 |
| `integrity.force_monthly_split` | `True` | 是否强制按月分段 |
| `run.window_override.start` | — | CLI 窗口覆盖起始时间(触发 window 模式) |
| `run.window_override.end` | — | CLI 窗口覆盖结束时间 |
### 输出报表
检查结果以 JSON 格式写入 `reports/` 目录:
- 历史模式:`reports/data_integrity_history_{timestamp}.json`
- 窗口模式:`reports/data_integrity_window_{timestamp}.json`
### CLI 示例
```bash
# 历史全量检查(默认从 2025-07-01 至今)
python -m cli.main --tasks DATA_INTEGRITY_CHECK --pg-dsn "$PG_DSN" \
--store-id "$STORE_ID" --api-token "$API_TOKEN"
# 指定时间范围
python -m cli.main --tasks DATA_INTEGRITY_CHECK --pg-dsn "$PG_DSN" \
--store-id "$STORE_ID" --api-token "$API_TOKEN" \
--extra integrity.history_start=2026-01-01 --extra integrity.history_end=2026-02-01
# 窗口模式 + 自动回填
python -m cli.main --tasks DATA_INTEGRITY_CHECK --pg-dsn "$PG_DSN" \
--store-id "$STORE_ID" --api-token "$API_TOKEN" \
--window-start "2026-02-01" --window-end "2026-02-15" \
--extra integrity.auto_backfill=true
```