初始提交:飞球 ETL 系统全量代码

This commit is contained in:
Neo
2026-02-13 08:05:34 +08:00
commit 3c51f5485d
441 changed files with 117631 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
# 单元测试清单280 passed / 1 skipped
> 最后更新2026-02-12基于 `pytest tests/unit -v` 输出。
## 概览
| 分类 | 测试文件 | 测试数 | 说明 |
|------|---------|--------|------|
| ETL 任务(在线) | `test_etl_tasks_online.py` | 14 | FakeAPI 模拟在线抓取,验证 14 个 ODS 任务 E/T/L |
| ETL 任务(离线) | `test_etl_tasks_offline.py` | 14 | 本地 JSON 回放,验证离线入库链路 |
| ETL 任务(分阶段) | `test_etl_tasks_stages.py` | 42 | 14 个任务 × 3 阶段Extract/Transform/Load |
| ODS 通用任务 | `test_ods_tasks.py` | ~20+ | ODS 通用加载器任务测试 |
| 解析器 | `test_parsers.py` | ~10+ | 数据类型解析(日期/金额/枚举) |
| 配置管理 | `test_config.py` | ~10+ | AppConfig 加载、点号路径、分层覆盖 |
| 接口路由 | `test_endpoint_routing.py` | ~5+ | 近期/历史接口路由规则 |
| 报告工具 | `test_reporting.py` | ~5+ | 汇总格式化工具 |
| 审计扫描 | `test_audit_*.py`6 个文件) | ~40+ | 仓库审计:文件清单、流程树、文档对齐、报告属性 |
| 关系指数 | `test_relation_index_base.py` | ~5+ | RS/OS/MS/ML 指数基础逻辑 |
| **调度器重构(新增)** | 见下方 | **51** | TaskRegistry / TaskExecutor / PipelineRunner / CLI / E2E |
## 调度器重构新增测试51 个)
### `test_task_registry.py` — TaskRegistry 单元测试16 个)
| 测试类 | 测试方法 | 验证内容 |
|--------|---------|---------|
| `TestRegisterAndMetadata` | `test_register_with_defaults` | 仅传 task_code + task_class 时使用默认元数据 |
| | `test_register_with_full_metadata` | 完整元数据注册layer/task_type |
| | `test_register_utility_task` | 工具类任务 requires_db_config=False |
| | `test_case_insensitive_lookup` | task_code 大小写不敏感 |
| | `test_get_metadata_unknown_returns_none` | 未注册任务返回 None |
| `TestCreateTask` | `test_create_task_returns_instance` | 创建任务实例(接口不变) |
| | `test_create_task_unknown_raises` | 未知任务抛 ValueError |
| `TestGetTasksByLayer` | `test_returns_matching_tasks` | 按层查询返回匹配任务 |
| | `test_case_insensitive_layer` | 层名大小写不敏感 |
| | `test_no_match_returns_empty` | 无匹配返回空列表 |
| | `test_none_layer_excluded` | layer=None 不被任何层查询返回 |
| `TestIsUtilityTask` | `test_utility_task` | requires_db_config=False → True |
| | `test_normal_task` | requires_db_config=True → False |
| | `test_unknown_task` | 未注册任务 → False |
| `TestGetAllTaskCodes` | `test_returns_all_codes` | 返回所有已注册代码 |
| | `test_empty_registry` | 空注册表返回空列表 |
### `test_task_registry_properties.py` — TaskRegistry 属性测试3 个类,~300 次迭代)
| 测试类 | 测试方法 | Property | 验证内容 | 迭代次数 |
|--------|---------|----------|---------|---------|
| `TestProperty8MetadataRoundTrip` | `test_metadata_round_trip` | P8 | 任意 task_code/requires_db/layer/task_type 组合注册后get_metadata 返回完全相同的值 | 100 |
| `TestProperty9BackwardCompatibleDefaults` | `test_legacy_register_uses_defaults` | P9 | 仅传 task_code + task_class 时,默认 requires_db_config=True、layer=None、task_type="etl" | 100 |
| `TestProperty10GetTasksByLayer` | `test_get_tasks_by_layer_matches_manual_filter` | P10 | 注册一组任务后,按层查询结果与手动过滤完全一致 | 100 |
### `test_config_properties.py` — 配置映射属性测试1 个类100 次迭代)
| 测试类 | 测试方法 | Property | 验证内容 | 迭代次数 |
|--------|---------|----------|---------|---------|
| `TestProperty11FlowToDataSourceMapping` | `test_pipeline_flow_maps_to_data_source` | P11 | pipeline_flowFULL/FETCH_ONLY/INGEST_ONLY→ data_sourcehybrid/online/offline映射一致 | 100 |
### `test_task_executor_properties.py` — TaskExecutor 属性测试4 个类7 个方法,~700 次迭代)
| 测试类 | 测试方法 | Property | 验证内容 | 迭代次数 |
|--------|---------|----------|---------|---------|
| `TestProperty1DataSourceDeterminesPath` | `test_flow_includes_fetch` | P1 | data_source 为 online/hybrid 时 fetch=Trueoffline 时 fetch=False | 100 |
| | `test_flow_includes_ingest` | P1 | data_source 为 offline/hybrid 时 ingest=Trueonline 时 ingest=False | 100 |
| | `test_fetch_and_ingest_consistency` | P1 | hybrid 两者皆 Trueonline 仅 fetchoffline 仅 ingest | 100 |
| `TestProperty2SuccessAdvancesCursor` | `test_success_with_window_advances_cursor` | P2 | 成功任务调用 cursor_mgr.advance传入正确的 window_start/window_end | 100 |
| `TestProperty3FailureMarksFailAndReraises` | `test_exception_marks_fail_and_reraises` | P3 | 异常时 run_tracker.update_run(status="FAIL") 并重新抛出原始异常 | 100 |
| `TestProperty4UtilityTaskDeterminedByMetadata` | `test_utility_task_skips_cursor_and_run_tracker` | P4 | 工具类任务requires_db_config=False跳过游标和运行记录 | 100 |
| | `test_non_utility_task_uses_cursor_and_run_tracker` | P4 | 非工具类任务使用游标和运行记录 | 100 |
### `test_pipeline_runner_properties.py` — PipelineRunner 属性测试3 个类8 个方法,~800 次迭代)
| 测试类 | 测试方法 | Property | 验证内容 | 迭代次数 |
|--------|---------|----------|---------|---------|
| `TestProperty5PipelineNameToLayers` | `test_layers_match_pipeline_definition` | P5 | run() 返回的 layers 与 PIPELINE_LAYERS[pipeline] 完全一致 | 100 |
| | `test_resolve_tasks_called_with_correct_layers` | P5 | _resolve_tasks 接收的层列表与定义一致 | 100 |
| `TestProperty6ProcessingModeControlsFlow` | `test_increment_executes_iff_mode_contains_increment` | P6 | 增量 ETL 执行当且仅当 mode 包含 "increment" | 100 |
| | `test_verification_executes_iff_mode_contains_verify` | P6 | 校验流程执行当且仅当 mode 包含 "verify" | 100 |
| `TestProperty7PipelineSummaryCompleteness` | `test_summary_has_required_fields` | P7 | 返回字典包含 status/pipeline/layers/results/verification_summary | 100 |
| | `test_results_length_equals_executed_tasks` | P7 | results 长度等于实际执行的任务数 | 100 |
| | `test_pipeline_and_layers_match_input` | P7 | 返回的 pipeline 和 layers 与输入一致 | 100 |
| | `test_increment_only_has_no_verification` | P7 | increment_only 模式下 verification_summary 为 None | 100 |
### `test_filter_verify_tables.py` — 校验表过滤单元测试9 个)
| 测试类 | 测试方法 | 验证内容 |
|--------|---------|---------|
| `TestFilterVerifyTables` | `test_none_input_returns_none` | 输入 None 返回 None |
| | `test_empty_list_returns_none` | 空列表返回 None |
| | `test_dwd_layer_filters_correctly` | DWD 层过滤:保留 dwd_/dim_/fact_ 前缀 |
| | `test_dws_layer_filters_correctly` | DWS 层过滤:保留 dws_ 前缀 |
| | `test_index_layer_filters_correctly` | INDEX 层过滤:保留 v_/wbi_/nci_ 等前缀 |
| | `test_ods_layer_filters_correctly` | ODS 层过滤:保留 ods_ 前缀 |
| | `test_unknown_layer_returns_normalized` | 未知层返回归一化后的全部表名 |
| | `test_layer_case_insensitive` | 层名大小写不敏感 |
| | `test_whitespace_and_empty_entries_stripped` | 空白和空条目被过滤 |
### `test_cli_args.py` — CLI 参数解析单元测试14 个)
| 测试类 | 测试方法 | 验证内容 |
|--------|---------|---------|
| `TestDataSourceArg` | `test_data_source_valid_values` (×3) | --data-source 接受 online/offline/hybrid |
| | `test_data_source_default_is_none` | 未指定时默认 None |
| `TestResolveDataSource` | `test_explicit_data_source_returns_directly` | 显式 --data-source 直接返回 |
| | `test_data_source_takes_priority_over_pipeline_flow` | --data-source 优先于 --pipeline-flow |
| | `test_pipeline_flow_maps_with_deprecation_warning` (×3) | 旧参数映射 + 弃用警告 |
| | `test_neither_arg_defaults_to_hybrid` | 两者都未指定时默认 hybrid |
| `TestBuildCliOverrides` | `test_data_source_online_sets_run_key` | --data-source 写入 run.data_source |
| | `test_pipeline_flow_sets_both_keys` | 旧参数同时写入 pipeline.flow 和 run.data_source |
| | `test_default_data_source_is_hybrid` | 默认 run.data_source 为 hybrid |
| `TestPipelineAndTasks` | `test_pipeline_and_tasks_both_parsed` | --pipeline + --tasks 同时解析 |
### `test_e2e_flow.py` — 端到端流程集成测试4 个)
| 测试类 | 测试方法 | 验证内容 |
|--------|---------|---------|
| `TestTraditionalModeE2E` | `test_run_tasks_executes_utility_task_and_returns_results` | TaskExecutor.run_tasks 工具类任务端到端 |
| `TestPipelineModeE2E` | `test_pipeline_delegates_to_executor_and_returns_structure` | PipelineRunner → TaskExecutor 委托 + 返回结构 |
| | `test_pipeline_verify_only_skips_increment` | verify_only 模式跳过增量 ETL |
| `TestSchedulerThinWrapper` | `test_scheduler_delegates_run_tasks` | ETLScheduler 薄包装层正确委托 TaskExecutor/PipelineRunner |
---
## 属性测试PBT汇总
| Property | 所属组件 | 验证需求 | 迭代次数 |
|----------|---------|---------|---------|
| P1 | TaskExecutor | data_source 参数决定执行路径Req 1.2 | 300 |
| P2 | TaskExecutor | 成功任务推进游标Req 1.3 | 100 |
| P3 | TaskExecutor | 失败任务标记 FAIL 并重新抛出Req 1.4 | 100 |
| P4 | TaskExecutor | 工具类任务由元数据决定Req 1.6, 4.2 | 200 |
| P5 | PipelineRunner | 管道名称→层列表映射Req 2.1 | 200 |
| P6 | PipelineRunner | processing_mode 控制执行流程Req 2.3, 2.4 | 200 |
| P7 | PipelineRunner | 管道结果汇总完整性Req 2.6 | 400 |
| P8 | TaskRegistry | 元数据 round-tripReq 4.1 | 100 |
| P9 | TaskRegistry | 向后兼容默认值Req 4.4 | 100 |
| P10 | TaskRegistry | 按层查询任务Req 4.3 | 100 |
| P11 | AppConfig | pipeline_flow → data_source 映射一致性Req 8.1-8.4, 5.2 | 100 |
总计11 个属性,~1900 次迭代。

