# INDEX 层任务详解 > 本文档说明飞球 ETL 系统中 INDEX(指数算法层)的所有任务。 > INDEX 层基于 DWD/DWS 层数据,通过自定义算法计算业务指数, > 服务于会员运营(回流挽回、新客转化)和助教管理(关系归属、付费关联)等场景。 --- ## 概述 INDEX 层共有 4 个已注册任务: | 任务代码 | Python 类 | 目标表 | 指数类型 | 更新策略 | |----------|-----------|--------|----------|----------| | `DWS_WINBACK_INDEX` | `WinbackIndexTask` | `dws_member_winback_index` | WBI(回流指数) | delete-before-insert(按门店全量刷新) | | `DWS_NEWCONV_INDEX` | `NewconvIndexTask` | `dws_member_newconv_index` | NCI(新客转化指数) | delete-before-insert(按门店全量刷新) | | `DWS_RELATION_INDEX` | `RelationIndexTask` | `dws_member_assistant_relation_index` | RS/OS/MS/ML(关系指数) | delete-before-insert(按门店全量刷新) | | `DWS_ML_MANUAL_IMPORT` | `MlManualImportTask` | `dws_ml_manual_order_source` / `dws_ml_manual_order_alloc` | ML(手动台账导入) | 按 scope 先删后写 | > 注册位置:`orchestration/task_registry.py`,所有 INDEX 任务的 `requires_db_config=False`、`layer="INDEX"`。 --- ## BaseIndexTask 公共机制 `BaseIndexTask`(位于 `tasks/dws/index/base_index_task.py`)继承自 `BaseDwsTask`,为所有指数任务提供统一的算法基础设施。 ### 继承层次 ``` BaseTask └── BaseDwsTask └── BaseIndexTask ├── MemberIndexBaseTask ← WBI / NCI 共享的会员特征提取 │ ├── WinbackIndexTask │ └── NewconvIndexTask ├── RelationIndexTask ← RS/OS/MS/ML 四合一 └── MlManualImportTask ← ML 人工台账导入 ``` ### 子类必须实现的抽象方法 ```python def get_index_type(self) -> str: """返回指数类型标识,如 'WBI'、'NCI'、'RS'""" ``` ### 核心能力 #### 1. 半衰期时间衰减函数 所有指数共享的时间权重模型,核心思想是"越近越重要": ``` decay(d; h) = exp(-ln(2) × d / h) ``` | 参数 | 含义 | 示例 | |------|------|------| | `d` | 事件距今天数(≥0) | 7 天 | | `h` | 半衰期(>0),单位:天 | 7 天 | | 返回值 | 衰减权重,范围 (0, 1] | 0.5 | 当 `d = h` 时权重恰好衰减到 0.5;`d = 0` 时权重为 1.0。 #### 2. 分位数计算与截断(Winsorize) 用于消除极端值对归一化的影响: 1. 计算 P5 和 P95 分位点 2. 将所有 Raw Score 截断到 [P5, P95] 范围内 ```python calculate_percentiles(scores, lower=5, upper=95) → (P5, P95) winsorize(value, lower, upper) → clipped_value ``` #### 3. 0-10 归一化映射 将 Raw Score 映射到 0-10 分的 Display Score,便于业务理解和排序: ``` 映射流程:Raw Score → [可选压缩] → Winsorize(P5, P95) → MinMax(0, 10) ``` 压缩模式(由 `compression_mode` 参数控制): | compression_mode | 方式 | 公式 | 适用场景 | |------------------|------|------|----------| | 0 | 无压缩 | `y = x` | 分布较均匀时 | | 1 | log1p | `y = ln(1 + x)` | 右偏分布(默认) | | 2 | asinh | `y = asinh(x)` | 含负值或极端右偏 | 当所有分数几乎相同(`max - min < ε`)时,返回中间值 5.0。 #### 4. 算法参数加载 从 `billiards_dws.cfg_index_parameters` 表按 `index_type` 加载参数: - 按 `effective_from` 降序取最新生效的参数值 - 支持按 `index_type` 隔离的内存缓存(TTL = 300 秒) - 子类可通过 `get_param(name, default)` 获取单个参数 ```python load_index_parameters(index_type=None) → Dict[str, float] get_param(name, default=0.0, index_type=None) → float ``` #### 5. 分位点历史管理(EWMA 平滑) 为避免分位点在不同批次间剧烈波动,支持 EWMA(指数加权移动平均)平滑: ``` Q_t = (1 - α) × Q_{t-1} + α × Q_now ``` | 参数 | 含义 | 默认值 | |------|------|--------| | `α`(ewma_alpha) | 平滑系数,越大越跟随当前值 | 0.2 | | `Q_{t-1}` | 上一次平滑后的分位点 | 从 `dws_index_percentile_history` 表读取 | | `Q_now` | 当前批次计算的分位点 | 实时计算 | 首次计算时无历史记录,直接使用当前分位点(不平滑)。每次计算后将原始分位点和平滑分位点保存到 `dws_index_percentile_history` 表。 #### 6. 统计工具方法 | 方法 | 功能 | |------|------| | `calculate_median(values)` | 中位数 | | `calculate_mad(values)` | MAD(中位绝对偏差),比标准差更稳健 | | `safe_log(value)` | 安全对数(value ≤ 0 时返回默认值) | | `safe_ln1p(value)` | 安全的 `ln(1+x)` | --- ## MemberIndexBaseTask 会员指数共享基类 `MemberIndexBaseTask`(位于 `tasks/dws/index/member_index_base.py`)继承自 `BaseIndexTask`,为 WBI 和 NCI 提供共享的会员活动特征提取逻辑。 ### 会员活动特征(MemberActivityData) 从 DWD 层提取并计算的会员特征数据结构: | 字段 | 类型 | 含义 | |------|------|------| | `member_id` | int | 会员 ID | | `site_id` / `tenant_id` | int | 门店 / 租户 ID | | `member_create_time` | datetime | 会员建档时间 | | `first_visit_time` | datetime | 首次到店时间 | | `last_visit_time` | datetime | 最近到店时间 | | `last_recharge_time` | datetime | 最近充值时间 | | `t_v` | float | 距最近到店天数(截断到 recency 窗口) | | `t_r` | float | 距最近充值天数(截断到 recency 窗口) | | `t_a` | float | `min(t_v, t_r)`,综合活跃度 | | `visits_14d` / `visits_60d` / `visits_total` | int | 近 14 天 / 60 天 / 总到店次数 | | `spend_30d` / `spend_180d` | float | 近 30 天 / 180 天消费金额 | | `sv_balance` | float | 储值卡余额 | | `recharge_60d_amt` | float | 近 60 天充值金额 | | `intervals` | List[float] | 到店间隔天数序列 | | `interval_ages_days` | List[int] | 每个间隔对应的"年龄"(距今天数) | | `recharge_unconsumed` | int | 充值后是否未回访(1=是) | ### 数据来源 | 数据 | 来源表 | 提取方式 | |------|--------|----------| | 到店记录 | `billiards_dwd.dwd_settlement_head` | 按天去重,仅计入正常结账(settle_type=1)和激励课结账(settle_type=3 且关联 BONUS 技能) | | 充值记录 | `billiards_dwd.dwd_recharge_order` | settle_type=5,近 recency_days 天 | | 会员建档时间 | `billiards_dwd.dim_member` | scd2_is_current=1 | | 首次到店时间 | `billiards_dwd.dwd_settlement_head` | 全量 MIN(pay_time) | | 储值卡余额 | `billiards_dwd.dim_member_card_account` | 按 card_type_id 筛选现金卡 | > 会员 ID 规范化:优先使用 `member_id`,若为 0 则通过 `dim_member_card_account` 关联取 `tenant_member_id`。 ### 会员分群(classify_segment) WBI 和 NCI 共享的三分群逻辑,决定会员进入哪个指数的计算范围: | 分群 | 条件 | 进入指数 | |------|------|----------| | **STOP** | `t_a ≥ recency_days`(默认 60 天无活动) | 不参与评分(除 STOP_HIGH_BALANCE 例外) | | **NEW** | 满足以下任一:到店 ≤ 2 次、首访 ≤ 30 天、近期充值未回访 | NCI | | **OLD** | 不满足 STOP 和 NEW 条件 | WBI | STOP_HIGH_BALANCE 例外:当 `enable_stop_high_balance_exception=1` 且储值余额 ≥ `high_balance_threshold`(默认 1000 元)时,STOP 会员仍参与 WBI 评分。 --- ## DWS_WINBACK_INDEX — 老客挽回指数(WBI) | 属性 | 值 | |------|-----| | 任务代码 | `DWS_WINBACK_INDEX` | | Python 类 | `WinbackIndexTask`(`tasks/dws/index/winback_index_task.py`) | | 继承链 | `BaseTask → BaseDwsTask → BaseIndexTask → MemberIndexBaseTask → WinbackIndexTask` | | 目标表 | `billiards_dws.dws_member_winback_index` | | 主键 | `site_id, member_id` | | 指数类型 | `WBI` | | 更新策略 | 按门店全量刷新(先 DELETE WHERE site_id = %s,再 INSERT) | ### 业务含义 WBI 衡量老客的"挽回紧急度"——分数越高,表示该会员越需要运营人员主动触达。适用于已有多次到店记录但近期活跃度下降的老客群体。 ### 计算范围 仅对 `segment = "OLD"` 或 `status = "STOP_HIGH_BALANCE"` 的会员计算。 ### 算法概要 WBI Raw Score 由 4 个分项加权求和,再乘以近期抑制系数: ``` WBI_raw = suppression × (w_over × Overdue + w_drop × Drop + w_re × Recharge + w_value × Value) ``` #### 分项 1:超期紧急性(Overdue) 基于会员个人历史到店间隔的加权经验 CDF,衡量当前缺席天数的异常程度: 1. 收集会员历史到店间隔序列 `{interval_i, age_i}` 2. 计算加权 CDF:`P(interval ≤ t_v)`,权重按间隔年龄半衰期衰减 3. 对小样本混合等权分布与加权分布(`λ = min(1, N / blend_min_samples)`) 4. `Overdue = P^α`(α 默认 2.0,放大高概率区间的紧急性) 同时计算理想到店间隔(加权中位数),用于推算 `ideal_next_visit_date`。 #### 分项 2:降频分(Drop) 检测近期到店频率是否低于历史均值: ``` expected_14d = visits_60d × 14 / 60 Drop = clip((expected_14d - visits_14d) / (expected_14d + 1), 0, 1) ``` #### 分项 3:充值未回访压力(Recharge) 若会员充值后未回访(`recharge_unconsumed = 1`),按充值距今天数衰减: ``` Recharge = decay(t_r, h_recharge) # h_recharge 默认 7 天 ``` #### 分项 4:价值分(Value) 综合消费金额和储值余额的对数压缩: ``` Value = w_spend × ln(1 + spend_180d / M0) + w_bal × ln(1 + sv_balance / B0) ``` | 参数 | 默认值 | 含义 | |------|--------|------| | `M0` (amount_base_M0) | 300 | 消费金额压缩基准 | | `B0` (balance_base_B0) | 500 | 余额压缩基准 | #### 近期抑制(Suppression) 防止刚到店的会员获得高分,使用 Sigmoid 门控: ``` suppression = σ((t_v - gate_days) / slope_days) ``` - 当 `t_v < hard_floor_days`(默认 14 天)时,`suppression = 0`(完全抑制) - 当 `t_v` 远大于 `gate_days` 时,`suppression → 1`(不抑制) ### 默认权重 | 参数 | 默认值 | 含义 | |------|--------|------| | `w_over` | 2.0 | 超期紧急性权重 | | `w_drop` | 1.0 | 降频权重 | | `w_re` | 0.4 | 充值压力权重 | | `w_value` | 1.2 | 价值权重 | --- ## DWS_NEWCONV_INDEX — 新客转化指数(NCI) | 属性 | 值 | |------|-----| | 任务代码 | `DWS_NEWCONV_INDEX` | | Python 类 | `NewconvIndexTask`(`tasks/dws/index/newconv_index_task.py`) | | 继承链 | `BaseTask → BaseDwsTask → BaseIndexTask → MemberIndexBaseTask → NewconvIndexTask` | | 目标表 | `billiards_dws.dws_member_newconv_index` | | 主键 | `site_id, member_id` | | 指数类型 | `NCI` | | 更新策略 | 按门店全量刷新(先 DELETE WHERE site_id = %s,再 INSERT) | ### 业务含义 NCI 衡量新客的"转化紧迫度"——分数越高,表示该新客越需要及时跟进以促成二访/三访。适用于首次到店不久或到店次数较少的新客群体。 ### 计算范围 仅对 `segment = "NEW"` 的会员计算。 ### 算法概要 NCI 由两部分组成:欢迎建联分(Welcome)和转化召回分(Convert),合并为总分: ``` NCI_raw = raw_score_welcome + raw_score_convert ``` #### 欢迎建联分(Welcome) 针对首访后 3 天内的会员,鼓励立即触达: ``` welcome_new = clip(1 - t_v / welcome_window_days, 0, 1) # 仅 visits_total ≤ 1 时生效 raw_score_welcome = w_welcome × welcome_new ``` #### 转化召回分(Convert) 由 4 个分项加权组成,并受活跃度抑制: ``` raw_score_convert = active_multiplier × ( w_need × (Need × Salvage) + w_re × Recharge × touch_multiplier + w_value × Value × touch_multiplier ) ``` ##### 分项 1:紧迫度(Need) 衡量距二访目标窗口的紧迫程度: ``` Need = clip((t_v - no_touch_days) / (2 × t2_target_days - no_touch_days), 0, 1) ``` - `no_touch_days`(默认 3 天):免打扰窗口,首访后短期内不催促 - `t2_target_days`(默认 7 天):二访目标天数 ##### 分项 2:挽救系数(Salvage) 30-60 天线性衰减,超过 60 天视为流失: ``` Salvage = clip((salvage_end - t_a) / (salvage_end - salvage_start), 0, 1) ``` ##### 分项 3:充值未回访压力(Recharge) 与 WBI 相同:`Recharge = decay(t_r, h_recharge)` ##### 分项 4:价值分(Value) 与 WBI 相同:`Value = w_spend × ln(1 + spend_180d / M0) + w_bal × ln(1 + sv_balance / B0)` #### 活跃新客抑制 近期高频到店的新客不需要催促,降低其排名权重: ``` 若 visits_14d ≥ active_new_visit_threshold_14d 且 t_v ≤ active_new_recency_days: active_multiplier = active_new_penalty (默认 0.2) 否则: active_multiplier = 1.0 ``` #### 免打扰窗口乘数 价值分和充值分在进入免打扰窗口后才逐步生效: ``` touch_multiplier = clip(t_v / no_touch_days, 0, 1) ``` ### Display Score 归一化 NCI 产出 3 个 Display Score: - `display_score`:总分归一化(使用 EWMA 平滑) - `display_score_welcome`:欢迎分归一化(不平滑) - `display_score_convert`:转化分归一化(不平滑) ### 默认权重 | 参数 | 默认值 | 含义 | |------|--------|------| | `w_welcome` | 1.0 | 欢迎建联权重 | | `w_need` | 1.6 | 紧迫度权重 | | `w_re` | 0.8 | 充值压力权重 | | `w_value` | 1.0 | 价值权重 | --- ## DWS_RELATION_INDEX — 关系指数(RS/OS/MS/ML) | 属性 | 值 | |------|-----| | 任务代码 | `DWS_RELATION_INDEX` | | Python 类 | `RelationIndexTask`(`tasks/dws/index/relation_index_task.py`) | | 继承链 | `BaseTask → BaseDwsTask → BaseIndexTask → RelationIndexTask` | | 目标表 | `billiards_dws.dws_member_assistant_relation_index` | | 主键 | `site_id, member_id, assistant_id` | | 指数类型 | RS / OS / MS / ML(单任务产出四个子指数) | | 更新策略 | 按门店全量刷新(先 DELETE WHERE site_id = %s,再 INSERT) | ### 业务含义 关系指数以"会员-助教"关系对为粒度,一次执行产出 4 个子指数: | 子指数 | 全称 | 含义 | |--------|------|------| | **RS** | Relation Strength | 关系强度——衡量会员与助教之间的服务关系紧密程度 | | **OS** | Ownership Share | 归属份额——确定会员的"主责助教"归属关系 | | **MS** | Momentum Score | 升温动量——衡量关系是在升温还是降温 | | **ML** | Money Link | 付费关联——基于人工台账的付费归因强度 | ### 数据来源 | 数据 | 来源表 | 说明 | |------|--------|------| | 服务记录 | `billiards_dwd.dwd_assistant_service_log` | RS/MS 的核心数据源 | | 助教维度 | `billiards_dwd.dim_assistant` | 通过 user_id 关联获取 assistant_id | | 人工台账 | `billiards_dws.dws_ml_manual_order_alloc` | ML 的唯一数据源 | ### 会话合并 服务记录按 `(member_id, assistant_id)` 分组后,相邻服务间隔 ≤ `session_merge_hours`(默认 4 小时)的记录合并为一个会话(ServiceSession)。合并后保留: - 会话起止时间、总时长 - 课程权重(激励课 `course_weight = incentive_weight`,默认 1.5;普通课 = 1.0) - 是否包含激励课标记 ### 子指数 1:RS(关系强度) ``` RS_raw = (w_f × F + w_d × D) × Gate(R) ``` | 分项 | 公式 | 含义 | |------|------|------| | F(频次) | `Σ course_weight × decay(days_ago, halflife_session)` | 加权会话频次 | | D(时长) | `Σ √(duration_min / 60) × course_weight × decay(days_ago, halflife_session)` | 加权服务时长 | | R(近期性) | `decay(days_since_last_session, halflife_last)` | 最近一次服务的时间衰减 | | Gate | `R^gate_alpha` | 近期性门控,无近期服务则整体压低 | 默认参数:`halflife_session=14`, `halflife_last=10`, `w_f=1.0`, `w_d=0.7`, `gate_alpha=0.6` ### 子指数 2:OS(归属份额) OS 不是独立计算的 Raw Score,而是基于 RS_raw 的份额分配: 1. 筛选 `rs_raw ≥ min_rs_raw_for_ownership`(默认 0.05)的关系对 2. 计算份额:`os_share = rs_raw / Σ rs_raw`(同一会员下所有合格助教) 3. 若 `Σ rs_raw < min_total_rs_raw`(默认 0.10),标记为 `UNASSIGNED` 归属标签判定规则: | 标签 | 条件 | |------|------| | `MAIN` | 第一名份额 ≥ `ownership_main_threshold`(0.60)且与第二名差距 ≥ `ownership_gap_threshold`(0.15) | | `COMANAGE` | 份额 ≥ `ownership_comanage_threshold`(0.35)但不满足 MAIN 条件 | | `POOL` | 其余合格关系对 | | `UNASSIGNED` | 总 RS 不足,无法形成稳定归属 | ### 子指数 3:MS(升温动量) 衡量关系是在升温(MS > 0)还是降温(MS ≈ 0): ``` f_short = Σ course_weight × decay(days_ago, halflife_short) # 短期半衰期 7 天 f_long = Σ course_weight × decay(days_ago, halflife_long) # 长期半衰期 30 天 MS_raw = max(0, ln(f_short + ε) / (f_long + ε)) ``` 短期频次高于长期频次时 MS 为正,表示关系在升温。 ### 子指数 4:ML(付费关联) 以人工台账窄表(`dws_ml_manual_order_alloc`)为唯一数据源: ``` ML_raw = Σ ln(1 + allocated_amount / amount_base) × decay(days_ago, halflife_recharge) ``` | 参数 | 默认值 | 含义 | |------|--------|------| | `amount_base` | 500 | 金额压缩基准 | | `halflife_recharge` | 21 天 | 充值半衰期 | 若某 `(member_id, assistant_id)` 对仅在台账中出现而无服务记录,会自动创建关系对。 ### Display Score 归一化 RS、MS、ML 各自独立归一化到 0-10 分,分位历史按 `index_type` 隔离(分别记录 RS/MS/ML 的分位点)。OS 不做归一化,直接输出份额和标签。 --- ## DWS_ML_MANUAL_IMPORT — ML 人工台账导入 | 属性 | 值 | |------|-----| | 任务代码 | `DWS_ML_MANUAL_IMPORT` | | Python 类 | `MlManualImportTask`(`tasks/dws/index/ml_manual_import_task.py`) | | 继承链 | `BaseTask → BaseDwsTask → BaseIndexTask → MlManualImportTask` | | 目标表 | `billiards_dws.dws_ml_manual_order_source`(宽表)+ `billiards_dws.dws_ml_manual_order_alloc`(窄表) | | 主键 | 宽表:`site_id, external_id, import_scope_key, row_no`;窄表:`site_id, external_id, assistant_id` | | 指数类型 | `ML` | | 更新策略 | 按 scope 先删后写(DAY 或 P30 批次覆盖) | ### 业务含义 ML 人工台账导入是一个工具型任务,用于将运营人员手工整理的订单-助教归因数据导入系统。导入后的数据作为 `DWS_RELATION_INDEX` 任务中 ML 子指数的唯一数据源。 该任务不依赖时间窗口,由调度器以工具任务方式直接触发。 ### 文件路径解析 按以下优先级查找台账文件: 1. 配置项 `run.ml_manual_ledger_file` 2. 配置项 `run.ml_manual_file` 3. 环境变量 `ML_MANUAL_LEDGER_FILE` ### Excel 模板格式 台账文件为 `.xlsx` 格式,第一行为表头,第二行起为数据。模板列定义: | 列名 | 类型 | 必填 | 说明 | |------|------|------|------| | `site_id` | int | 否(默认取配置) | 门店 ID | | `biz_date` | date | 是 | 业务日期 | | `external_id` | string | 是 | 外部订单 ID(唯一标识) | | `member_id` | int | 否 | 会员 ID | | `pay_time` | datetime | 否(默认取 biz_date) | 支付时间 | | `order_amount` | decimal | 否 | 订单金额 | | `currency` | string | 否(默认 CNY) | 币种 | | `assistant_id_1` ~ `assistant_id_5` | int | 否 | 助教 ID(最多 5 个) | | `assistant_name_1` ~ `assistant_name_5` | string | 否 | 助教姓名 | | `remark` | string | 否 | 备注 | ### 导入逻辑 #### 1. 读取与规范化 - 使用 `openpyxl` 读取 Excel,跳过空行 - 每行规范化:类型转换、缺省值填充、助教列表提取 - `external_id` 为必填,缺失则抛出 `ValueError` #### 2. 助教分摊 同一订单支持最多 5 个助教归因,默认均分: ``` share_ratio = 1 / N allocated_amount = order_amount × share_ratio ``` #### 3. 覆盖策略(ImportScope) 根据 `biz_date` 与当前日期的距离,采用不同的覆盖粒度: | 条件 | scope_type | 覆盖范围 | 说明 | |------|------------|----------|------| | `today - biz_date ≤ 30 天` | `DAY` | 单日 | 按 `site_id + biz_date` 日覆盖 | | `today - biz_date > 30 天` | `P30` | 30 天批次 | 以固定纪元(2026-01-01)为锚点,按 30 天分桶 | P30 分桶算法: ``` bucket_index = (biz_date - EPOCH_ANCHOR).days // 30 bucket_start = EPOCH_ANCHOR + bucket_index × 30 天 bucket_end = bucket_start + 29 天 ``` #### 4. 写入流程 1. 按 scope 删除旧数据(宽表 + 窄表) 2. 插入宽表(`dws_ml_manual_order_source`) 3. Upsert 窄表(`dws_ml_manual_order_alloc`),冲突键为 `(site_id, external_id, assistant_id)` 4. 提交事务 #### 5. 导入批次号 格式:`MLM__`,如 `MLM_20260215143022_a1b2c3d4` 导入用户按优先级取:环境变量 `ETL_OPERATOR` → `USERNAME` → `USER` → `"system"` --- ## cfg_index_parameters 配置表 所有指数任务的算法参数统一存储在 `billiards_dws.cfg_index_parameters` 表中,支持按时间生效和历史追溯。 ### 表结构 | 字段 | 类型 | 说明 | |------|------|------| | `param_id` | SERIAL PK | 自增主键 | | `index_type` | VARCHAR(50) NOT NULL | 指数类型:`RS` / `OS` / `MS` / `ML` / `NCI` / `WBI` | | `param_name` | VARCHAR(100) NOT NULL | 参数名称 | | `param_value` | NUMERIC(14,6) NOT NULL | 参数值 | | `description` | TEXT | 参数说明 | | `effective_from` | DATE NOT NULL | 生效起始日期(默认当天) | | `effective_to` | DATE | 生效截止日期(NULL = 永久有效) | | `created_at` | TIMESTAMPTZ | 创建时间 | | `updated_at` | TIMESTAMPTZ | 更新时间 | 唯一约束:`(index_type, param_name, effective_from)` 索引:`idx_cfg_index_params_type`(index_type)、`idx_cfg_index_params_effective`(effective_from, effective_to) ### 参数加载逻辑 ```sql SELECT param_name, param_value FROM billiards_dws.cfg_index_parameters WHERE index_type = %s AND effective_from <= CURRENT_DATE AND (effective_to IS NULL OR effective_to >= CURRENT_DATE) ORDER BY effective_from DESC ``` 同一 `param_name` 若有多条生效记录,取 `effective_from` 最新的一条(代码中通过 `seen` 集合去重)。 ### 参数调优方式 新增一条 `effective_from` 为新日期的记录即可覆盖旧参数,旧记录自动失效(无需删除)。如需回滚,将新记录的 `effective_to` 设为过去日期即可。 ### WBI 参数清单 | 参数名 | 默认值 | 说明 | |--------|--------|------| | `lookback_days_recency` | 60 | 近期活跃判定窗口(天) | | `visit_lookback_days` | 180 | 到店记录回溯窗口(天) | | `percentile_lower` / `percentile_upper` | 5 / 95 | 归一化分位点 | | `compression_mode` | 0 | 压缩模式(0=无/1=log1p/2=asinh) | | `use_smoothing` | 1 | 是否启用 EWMA 分位平滑 | | `ewma_alpha` | 0.2 | EWMA 平滑系数 | | `new_visit_threshold` | 2 | 新客到店次数阈值 | | `new_days_threshold` | 30 | 新客首访天数阈值 | | `recharge_recent_days` | 14 | 近期充值窗口(天) | | `new_recharge_max_visits` | 10 | 充值新客最大到店次数 | | `overdue_alpha` | 2.0 | 超期 CDF 幂指数 | | `overdue_weight_halflife_days` | 30 | 超期加权 CDF 间隔半衰期(天) | | `overdue_weight_blend_min_samples` | 8 | 加权 CDF 最小样本数 | | `h_recharge` | 7 | 充值衰减半衰期(天) | | `amount_base_M0` | 300 | 消费金额压缩基准 | | `balance_base_B0` | 500 | 余额压缩基准 | | `value_w_spend` / `value_w_bal` | 1.0 / 1.0 | 价值分中消费/余额权重 | | `w_over` / `w_drop` / `w_re` / `w_value` | 2.0 / 1.0 / 0.4 / 1.2 | 四分项权重 | | `recency_hard_floor_days` | 14 | 近期硬抑制天数 | | `recency_gate_days` | 14 | Sigmoid 门控中心(天) | | `recency_gate_slope_days` | 3 | Sigmoid 门控斜率(天) | | `enable_stop_high_balance_exception` | 0 | 是否启用 STOP 高余额例外 | | `high_balance_threshold` | 1000 | 高余额阈值(元) | ### NCI 参数清单 | 参数名 | 默认值 | 说明 | |--------|--------|------| | `lookback_days_recency` | 60 | 近期活跃判定窗口(天) | | `visit_lookback_days` | 180 | 到店记录回溯窗口(天) | | `percentile_lower` / `percentile_upper` | 5 / 95 | 归一化分位点 | | `compression_mode` | 0 | 压缩模式 | | `use_smoothing` | 1 | 是否启用 EWMA 分位平滑 | | `ewma_alpha` | 0.2 | EWMA 平滑系数 | | `no_touch_days_new` | 3 | 免打扰窗口(天) | | `t2_target_days` | 7 | 二访目标天数 | | `salvage_start` / `salvage_end` | 30 / 60 | 挽救系数衰减区间(天) | | `welcome_window_days` | 3 | 欢迎建联窗口(天) | | `active_new_visit_threshold_14d` | 2 | 活跃新客 14 天到店阈值 | | `active_new_recency_days` | 7 | 活跃新客近期天数 | | `active_new_penalty` | 0.2 | 活跃新客抑制系数 | | `h_recharge` | 7 | 充值衰减半衰期(天) | | `amount_base_M0` / `balance_base_B0` | 300 / 500 | 价值分压缩基准 | | `value_w_spend` / `value_w_bal` | 1.0 / 0.8 | 价值分权重 | | `w_welcome` / `w_need` / `w_re` / `w_value` | 1.0 / 1.6 / 0.8 / 1.0 | 分项权重 | ### RS 参数清单 | 参数名 | 默认值 | 说明 | |--------|--------|------| | `lookback_days` | 60 | 服务行为回溯窗口(天) | | `session_merge_hours` | 4 | 会话合并阈值(小时) | | `incentive_weight` | 1.5 | 激励课权重 | | `halflife_session` | 14 | 会话半衰期(天) | | `halflife_last` | 10 | 最近服务半衰期(天) | | `weight_f` / `weight_d` | 1.0 / 0.7 | 频次/时长权重 | | `gate_alpha` | 0.6 | 近期性门控指数 | | `percentile_lower` / `percentile_upper` | 5 / 95 | 归一化分位点 | | `compression_mode` | 1 | 压缩模式(默认 log1p) | | `use_smoothing` / `ewma_alpha` | 1 / 0.2 | EWMA 平滑 | ### OS 参数清单 | 参数名 | 默认值 | 说明 | |--------|--------|------| | `min_rs_raw_for_ownership` | 0.05 | 参与归属计算的最小 RS_raw | | `min_total_rs_raw` | 0.10 | 形成稳定归属的最小 sum_rs | | `ownership_main_threshold` | 0.60 | 主责份额阈值 | | `ownership_comanage_threshold` | 0.35 | 共管份额阈值 | | `ownership_gap_threshold` | 0.15 | 主责与次席差距阈值 | | `eps` | 0.000001 | 数值稳定项 | ### MS 参数清单 | 参数名 | 默认值 | 说明 | |--------|--------|------| | `lookback_days` | 60 | 服务行为回溯窗口(天) | | `session_merge_hours` | 4 | 会话合并阈值(小时) | | `incentive_weight` | 1.5 | 激励课权重 | | `halflife_short` / `halflife_long` | 7 / 30 | 短期/长期半衰期(天) | | `eps` | 0.000001 | 数值稳定项 | | `percentile_lower` / `percentile_upper` | 5 / 95 | 归一化分位点 | | `compression_mode` | 1 | 压缩模式(默认 log1p) | | `use_smoothing` / `ewma_alpha` | 1 / 0.2 | EWMA 平滑 | ### ML 参数清单 | 参数名 | 默认值 | 说明 | |--------|--------|------| | `lookback_days` | 60 | 充值行为回溯窗口(天) | | `amount_base` | 500 | 金额压缩基准 | | `halflife_recharge` | 21 | 充值半衰期(天) | | `percentile_lower` / `percentile_upper` | 5 / 95 | 归一化分位点 | | `compression_mode` | 1 | 压缩模式(默认 log1p) | | `use_smoothing` / `ewma_alpha` | 1 / 0.2 | EWMA 平滑 | > 种子数据脚本:`database/seed_index_parameters.sql` > DDL 定义:`database/schema_dws.sql`(第 21 节)