View File

@@ -0,0 +1,34 @@
在线抓取更新ODS 然后将更新的ODS内容对应到DWD的更新。
可以按“两段定时”跑:先在线抓取+入库更新 ODS再跑 DWD_LOAD_FROM_ODS 把新增/变更同步到 DWD。CLI 用 python -m etl_billiards.cli.main。
1) ODS在线抓取 + 入库FULL
python -m etl_billiards.cli.main ^
--pipeline-flow FULL ^
--tasks PRODUCTS,TABLES,MEMBERS,ASSISTANTS,PACKAGES_DEF,ORDERS,PAYMENTS,REFUNDS,COUPON_USAGE,INVENTORY_CHANGE,TOPUPS,TABLE_DISCOUNT,ASSISTANT_ABOLISH,LEDGER ^
--pg-dsn "%PG_DSN%" ^
--store-id %STORE_ID% ^
--api-token "%API_TOKEN%"
(可选)指定落盘目录:加 --fetch-root "export/JSON";美化 JSON--write-pretty-json
2) DWDODS → DWD
python -m etl_billiards.cli.main ^
--pipeline-flow INGEST_ONLY ^
--tasks DWD_LOAD_FROM_ODS ^
--pg-dsn "%PG_DSN%" ^
--store-id %STORE_ID%
推荐的环境变量
PG_DSN=postgresql://user:pwd@host:5432/db
STORE_ID=...
API_TOKEN=...
可选JSON_FETCH_ROOT=... / FETCH_ROOT=...LOG_ROOT=...
如果你希望“一条命令顺序跑完 ODS+DWD”也可以直接
python -m etl_billiards.cli.main ^
--pipeline-flow FULL ^
--tasks PRODUCTS,TABLES,MEMBERS,ASSISTANTS,PACKAGES_DEF,ORDERS,PAYMENTS,REFUNDS,COUPON_USAGE,INVENTORY_CHANGE,TOPUPS,TABLE_DISCOUNT,ASSISTANT_ABOLISH,LEDGER,DWD_LOAD_FROM_ODS ^
--pg-dsn "%PG_DSN%" ^
--store-id %STORE_ID% ^
--api-token "%API_TOKEN%"
(这会对前半段任务走在线抓取+入库,对 DWD_LOAD_FROM_ODS 只做入库阶段,因为它没有抓取逻辑。)

View File

@@ -0,0 +1,455 @@
PRD保留 NCI / WBI删除亲密指数新增 RS / OS / MS / ML 指数体系
生效目标:用**客户级NCI/WBI负责“触达优先级”用关系级RS/OS/MS/ML**负责“归属与执行”,替代原 INTIMACY 的混合口径,提升可解释性与可运营性。
统计与映射方法沿用现有“时间衰减 + 分位截断 + 010 映射 + 可选 EWMA 平滑”的工程框架(减少改造风险)。
1. 背景与问题
1.1 背景
当前体系已有两类客户级指数:
NCI新客转化指数用于新客欢迎与转化排序
WBI老客挽回指数用于老客召回排序
同时存在一个关系级的 亲密指数INTIMACY但它把“关系强度、归属、升温、付费关联”混在一个分数里导致
一个分数承担多个运营目的,解释困难,策略难稳定
动量burst乘法放大会掩盖“真实关系强度”
充值归因可靠性要求高,一旦归因口径瑕疵会放大偏差
1.2 目标
保留 NCI / WBI 不变(持续作为客户级“触达优先级”)
删除 INTIMACY停止计算/停止被消费)
新增四个关系级指数RS / OS / MS / ML
RS关系强度熟不熟
OS归属份额主要归谁
MS动量升温最近是否回暖/升温)
ML付费关联推增值/储值由谁推更可能成)
2. 术语与设计依据(对齐工程约定)
2.1 时间衰减(半衰期)
统一采用半衰期形式的指数衰减,保证“越近越重要”的可解释性。
2.2 010 映射(展示分)
统一采用:
P5/P95 分位截断Winsorize降低极端值影响
可选压缩log1p/asinh
MinMax 映射到 010
可选 EWMA 平滑减少跨批次抖动
2.3 价值/触达优先级方法论NCI/WBI 保留原因)
RFMRecency/Frequency/Monetary作为客户分层与运营触达优先级的主流方法与你的 WBI/NCI 结构一致(尤其是 recency + frequency + monetary 信号)。
其中 NCI/WBI 继续承担“客户级排序”,关系级指数负责“落人/归属/推荐成功率”。
3. 用户与核心运营场景
3.1 角色
店长/运营:配置策略、看板、复盘
助教主管:分派任务、监控撞单/共管
助教:执行跟进、召回、增值推荐
3.2 场景总览(决策逻辑分层)
客户级:要不要触达、先触达谁 → NCI / WBI
关系级:由谁触达、怎么触达 → OS定责+ RS/MS/ML定策略
4. 新指标定义(删除 INTIMACY新增 RS/OS/MS/ML
粒度说明RS/OS/MS/ML 均为 (site_id, member_id, assistant_id) 关系对粒度。
数据基础与会话合并逻辑沿用原 INTIMACY 的服务日志抽取与 session merge减少工程变动
NCI/WBI 完全保留原逻辑与输出。
4.1 RS关系强度Relationship Strength
用途:判断“这位助教与该客户是否真的熟、关系是否牢”。
核心输入:
合并会话后的:次数、时长、课型权重(基础/附加)
距今天数(会话结束时间)
最近一次服务距今天数
计算(建议口径):
会话权重τ_i = 1.0(基础) 或 incentive_weight附加
会话衰减decay(d; h) = exp(-ln(2)*d/h)
频次项F = Σ ( τ_i * decay(d_i; h_session) )
时长项D = Σ ( sqrt(dur_hours_i) * τ_i * decay(d_i; h_session) )
最近门控R = decay(days_since_last; h_last)
RS_raw
base = w_F*F + w_D*D
gate = R^(gate_alpha)
RS_raw = base * gate
输出:
RS_raw
RS_display010沿用通用映射与可选 EWMA
4.2 OS归属份额Ownership Share
用途:解决“客户到底归谁主跟,避免多人撞单”。
核心输入:同一客户在所有助教上的 RS_raw。
计算:
对每个 member_idOS = RS_raw_i / (Σ RS_raw_all_assistants + eps)
加入噪声门槛:
若 RS_raw_i < min_rs_raw_for_ownership则 OS 视为 0不参与归属
若 Σ RS_raw_all_assistants < min_total_rs_raw则该客户视为“未形成稳定归属”
输出:
OS_share01推荐 UI 显示百分比)
OS_label主责/共管/公海):
主责OS_share >= ownership_main_threshold
共管ownership_comanage_threshold <= OS_share < ownership_main_threshold
公海OS_share < ownership_comanage_threshold
OS 不建议做分位映射(它是份额值,天然可解释)。如必须 010只做 OS_share*10 的线性映射。
4.3 MS动量升温Momentum
用途:判断“最近是否升温/回流”,用于跟进紧急程度(而不是关系强度)。
核心输入:短期与长期的加权频次(含衰减与课型权重)。
计算:
F_short = Σ( τ_i * decay(d_i; h_short) )
F_long = Σ( τ_i * decay(d_i; h_long) )
ratio = (F_short + eps) / (F_long + eps)
MS_raw只保留升温部分
MS_raw = max(0, ln(ratio))
输出:
MS_raw
MS_display010通用映射与可选 EWMA
4.4 ML付费关联Monetization Link
用途:判断“推储值/增值由谁推更可能成”,用于选择执行人/协同人。
核心输入:服务后短窗口内的充值归因、金额、时间衰减。
关键前提(必须做的口径修复):
单笔充值只归因一个助教采用“last-touch”原则
对每笔充值:在归因窗口内,找 session_end <= pay_time 且最接近 pay_time 的那条会话对应的助教归因
计算:
对每笔归因充值 r
金额压缩ln(1 + amt / amount_base)
时间衰减decay(days_ago_r; h_recharge)
ML_raw = Σ( ln(1 + amt/amount_base) * decay(days_ago_r; h_recharge) )
输出:
ML_raw
ML_display010通用映射与可选 EWMA
5. 数据依赖与产出表
5.1 输入数据(沿用原 INTIMACY 的服务/充值口径)
服务日志billiards_dwd.dwd_assistant_service_log + billiards_dwd.dim_assistant
充值订单billiards_dwd.dwd_recharge_ordersettle_type=5
课型映射cfg_skill_type决定 BONUS/BASE 权重)
5.2 输出表(新增)
建议新增统一关系表(替代原 dws_member_assistant_intimacy
表名billiards_dws.dws_member_assistant_relation_index
主键:(site_id, member_id, assistant_id)
核心字段:
基础特征(用于解释与排查):
session_count, total_duration_minutes, basic_session_count, incentive_session_count, days_since_last_session
attributed_recharge_count, attributed_recharge_amount
指数:
rs_raw, rs_display
os_share, os_label, os_rank
ms_raw, ms_display
ml_raw, ml_display
时间calc_time, created_at, updated_at
NCI/WBI 输出表保持不变。
5.3 删除/下线(原 INTIMACY
停止写入billiards_dws.dws_member_assistant_intimacy
兼容期保留表但不再更新,前端与运营入口不再读取
6. cfg_index_parameters 配置体系更新(你要求的“更新”核心)
6.1 现有配置表结构(保持不变)
cfg_index_parameters 继续使用现有字段:
(param_id, index_type, param_name, param_value, description, effective_from, effective_to, created_at, updated_at)
6.2 index_type 更新范围
保留NCI, WBI不改参数不改逻辑
删除INTIMACY通过 effective_to 失效,不再读取)
新增RS, OS, MS, ML
其它 index_type如 RECALL本 PRD 不涉及,保持现状。
7. 新增参数清单(默认值建议)
说明参数名尽量沿用现有风格snake_case并把“展示映射参数”复用到 RS/MS/ML 三个需要 010 映射的指数上。Winsorize 与 EWMA 的合理性见设计依据。
7.1 RS 参数index_type = RS
param_name 默认值 说明
lookback_days 60 回看窗口(天)
session_merge_hours 4 会话合并间隔(小时)
incentive_weight 1.5 附加课权重
halflife_session 14 会话衰减半衰期(天)
halflife_last 10 最近服务衰减半衰期(天)
weight_F 1.0 频次项权重
weight_D 0.7 时长项权重
gate_alpha 0.6 最近门控幂次(越大越强调“必须最近”)
percentile_lower 5 映射下分位
percentile_upper 95 映射上分位
compression_mode 1 0=none,1=log1p,2=asinh
use_smoothing 1 是否启用 EWMA 平滑
ewma_alpha 0.2 EWMA α
7.2 OS 参数index_type = OS
param_name 默认值 说明
min_rs_raw_for_ownership 0.05 归属噪声门槛(低于此 RS_raw 不参与 OS
min_total_rs_raw 0.10 客户总体关系强度过低则视为“未形成归属”
ownership_main_threshold 0.60 OS 主责阈值
ownership_comanage_threshold 0.35 OS 共管阈值
eps 1e-6 分母保护
7.3 MS 参数index_type = MS
param_name 默认值 说明
lookback_days 60 回看窗口(天)
session_merge_hours 4 会话合并间隔(小时)
incentive_weight 1.5 附加课权重
halflife_short 7 短期半衰期(天)
halflife_long 30 长期半衰期(天)
eps 1e-6 比值保护
percentile_lower 5 映射下分位
percentile_upper 95 映射上分位
compression_mode 1 0=none,1=log1p,2=asinh
use_smoothing 1 是否启用 EWMA 平滑
ewma_alpha 0.2 EWMA α
7.4 ML 参数index_type = ML
param_name 默认值 说明
lookback_days 60 回看窗口(天)
recharge_attribute_hours 1 充值归因窗口(小时)
attribution_mode 1 1=last_touch单笔充值只归因一个助教
amount_base 500 金额压缩基数
halflife_recharge 21 充值衰减半衰期(天)
percentile_lower 5 映射下分位
percentile_upper 95 映射上分位
compression_mode 1 0=none,1=log1p,2=asinh
use_smoothing 1 是否启用 EWMA 平滑
ewma_alpha 0.2 EWMA α
8. 配置迁移策略cfg_index_parameters 具体更新方式)
8.1 INTIMACY 下线
将 index_type = 'INTIMACY' 的现行有效参数统一设置 effective_to = 下线日(建议为新版本生效日前一天)
代码层:不再加载/执行 INTIMACY 任务
8.2 新增 RS/OS/MS/ML 参数
插入上述四个 index_type 的参数行,设置 effective_from = 新版本生效日
param_id 由数据库自增生成(不在 PRD 固定)
8.3 生效日期建议
当前日期为 2026-02-08台北时区建议
新增四类参数 effective_from = 2026-02-09
INTIMACY effective_to = 2026-02-08
9. 任务与工程改造范围
9.1 ETL 任务
保留NCI/WBI 原任务
新增RelationIndexTask或拆为 RS/MS/ML/OS 四个任务,但建议一个任务产出一张关系表)
删除/停用:原 IntimacyIndexTask
9.2 关键工程点(必须实现)
复用 session merge降低风险
充值归因改为 last_touch 单归因ML 可靠性的硬前提)
RS/MS/ML 的 display 映射复用 BaseIndexTask一致性与可调参性
OS 份额化与标签化(防撞单的唯一有效方式)
10. 运营使用方式(落地规则)
10.1 任务队列(建议固定四条队列)
新客欢迎:按 NCI_welcome 排序
新客转化:按 NCI_convert 排序
老客召回:按 WBI 排序
活跃升温承接:按 MS 排序
10.2 “落人”规则(所有队列通用)
有明确归属:按 OS_label=主责 的助教派单
共管:只派给主责助教,协同人由 ML 或 RS 次高者确定
公海:派给当班/新客官/运营池
10.3 增值推荐(谁推更可能成)
选客户:以 NCI/WBI 中的价值/充值未回访信号做筛选
选执行人:以 ML 高者为主OS 作为责任边界RS 决定话术深度
11. 验收标准(可测试、可回归)
11.1 数据正确性
OS同一 member_id 下所有 assistant_id 的 OS_share参与归属者求和≈1
RS新增会话、会话更近、时长更长 → RS_raw 单调上升(统计抽样验证)
MS短期频次明显高于长期 → MS_raw>0否则 MS_raw=0
ML充值发生在归因窗口内且越近越大 → ML_raw 越高;且单笔充值只归因一个助教
11.2 运营可用性
至少能稳定支持:
客户分配OS
跟进紧急程度MS
召回优先级WBI
新客欢迎/转化NCI
推增值选人ML
12. 风险与对策
OS 噪声归属:低互动关系也被算份额
→ 用 min_rs_raw_for_ownership 与 min_total_rs_raw 双门槛
ML 偏差:归因口径不稳定导致误导选人
→ 强制 last_touch 单归因;窗口可调;上线初期做抽样对账
display 分数跨批次漂移(相对分固有属性)
→ 开启 EWMA 平滑降低短期抖动
13. 上线与灰度建议
第 1 阶段影子跑数RS/OS/MS/ML 与 INTIMACY 并行计算但不对外展示12 周)
第 2 阶段(切读):前端/运营策略只读 RS/OS/MS/MLINTIMACY 停止消费
第 3 阶段(下线):停更 INTIMACY 表,保留历史查询周期后再清理
14. 交付物清单
新增关系表dws_member_assistant_relation_index
新增指数任务RelationIndexTask含 RS/OS/MS/ML
cfg_index_parameters
INTIMACY 参数失效effective_to
新增 RS/OS/MS/ML 参数effective_from
运营端:
队列:新客欢迎/新客转化/老客召回/升温承接
客户详情:展示 NCI、WBI、以及每位助教的 RS/OS/MS/ML
15. 实施定稿补充2026-02-08
1. ML 数据源定稿为“人工台账唯一真源”:
- `dws_ml_manual_order_alloc` 为 ML 主口径输入;
- 无台账时 `ML_raw=0`
- `dwd_recharge_order` 的 last-touch 仅保留备用代码路径(默认关闭,`ML.source_mode=0`)。
2. 台账规则定稿:
- 一单可归多个助教,默认均分;
- `external_id` 作为订单ID必填
- 同一 `(site_id, external_id, assistant_id)` 重复导入时覆盖;
- 覆盖边界:
- 30天内按 `site_id + biz_date` 日覆盖;
- 超过30天按固定纪元 `2026-01-01` 的 30 天桶覆盖。
3. 关系指数任务形态:
- 单任务 `RelationIndexTask` 一次产出 RS/OS/MS/ML
- 输出表:`dws_member_assistant_relation_index`
- `RS/MS/ML` 分位映射与 EWMA 历史按 `index_type` 隔离。
4. 参数补充:
- `index_type=OS` 新增 `ownership_gap_threshold`(默认 0.15
- `index_type=ML` 新增 `source_mode`(默认 0manual_only
5. 上线策略修订:
- 当前未正式上线,直接切换读新表;
- 影子期不再作为强制步骤。

View File

@@ -0,0 +1,11 @@
现在进行ETL全流程测试。
按以下要求后台运行此任务。
你每隔1-10分析获取一遍输出及时DEBUG。
并对完成的没有报错的内容,在数据来源侧和数据落回测进行数据比对。
[09:56:35] [环境变量] WINDOW_SPLIT_UNIT=month
[09:56:35] [环境变量] INDEX_LOOKBACK_DAYS=180
[09:56:35] [环境变量] VERIFY_SKIP_ODS_ON_FETCH=true
[09:56:35] [环境变量] VERIFY_ODS_LOCAL_JSON=true
[09:56:35] [工作目录] C:\dev\LLTQ\ETL\feiqiu-ETL\etl_billiards
[09:56:35] [执行命令] python -m cli.main --pipeline api_full --processing-mode verify_only --fetch-before-verify --window-start 2025-07-07 09:55:21 --window-end 2026-02-09 09:55:21 --window-split month --tasks ODS_MEMBER_BALANCE,ODS_MEMBER,ODS_MEMBER_CARD,ODS_SETTLEMENT_RECORDS,ODS_PAYMENT,ODS_RECHARGE_SETTLE,ODS_REFUND,ODS_SETTLEMENT_TICKET,ODS_ASSISTANT_LEDGER,ODS_ASSISTANT_ABOLISH,ODS_ASSISTANT_ACCOUNT,ODS_TENANT_GOODS,ODS_STORE_GOODS,ODS_STORE_GOODS_SALES,ODS_GOODS_CATEGORY,ODS_TABLES,ODS_TABLE_USE,ODS_TABLE_FEE_DISCOUNT,ODS_GROUP_BUY_REDEMPTION,ODS_GROUP_PACKAGE,ODS_PLATFORM_COUPON,ODS_INVENTORY_STOCK,ODS_INVENTORY_CHANGE,DWD_LOAD_FROM_ODS,PAYMENTS_DWD,MEMBERS_DWD,DWS_BUILD_ORDER_SUMMARY,DWS_ASSISTANT_DAILY,DWS_ASSISTANT_MONTHLY,DWS_ASSISTANT_CUSTOMER,DWS_ASSISTANT_SALARY,DWS_ASSISTANT_FINANCE,DWS_MEMBER_CONSUMPTION,DWS_MEMBER_VISIT,DWS_FINANCE_DAILY,DWS_FINANCE_RECHARGE,DWS_FINANCE_INCOME_STRUCTURE,DWS_FINANCE_DISCOUNT_DETAIL,DWS_MV_REFRESH_FINANCE_DAILY,DWS_MV_REFRESH_ASSISTANT_DAILY,DWS_RETENTION_CLEANUP,DWS_WINBACK_INDEX,DWS_NEWCONV_INDEX,DWS_RELATION_INDEX

View File

@@ -0,0 +1,314 @@
时间分层机制需求明确“四层时间分层近2天/近1月/近3月/全量)”,方案只写了更新频率,需补齐具体实现(分区策略/分层表或物化汇总层/定期归档与清理作业)。
DDL 完整性:补充说明中提到缺失的表(如 cfg_tier_effective_period、dws_assistant_salary_calc、dws_member_visit_detail、dws_finance_discount_detail、dws_finance_recharge_summary、dws_finance_expense_summary需要在 schema_dws.sql 里落全方案里写了“更新DDL”但应明确完整DDL清单与字段级定义。
薪酬规则与生效期:档位、奖金、规则有“按月/按时间生效”的要求,方案目前只有 cfg_performance_tier/cfg_bonus_rules需要补充生效期字段或独立“规则生效期配置表”否则历史月份口径会错。
SCD2 / as-of 口径助教等级是SCD2维度历史月份不能直接用“当前等级”。方案需明确“按有效期 as-of join”的取数规则。
技能枚举规范:需求要求用 skill_id 判断基础课/附加课;方案应明确 skill_id→课程类型映射可用配置表避免 skill_name 漏记。
滚动区间统计:需求中明确 7/10/15/30/60/90 天窗口,方案未明确存储方式(建议在 dws_assistant_customer_stats、dws_member_consumption_summary 中直接落多窗口字段,或新增滚动汇总表)。
财务口径矩阵需全覆盖:方案已有“数据来源矩阵”,但需扩展至财务页面每一项指标(发生额/优惠拆分/确认收入/现金流/充值/平台回款/支出结构),确保每一项都有明确字段+公式+来源表。
手工导入表规范:支出/平台回款/充值提成的Excel导入要补“字段定义、时间粒度、门店维度、去重与校验规则”否则实现阶段会反复返工。
区域/房型维表:方案已有 cfg_area_category但需落地“具体映射规则 + 默认兜底 + 异常值处理”,并与 BD_manual_dim_table.md 一致。
# 更新
时间口径定义:本周/上周/本季度/上季度/最近半年不含本月 等窗口的“起止边界”为月第一天0点。周起始日为周一。
环比规则:开启对比时,是“对比上一个等长区间”相比。
有效业绩的排除规则:仅对“助教废除表”的记录进行处理排除。其影响绩效。
新入职定档规则月1日0点之后入住的计算为新入职。入职日以助教表入职时间为准。
Top3 奖金排名口径按绩效总小时数。如遇并列则都算比如2个第一则记为2个第一一个第三。
充值提成规则:比例/阶梯/时间口径缺失:通过手动导入表格,表格中会明确月份,提成关联充值订单金额和助教获得的提成金额。
大客户优惠/其他优惠划分规则:目前需要抽样分析。
平台回款/服务费口径:明确导入数据字段包含:回款金额、佣金、服务费、回款日期、平台类型、订单关联键。
散客处理member_id=0 的客户是散客。不进入客户维度统计。
门店/租户范围:现在只有一个门店,一个租户。
我想让你帮我基于DWS层的数据也可使用DWD层设计2个指数算法
- 客户召回指数:根据客户的到店时间,计算由助教或工作人员进行召回的必要性和紧急程度。算法不仅尊重每个客户的到店周期习惯,还要对新客户和刚充值客户进行一定的召回倾向。
- 客户与助教亲密程度根据单个客户与单个助教发生的服务关系为助教的约课精力分配约课成功率进行推算参考。计算2个对象的亲密程度。附加课激励/超休权重是基础课的1.5倍。重要的指标包括服务频次为其充值服务开始到结束后的1个小时内发生的充值即算做为其充值。此逻辑仅在指数算法有效最后一次服务发生到现在的间隔等。次重要的是每次服务的时长同一个客人对某一个助教的服务间隔小于4小时则算作同次服务。若一段时间内频次频率出现激增则加重权重。
注意指数算法需要符合人性直觉对时间间隔周期敏感。指数会周期更新1小时到1天不等根据实际业务进行调整计算的分数会直接覆盖旧分数是一个动态的实时的分数。我建议算法没有最高分是一个线性的分数更新完一轮后将最高分映射为满分上限10.0分。在0.0-10.0区间内,映射所有分数。
参考资料如下,告诉我你的实施计划。
# 指数算法方案(假设所有输入特征已具备)
> 统一约定:以“天”为时间单位;回溯窗口最多 60 天;指数每轮重算并覆盖旧分数。
> 所有指数先计算 **Raw Score无上限**,再映射为 **Display Score0.010.0** 用于展示与排序。
---
## 0. 通用函数与参数
### 0.1 时间衰减函数(半衰期模型)
设事件距今天数为 \(d \ge 0\),半衰期为 \(h>0\)(天):
\[
\mathrm{decay}(d;h)=\exp\left(-\ln(2)\cdot \frac{d}{h}\right)
\]
解释:当 \(d=h\) 时权重衰减到 0.5;越近权重越大,符合“近两周更重要”的直觉。
### 0.2 更新窗口
- 回溯:最近 \(W=60\) 天内的到店/服务/充值事件
- 近期重点:半衰期通常取 \(7\sim 14\) 天
---
## 1) 客户召回指数Recall Index, RI
### 1.1 目标
衡量“是否需要召回”及“紧急程度”。
同时尊重客户个人到店周期,并对 **新客户**、**刚充值客户** 增加召回倾向。
### 1.2 假设输入特征(概念层,不细化字段)
对每个客户 \(c\),假设已具备:
- \(t\): 距离最近一次到店(或最近一次服务结束)已过去的天数
- \(\mu\): 客户过去 60 天到店间隔的“典型周期”(建议中位数)
- \(\sigma\): 客户到店间隔波动尺度(建议 MAD / IQR 等稳健尺度)
- \(d_{\text{first}}\): 距离首访的天数(若无首访则视为很大)
- \(d_{\text{re}}\): 距离最近一次充值的天数(若无充值则视为很大)
- \(n_{14}, n_{60}\): 近 14 天/60 天到店(或会话)次数
> 注:若 \(t>60\),可按 \(t=60\) 截断用于衰减计算,避免“太久不来”占用资源。
### 1.3 参数(可调默认值)
- \(\sigma_0=2\):波动下限(天),避免 \(\sigma\) 过小导致超期过敏
- 新客半衰期 \(h_{\text{new}}=7\)
- 刚充值半衰期 \(h_{\text{re}}=10\)
- 召回各分量权重:
- \(w_{\text{over}}=3.0\)(超期紧急性,主导)
- \(w_{\text{new}}=1.0\)
- \(w_{\text{re}}=1.0\)
- \(w_{\text{hot}}=1.0\)(近期活跃后断档)
- 防除零:\(\epsilon=10^{-6}\)
### 1.4 计算步骤Raw Score
#### (1) 超期紧急性(尊重个人周期)
先做稳健标准化超期量:
\[
\sigma'=\max(\sigma,\sigma_0)
\]
\[
z=\max\left(0,\frac{t-\mu}{\sigma'}\right)
\]
将其映射到 \(0\sim 1\) 的“超期强度”(越超期越接近 1
\[
\mathrm{overdue}=1-\exp(-z)
\]
#### (2) 新客户召回倾向(快衰减)
设“新客”条件为 \(d_{\text{first}}\le 60\)
\[
\mathrm{new\_bonus}=
\begin{cases}
\mathrm{decay}(d_{\text{first}};h_{\text{new}}), & d_{\text{first}}\le 60\\
0, & \text{否则}
\end{cases}
\]
#### (3) 刚充值召回倾向(快衰减)
设“近期充值”条件为 \(d_{\text{re}}\le 60\)
\[
\mathrm{re\_bonus}=
\begin{cases}
\mathrm{decay}(d_{\text{re}};h_{\text{re}}), & d_{\text{re}}\le 60\\
0, & \text{否则}
\end{cases}
\]
#### (4) 近期活跃后断档加重(“热了又断”更值得召回)
定义短期/长期活跃率:
\[
r_{14}=\frac{n_{14}}{14},\quad r_{60}=\frac{n_{60}+1}{60}
\]
活跃比:
\[
\mathrm{hot\_ratio}=\frac{r_{14}}{r_{60}+\epsilon}
\]
将“高于常态”的部分做对数压缩(避免爆炸):
\[
\mathrm{hot\_drop}=\max\left(0,\ln\left(1+(\mathrm{hot\_ratio}-1)\right)\right)
\]
#### (5) 汇总 Raw Score无上限
\[
RI_{\text{raw}}=
w_{\text{over}}\cdot \mathrm{overdue}
+w_{\text{new}}\cdot \mathrm{new\_bonus}
+w_{\text{re}}\cdot \mathrm{re\_bonus}
+w_{\text{hot}}\cdot \mathrm{hot\_drop}
\]
---
## 2) 客户-助教亲密指数Intimacy Index, II
### 2.1 目标
衡量“客户 \(c\) 与助教 \(a\) 的关系强度与近期温度”,用于:
- 助教约课精力分配
- 约课成功率的先验参考
强调:
- **附加课权重 = 基础课的 1.5 倍**
- 指标重要性:频次、归因充值、最近一次间隔 > 时长
- 若短期频率激增,权重要加重
### 2.2 假设输入特征(概念层)
对每个客户-助教对 \((c,a)\),假设已具备(近 60 天):
- 会话集合 \(i\in S\),每个会话有:
- 距今天数 \(\Delta d_i\)
- 时长(分钟)\(\mathrm{dur}_i\)
- 课型权重 \(\tau_i\in\{1.0,1.5\}\)(基础/附加)
- 最近一次会话距今天数:\(d_{\text{last}}\)
- 归因充值集合 \(j\in R\),每笔充值有:
- 金额 \(\mathrm{amt}_j\)
- 距今天数 \(\Delta d^{(r)}_j\)
### 2.3 参数(可调默认值)
- 会话衰减半衰期 \(h_{\text{sess}}=14\)
- 最近一次衰减半衰期 \(h_{\text{last}}=10\)
- 充值衰减半衰期 \(h_{\text{pay}}=21\)
- 金额压缩基准 \(A_0=500\)(选门店常见充值档位)
- Burst激增检测半衰期
- 短期 \(h_{\text{short}}=7\)
- 长期 \(h_{\text{long}}=30\)
- 汇总权重:
- \(w_F=2.0\)(频次)
- \(w_R=1.5\)(最近一次)
- \(w_M=2.0\)(归因充值)
- \(w_D=0.5\)(时长)
- 激增放大系数 \(\gamma=0.6\)
- 防除零:\(\epsilon=10^{-6}\)
### 2.4 计算步骤Raw Score
#### (1) 频次强度(课型加权 + 近因加权)
\[
F=\sum_{i\in S}\tau_i\cdot \mathrm{decay}(\Delta d_i;h_{\text{sess}})
\]
#### (2) 最近一次温度(单独建模,直觉更强)
\[
R=\mathrm{decay}(d_{\text{last}};h_{\text{last}})
\]
#### (3) 归因充值强度(金额压缩 + 时间衰减)
金额压缩采用对数(抑制长尾):
\[
m(\mathrm{amt})=\ln\left(1+\frac{\mathrm{amt}}{A_0}\right)
\]
\[
M=\sum_{j\in R} m(\mathrm{amt}_j)\cdot \mathrm{decay}(\Delta d^{(r)}_j;h_{\text{pay}})
\]
#### (4) 时长贡献(次要:温和加分,避免一局超长碾压)
\[
D=\sum_{i\in S}\sqrt{\frac{\mathrm{dur}_i}{60}}\cdot \tau_i\cdot \mathrm{decay}(\Delta d_i;h_{\text{sess}})
\]
#### (5) 频率激增Burst放大
分别计算短期/长期的“近因频次”:
\[
F_{\text{short}}=\sum_{i\in S}\tau_i\cdot \mathrm{decay}(\Delta d_i;h_{\text{short}})
\]
\[
F_{\text{long}}=\sum_{i\in S}\tau_i\cdot \mathrm{decay}(\Delta d_i;h_{\text{long}})
\]
激增幅度(仅放大“高于常态”的部分,并做对数压缩):
\[
\mathrm{burst}=\max\left(0,\ln\left(1+\left(\frac{F_{\text{short}}}{F_{\text{long}}+\epsilon}-1\right)\right)\right)
\]
放大因子:
\[
\mathrm{mult}=1+\gamma\cdot \mathrm{burst}
\]
#### (6) 汇总 Raw Score无上限
\[
II_{\text{raw}}=\left(w_F F + w_R R + w_M M + w_D D\right)\cdot \mathrm{mult}
\]
---
## 3) 统一的 0.010.0 映射方案(稳健替代“按最大值等比”)
> 目标:既能保持“高分更紧急/更亲密”的排序,又不被极端离群点劫持整体区间。
> 该映射对 RI 与 II 通用,分别在各自对象集合上计算分位点。
### 3.1 每轮映射步骤(推荐:分位截断 + 可选压缩 + MinMax
对某个指数的全体 Raw 分数集合 \(\{x_k\}\)(如所有客户的 \(RI_{\text{raw}}\) 或所有 pair 的 \(II_{\text{raw}}\)
1) 计算稳健锚点分位数(建议):
- 下锚:\(Q_L = P05(x)\)5 分位)
- 上锚:\(Q_U = P95(x)\)95 分位)
2) 分位截断Winsorize
\[
x'_k = \min\left(\max(x_k,Q_L),Q_U\right)
\]
3) 可选非线性压缩当仍呈长尾时启用II 通常更适合启用)
两种任选一种即可:
- \[
g(x)=\ln(1+x)
\]
- \[
g(x)=\mathrm{asinh}(x)
\]
得到:
\[
y_k=g(x'_k)
\]
4) 映射到 \([0,10]\)
\[
\text{score}_k=
10\cdot \frac{y_k-\min(y)}{\max(y)-\min(y)+\epsilon}
\]
### 3.2 防抖(可选但强烈建议):分位点做 EWMA 平滑
若你发现“每轮分布轻微变化导致全员分数跳动”,可对 \(Q_L, Q_U\) 做平滑:
\[
Q_{U,t}=(1-\alpha)Q_{U,t-1}+\alpha Q_{U,t}^{\text{now}},\quad \alpha=0.2
\]
\[
Q_{L,t}=(1-\alpha)Q_{L,t-1}+\alpha Q_{L,t}^{\text{now}}
\]
> 更新频率越高(例如每小时),越推荐启用平滑;每日更新可不启用或取更大 \(\alpha\)。
### 3.3 极端边界处理
- 若出现 \(\max(y)-\min(y)\) 很小(几乎全员相同),则直接置:
- \(\text{score}=5.0\) 或按业务设定为 0.0/固定值
- 对 \(t>60\) 的客户,可视业务做“召回上限策略”:例如将其召回分数封顶在 8~9避免永远占据第一优先级但 Raw 分数仍可保留用于分析。
---
## 4) 实施建议(不涉及字段级)
- 先按默认参数跑 1~2 周,观察:
- 召回指数 TopN 是否符合店内直觉(人工抽检)
- 亲密指数在助教维度是否形成合理“主客群”
- 分数跨轮次是否抖动(决定是否启用分位点 EWMA
- 权重调整优先级:
1) 映射稳定性(分位截断阈值、是否启用压缩/平滑)
2) RI\(w_{\text{over}}\) 与 \(h_{\text{new}},h_{\text{re}}\)
3) II\(w_F,w_M\) 与 \(h_{\text{sess}},h_{\text{pay}}\),以及 \(\gamma\)

View File

@@ -0,0 +1,167 @@
# 补充更多信息:
## DWD数据库更新
DWD的数据库若干表中新增了若干表可能会对整个DWS层设计有影响/优化,重新思考可用的字段。
## 支出/成本数据缺失
财务页需要房租、水电、物业、工资、报销、平台服务费等现金支出与“支出结构”DWD 里只有商品成本 dwd_store_goods_sale.cost_money但价格也不对。缺少费用/薪酬/平台服务费等表,导致“现金支出/现金结余/结余率/支出结构”无法落地。
### 更新:
- 这些内容先在数据库结构中预留后期会通过Excel等方式手动导入。
## 平台回款与团购差价口径不足
需求有“平台回款”“团购差价”DWD 只有团购核销/验券记录dwd_groupbuy_redemption/dwd_platform_coupon_redemption没有平台结算/回款/佣金/服务费明细,无法算“平台回款”与“平台服务费”。
### 更新:
- 确认的平台服务费与回款金额先在数据库结构中预留后期会通过Excel等方式手动导入。
## 优惠分类无法分拆
财务页要区分“团购优惠/大客户优惠/赠送卡抵扣/其他优惠”DWD 仅有 member_discount_amount / coupon_amount / adjust_amount / rounding_amount / gift_card_amount / recharge_card_amount 等汇总字段,且没有“大客户”标识或优惠原因维表,无法稳定拆分口径。
### 更新:
- 赠送卡抵扣 指的就是 酒水卡+台费卡+活动抵用券 结账 抵扣的。
- 团购优惠: ledger_amount + assistant_promotion_money - ledger_unit_price
- 大客户优惠和其他优惠就是手动调账产生的优惠订单中的折扣、台桌折扣、商品折扣、手动优惠这几项关系需要确认下找100个样本进行分析
## “发生额/正价”口径不清
- 结账记录中的正价: tableChargeMoney台费正价goodsMoney商品正价assistantPdMoney助教基础课正价assistantCxMoney助教激励课正价
- 团购中的正价ledger_amount(台桌正价) + assistant_promotion_money(助教正价)
- 团购中的核销价ledger_unit_price
## 区域/房型维度不规范
筛选要“大厅A/B/C、麻将房、团建房/包厢”DWD 只有 site_table_area_name 等自由文本,没有规范维表映射,容易导致前端筛选不可控。
### 更新
BD_manual_dim_table.md 中,有台区分布的对应关系
## 充值与赠送卡口径缺口
需求中“储值卡充值实收(首充/续费、不含赠送)”与“赠送卡新增/消费/余额”细分酒水卡/台费卡/抵用券。DWD 里 dwd_recharge_order 没有明确“赠送金额”字段dim_member_card_account / dwd_member_balance_change 仅有卡类型名称,缺少“是否赠送”“卡类别标准枚举”,需要补充规则/维表。
### 更新
- 酒水卡,台费卡活动抵用券,台费卡 是赠送卡 分类在dim_member_card_account 的card_type_id对应的数据库说明书中有介绍。
- 储值卡是充值的“现金卡”
## 助教薪酬规则未闭合
DWS 需求里“充值提成”空缺,且“冲刺奖/额外奖金”重复;没有助教工资/结算流水表,财务页“助教分成/奖惩”无法核算。
### 更新
- 充值提成数据库结构中预留后期会通过Excel等方式手动导入。会记录时间充值金额储值卡卡关联充值提成金额。
- “冲刺奖/额外奖金”重复:按照薪资说明进行相应调整。
- 没有助教工资/结算流水表:为我增加相应的表。满足业务逻辑。
## 时间分层与筛选不匹配
### 更新
- UI 需要“最近半年不含本月、上季度”等时间维度并且满足上葛周期的环比。DWS 分层仅到 3 个月,可能导致查询性能或需要额外聚合层。财务方面需要特殊处理。
## 缺失 DDL
方案里列出的表没有全部给出结构定义,包括 cfg_tier_effective_period、dws_assistant_salary_calc、dws_member_visit_detail、dws_finance_discount_detail、dws_finance_recharge_summary、dws_finance_expense_summary。这些在 DWS_任务计划_v1.md 中仅出现在清单里,但没有 DDL会导致实施阶段卡住。
### 更新
- 补全DLL。
## SCD2 维度取数口径
助教等级在 dws_assistant_monthly_summary 用了 SCD2_is_current=1这是否会把“当前等级”套到历史月份能否满足需求中的“历史月份”统计是否要加一些数据筛选条件是否需按业务时间点做 as-of join基于有效期
## 附加课/基础课口径
方案中用 skill_name 判断“超休/激励/打赏”为附加课但我希望换成skill_id进行枚举避免漏记或误记落在库中可以使用名称。
## 财务指标可追溯口径
dws_finance_daily_summary 已覆盖“发生额/优惠/确认收入/现金流/充值”等字段但缺少“数据来源矩阵”字段→DWD表→公式。财务需求对“发生额(正价)”和“优惠”拆分非常细,需明确“正价”来源(台费价、助教等级价、商品原价)与“优惠”拆分口径(团购差价、大客户折扣、赠送卡抵扣、免单/抹零、手动调整)。
### 更新
- 增加 数据来源矩阵,记录数据的来龙去脉
我觉得还不够全,给你一些我整理的内容。
# 1.2 DWD 核心表与关键字段
还差好多,举例:
## 助教服务相关:
dwd_assistant_service_log
| `order_assistant_type` | 服务类型 | 1=基础课或包厢课, 2=附加课/激励课 | 这个不重要用skill_id判断就好。
另外服务时keh长服务的助教ID与花名客户关联台桌号台桌分类关联等也很重要。
## 客户相关:
客户姓名手机号生日以及关联的会员卡。
## 财务:
还有从结账记录出发关联的台桌流水助教流水
结算路径
充值流水等。
以上是否要补充?
---------------
## 订单获取的字段更新
### 订单各项正价小计
- 台费正价table_charge_money
- 商品正价goods_money
- 助教基础课/陪打正价assistant_pd_money
- 助教激励课/超休正价assistant_cx_money
### 支付信息
- 会员卡支付金额recharge_card_amount。卡类型还要从dwd_settlement_head的order_settle_id 去dwd_member_balance_change表找到卡的类型。
- 收银实付pay_amount。
- 团购抵消的台费coupon_amount。
- 团购支付的金额2条路径若pl_coupon_sale_amount非0 则使用pl_coupon_sale_amount。若pl_coupon_sale_amount为0且coupon_amount不为0那么需要到dwd_groupbuy_redemption找到对应的订单的ledger_unit_price。
### 订单优惠与打折
- 台费打折adjust_amount
- 团购券优惠:团购抵消的台费 - 团购支付的金额
-----------------
单独任务:
大客户优惠;抹零;其他优惠 需要抽样分析,当作一个单独任务为我分析执行。
| **会员折扣** | dwd_settlement_head | `member_discount_amount` | 会员身份折扣 | 这个貌似没有启用过,也为我作为单独任务分析处理吧。。
---------------
时间分层机制需求明确“四层时间分层近2天/近1月/近3月/全量)”,方案只写了更新频率,需补齐具体实现(分区策略/分层表或物化汇总层/定期归档与清理作业)。
DDL 完整性:补充说明中提到缺失的表(如 cfg_tier_effective_period、dws_assistant_salary_calc、dws_member_visit_detail、dws_finance_discount_detail、dws_finance_recharge_summary、dws_finance_expense_summary需要在 schema_dws.sql 里落全方案里写了“更新DDL”但应明确完整DDL清单与字段级定义。
薪酬规则与生效期:档位、奖金、规则有“按月/按时间生效”的要求,方案目前只有 cfg_performance_tier/cfg_bonus_rules需要补充生效期字段或独立“规则生效期配置表”否则历史月份口径会错。
SCD2 / as-of 口径助教等级是SCD2维度历史月份不能直接用“当前等级”。方案需明确“按有效期 as-of join”的取数规则。
技能枚举规范:需求要求用 skill_id 判断基础课/附加课;方案应明确 skill_id→课程类型映射可用配置表避免 skill_name 漏记。
滚动区间统计:需求中明确 7/10/15/30/60/90 天窗口,方案未明确存储方式(建议在 dws_assistant_customer_stats、dws_member_consumption_summary 中直接落多窗口字段,或新增滚动汇总表)。
财务口径矩阵需全覆盖:方案已有“数据来源矩阵”,但需扩展至财务页面每一项指标(发生额/优惠拆分/确认收入/现金流/充值/平台回款/支出结构),确保每一项都有明确字段+公式+来源表。
手工导入表规范:支出/平台回款/充值提成的Excel导入要补“字段定义、时间粒度、门店维度、去重与校验规则”否则实现阶段会反复返工。
区域/房型维表:方案已有 cfg_area_category但需落地“具体映射规则 + 默认兜底 + 异常值处理”,并与 BD_manual_dim_table.md 一致。
# 更新
时间口径定义:本周/上周/本季度/上季度/最近半年不含本月 等窗口的“起止边界”为月第一天0点。周起始日为周一。
环比规则:开启对比时,是“对比上一个等长区间”相比。
有效业绩的排除规则:仅对“助教废除表”的记录进行处理排除。其影响绩效。
新入职定档规则月1日0点之后入住的计算为新入职。入职日以助教表入职时间为准。
Top3 奖金排名口径按绩效总小时数。如遇并列则都算比如2个第一则记为2个第一一个第三。
充值提成规则:比例/阶梯/时间口径缺失:通过手动导入表格,表格中会明确月份,提成关联充值订单金额和助教获得的提成金额。
大客户优惠/其他优惠划分规则:目前需要抽样分析。
平台回款/服务费口径:明确导入数据字段包含:回款金额、佣金、服务费、回款日期、平台类型、订单关联键。
散客处理member_id=0 的客户是散客。不进入客户维度统计。
门店/租户范围:现在只有一个门店,一个租户。

View File

@@ -0,0 +1,4 @@
API遵循 RESTful API 规范

9294
docs/开发笔记/记录1.md Normal file

File diff suppressed because it is too large Load Diff