Browse Source

feat: 尾号实验探查 SQL 沉淀 + 召回策略效果新任务 + fetch_daily 异表头合并

- base_all_new_v3_分层: ab/34/5d 0425/0430 切桶映射更新;新增 exp_rov_combined_diff 复合指标(曝光×ROV 联动)
- fetch_daily: merge_csv_files 改为两遍扫描,自动按列名对齐不同表头(新增列空值填充)
- 新增 tasks/00_尾号实验/ 探查 SQL:ARP×flowpool/人均曝光/头部曝光占比/视频重合度
- 新增 策略打分诊断/ 子目录:scoresmap 字段全集与覆盖率、策略阶段分数 panel、策略调权底层/简表、阈值分布
- 新增 线上实验配置/:apollo 权重 v562/563/565/566/839 + 流量配置 20260425
- 新增 tasks/召回策略效果/base.sql:社交 i2i 召回 vs 对照组分页面拆分
- .gitignore 增补 .env / .claude/ / *.egg-info/ / logs/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
yangxiaohui 1 week ago
parent
commit
e0f42d3b32
26 changed files with 3575 additions and 17 deletions
  1. 4 0
      .gitignore
  2. 35 14
      fetch_daily.py
  3. 12 3
      tasks/00_尾号实验/base_all_new_v3_分层.sql
  4. 193 0
      tasks/00_尾号实验/探查_ARP按flowpool拆解.sql
  5. 10 0
      tasks/00_尾号实验/探查_人均曝光拆解.json
  6. 223 0
      tasks/00_尾号实验/探查_人均曝光拆解.sql
  7. 199 0
      tasks/00_尾号实验/探查_人均曝光按用户分级.sql
  8. 189 0
      tasks/00_尾号实验/探查_头部视频曝光占比.sql
  9. 124 0
      tasks/00_尾号实验/探查_视频重合度.sql
  10. 20 0
      tasks/00_尾号实验/策略打分诊断/探查_scoresmap字段全集.sql
  11. 51 0
      tasks/00_尾号实验/策略打分诊断/探查_scoresmap字段按尾号桶覆盖率.sql
  12. 6 0
      tasks/00_尾号实验/策略打分诊断/策略打分阈值分布.json
  13. 268 0
      tasks/00_尾号实验/策略打分诊断/策略打分阈值分布.sql
  14. 317 0
      tasks/00_尾号实验/策略打分诊断/策略打分阈值分布_统一字段.sql
  15. 374 0
      tasks/00_尾号实验/策略打分诊断/策略调权底层表.sql
  16. 6 0
      tasks/00_尾号实验/策略打分诊断/策略调权简表.json
  17. 283 0
      tasks/00_尾号实验/策略打分诊断/策略调权简表.sql
  18. 10 0
      tasks/00_尾号实验/策略打分诊断/策略阶段分数panel.json
  19. 959 0
      tasks/00_尾号实验/策略打分诊断/策略阶段分数panel.sql
  20. 37 0
      tasks/00_尾号实验/线上实验配置/流量配置/20260425.json
  21. 15 0
      tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv562.json
  22. 17 0
      tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv563.json
  23. 15 0
      tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv565.json
  24. 15 0
      tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv566.json
  25. 15 0
      tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv839.json
  26. 178 0
      tasks/召回策略效果/base.sql

+ 4 - 0
.gitignore

@@ -3,3 +3,7 @@ __pycache__/
 output/
 .DS_Store
 .venv/
+.env
+.claude/
+*.egg-info/
+logs/

+ 35 - 14
fetch_daily.py

@@ -61,7 +61,7 @@ def get_existing_dates(daily_dir, hh=None):
 
 
 def merge_csv_files(daily_dir, output_file=None):
-    """合并目录下所有日期 CSV 文件,只保留一个表头"""
+    """合并目录下所有日期 CSV 文件,自动对齐不同表头(新增列用空值填充)"""
     csv_files = sorted(daily_dir.glob("*.csv"))
     if not csv_files:
         print("没有找到 CSV 文件")
@@ -70,25 +70,46 @@ def merge_csv_files(daily_dir, output_file=None):
     if output_file is None:
         output_file = daily_dir.parent / f"{daily_dir.name}_merged.csv"
 
-    with open(output_file, "w", encoding="utf-8") as out:
-        header_written = False
+    # 第一遍:收集所有列名,按首次出现顺序保留
+    all_columns = []
+    col_set = set()
+    for csv_file in csv_files:
+        with open(csv_file, "r", encoding="utf-8") as f:
+            reader = csv.reader(f)
+            try:
+                file_header = next(reader)
+            except StopIteration:
+                continue
+            for col in file_header:
+                if col not in col_set:
+                    all_columns.append(col)
+                    col_set.add(col)
+
+    if not all_columns:
+        print("没有找到有效的表头")
+        return None
+
+    # 第二遍:按统一表头写出数据
+    with open(output_file, "w", encoding="utf-8", newline="") as out:
+        writer = csv.writer(out)
+        writer.writerow(all_columns)
         total_rows = 0
 
         for csv_file in csv_files:
-            with open(csv_file, "r", encoding="utf-8") as f:
-                lines = f.readlines()
-                if not lines:
+            with open(csv_file, "r", encoding="utf-8", newline="") as f:
+                reader = csv.reader(f)
+                try:
+                    file_header = next(reader)
+                except StopIteration:
                     continue
-
-                if not header_written:
-                    out.write(lines[0])
-                    header_written = True
-
-                for line in lines[1:]:
-                    out.write(line)
+                # 构建当前文件列名 → 索引的映射
+                col_index = {col: i for i, col in enumerate(file_header)}
+                for row in reader:
+                    aligned_row = [row[col_index[col]] if col in col_index and col_index[col] < len(row) else "" for col in all_columns]
+                    writer.writerow(aligned_row)
                     total_rows += 1
 
-    print(f"合并完成: {len(csv_files)} 个文件, {total_rows} 行数据")
+    print(f"合并完成: {len(csv_files)} 个文件, {total_rows} 行数据, {len(all_columns)} 列")
     print(f"输出文件: {output_file}")
     return output_file
 

+ 12 - 3
tasks/00_尾号实验/base_all_new_v3_分层.sql

@@ -68,14 +68,18 @@ WITH t_suffix_group AS
     -- ── apptype = 0 ──────────────────────────────────────────────────
     UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验 有问题", "20260413", "20260415"
     UNION ALL SELECT "0", "ab", "实验组:DNN模型-调参", "20260416", "20260416"
-    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "20260429"
+    UNION ALL SELECT "0", "ab", "实验组:DNN模型-调参", "20260430", "29991231"
     UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
     UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
     UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
     UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
     UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
     UNION ALL SELECT "0", "34", "实验组:DNN模型-调参", "20260416", "20260416"
-    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260417", "20260424"
+    UNION ALL SELECT "0", "34", "实验组:曝光建模v1+变更str*ros建模目标实验", "20260425", "20260425"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260426", "20260429"
+    UNION ALL SELECT "0", "34", "实验组:DNN模型-调参", "20260430", "29991231"
     UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
     UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
     UNION ALL SELECT "0", "67", "实验组:DNN模型-调参", "20260416", "20260416"
@@ -83,7 +87,8 @@ WITH t_suffix_group AS
     UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
     UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
     UNION ALL SELECT "0", "5d", "实验组:DNN模型-调参", "20260416", "20260416"
-    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260417", "20260424"
+    UNION ALL SELECT "0", "5d", "实验组:曝光建模v1+DNN模型", "20260425", "29991231"
     UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
     UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
     UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
@@ -709,6 +714,10 @@ SELECT  r.dt
         -- ── 横向对比:当日各桶 vs 基线桶(89),公式 = 当前值 / 基线值 - 1 ──
         ,ROUND(r.dau_vs_5d / NULLIF(ctrl.ctrl_dau_vs_5d, 0) - 1, 6) AS dau_vs_5d_diff
         ,ROUND(r.exp / NULLIF(ctrl.ctrl_exp, 0) - 1, 6) AS exp_diff
+        -- 复合指标:曝光量变化 × ROV变化 的联动效果
+        ,ROUND((1 + r.exp_per_dau / NULLIF(ctrl.ctrl_exp_per_dau, 0) - 1)
+             * (1 + r.total_rov / NULLIF(ctrl.ctrl_total_rov, 0) - 1)
+             - 1, 6) AS exp_rov_combined_diff
         ,ROUND(r.exp_per_dau / NULLIF(ctrl.ctrl_exp_per_dau, 0) - 1, 6) AS exp_per_dau_diff
         ,ROUND(r.str_one / NULLIF(ctrl.ctrl_str_one, 0) - 1, 6) AS str_one_diff
         ,ROUND(r.ros_one / NULLIF(ctrl.ctrl_ros_one, 0) - 1, 6) AS ros_one_diff

+ 193 - 0
tasks/00_尾号实验/探查_ARP按flowpool拆解.sql

@@ -0,0 +1,193 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- ARP 按 flowpool 拆解:看各流量池的曝光占比和平均热度变化
+-- 基于 base_all_new_v3_分层 精简
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT "a" AS suffix, "ab" AS suffix_group
+    UNION ALL SELECT "b", "ab"
+    UNION ALL SELECT "0", "01"
+    UNION ALL SELECT "1", "01"
+    UNION ALL SELECT "2", "2c"
+    UNION ALL SELECT "c", "2c"
+    UNION ALL SELECT "3", "34"
+    UNION ALL SELECT "4", "34"
+    UNION ALL SELECT "5", "5d"
+    UNION ALL SELECT "d", "5d"
+    UNION ALL SELECT "6", "67"
+    UNION ALL SELECT "7", "67"
+    UNION ALL SELECT "8", "89"
+    UNION ALL SELECT "9", "89"
+    UNION ALL SELECT "e", "ef"
+    UNION ALL SELECT "f", "ef"
+)
+,t_experiment_map AS
+(
+    -- ── apptype = 4 ──────────────────────────────────────────────────
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验 有问题" AS abcode, "20260413" AS start_dt, "20260415" AS end_dt
+    UNION ALL SELECT "4", "ab", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:bn_ros新损失函数",        "20260311", "20260319"
+    UNION ALL SELECT "4", "5d", "实验组:解构特征排序str模型",     "20260314", "20260406"
+    UNION ALL SELECT "4", "ef", "实验组:解构特征排序str模型&召回", "20260314", "20260320"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "299991231"
+
+    -- ── apptype = 0 ──────────────────────────────────────────────────
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验 有问题", "20260413", "20260415"
+    UNION ALL SELECT "0", "ab", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "34", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "67", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "5d", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+,t_base AS
+(
+    SELECT  sub.*
+            ,sg.suffix_group
+            ,COALESCE(m.abcode,"对照组") AS abcode
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,a.mid
+                        ,a.vid
+                        ,flowpool
+                FROM    loghubods.dwd_recsys_alg_exposure_base_20250108 a
+                WHERE   dt="${dt}"
+                AND     apptype IN ("0","4")
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     (apptype = "4"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                AND     (apptype = "0"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+            ) sub
+    INNER JOIN t_suffix_group sg
+    ON      sub.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+    ON      sub.apptype = m.apptype
+    AND     sg.suffix_group = m.suffix_group
+    AND     '${dt}' BETWEEN m.start_dt AND m.end_dt
+)
+-- 全局视频热度(不分桶,作为 popularity reference)
+,t_vid_global_pop AS
+(
+    SELECT  dt
+            ,apptype
+            ,vid
+            ,COUNT(1) AS vid_global_pop
+    FROM    t_base
+    GROUP BY dt, apptype, vid
+)
+-- 按桶×flowpool 聚合
+,t_bucket_fp AS
+(
+    SELECT  b.dt
+            ,b.apptype
+            ,b.abcode
+            ,b.suffix_group
+            ,b.suffix
+            ,COALESCE(b.flowpool, 'unknown') AS flowpool
+            ,COUNT(1) AS exp_cnt
+            ,COUNT(DISTINCT b.vid) AS vid_cnt
+            ,SUM(g.vid_global_pop) / COUNT(1) AS avg_vid_pop
+    FROM    t_base b
+    LEFT JOIN t_vid_global_pop g
+    ON      b.dt = g.dt
+    AND     b.apptype = g.apptype
+    AND     b.vid = g.vid
+    GROUP BY b.dt, b.apptype, b.abcode, b.suffix_group, b.suffix, b.flowpool
+)
+-- 加上桶内总曝光,算曝光占比
+,t_bucket_total AS
+(
+    SELECT  dt, apptype, abcode, suffix_group, suffix
+            ,SUM(exp_cnt) AS total_exp
+    FROM    t_bucket_fp
+    GROUP BY dt, apptype, abcode, suffix_group, suffix
+)
+,t_bucket_with_pct AS
+(
+    SELECT  f.*
+            ,ROUND(f.exp_cnt / t.total_exp, 6) AS exp_pct
+    FROM    t_bucket_fp f
+    JOIN    t_bucket_total t
+    ON      f.dt = t.dt
+    AND     f.apptype = t.apptype
+    AND     f.abcode = t.abcode
+    AND     f.suffix_group = t.suffix_group
+    AND     f.suffix = t.suffix
+)
+-- 按 suffix_group 求尾号均值
+,t_metrics AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix_group
+            ,flowpool
+            ,WM_CONCAT(DISTINCT ',', suffix) AS suffix
+            ,AVG(exp_cnt) AS exp_cnt
+            ,ROUND(AVG(exp_pct), 6) AS exp_pct
+            ,ROUND(AVG(vid_cnt), 0) AS vid_cnt
+            ,ROUND(AVG(avg_vid_pop), 0) AS avg_vid_pop
+    FROM    t_bucket_with_pct
+    GROUP BY dt, apptype, abcode, suffix_group, flowpool
+)
+-- 基线桶(89)
+,t_ctrl AS
+(
+    SELECT  dt, apptype, flowpool
+            ,exp_pct AS ctrl_exp_pct
+            ,avg_vid_pop AS ctrl_avg_vid_pop
+    FROM    t_metrics
+    WHERE   suffix_group = '89'
+)
+SELECT  r.dt
+        ,r.apptype
+        ,r.abcode
+        ,r.suffix_group
+        ,r.suffix
+        ,r.flowpool
+        ,r.exp_cnt
+        ,r.exp_pct
+        ,r.vid_cnt
+        ,r.avg_vid_pop
+        -- vs 89
+        ,ROUND(r.exp_pct - ctrl.ctrl_exp_pct, 6) AS exp_pct_diff
+        ,ROUND(r.avg_vid_pop / NULLIF(ctrl.ctrl_avg_vid_pop, 0) - 1, 6) AS avg_vid_pop_diff
+FROM    t_metrics r
+LEFT JOIN t_ctrl ctrl
+ON      r.dt = ctrl.dt
+AND     r.apptype = ctrl.apptype
+AND     r.flowpool = ctrl.flowpool
+ORDER BY r.dt DESC, r.apptype, r.suffix_group, r.exp_pct DESC
+;

+ 10 - 0
tasks/00_尾号实验/探查_人均曝光拆解.json

@@ -0,0 +1,10 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "7ZOfe1",
+  "sort": "dt:desc,apptype:asc,suffix_group:asc,source_type:asc,layer_type:asc",
+  "order": {
+      "suffix_group": ["ab", "34", "2c", "67", "01", "5d", "ef", "89"]
+  },
+  "cols": null,
+  "append_cols": true
+}

+ 223 - 0
tasks/00_尾号实验/探查_人均曝光拆解.sql

@@ -0,0 +1,223 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- exp_per_dau 拆解:人均session数 × 每session曝光数 × 按页面类型分布
+-- 基于 base_all_new_v3_分层 精简,仅保留消费深度相关指标
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT "a" AS suffix, "ab" AS suffix_group
+    UNION ALL SELECT "b", "ab"
+    UNION ALL SELECT "0", "01"
+    UNION ALL SELECT "1", "01"
+    UNION ALL SELECT "2", "2c"
+    UNION ALL SELECT "c", "2c"
+    UNION ALL SELECT "3", "34"
+    UNION ALL SELECT "4", "34"
+    UNION ALL SELECT "5", "5d"
+    UNION ALL SELECT "d", "5d"
+    UNION ALL SELECT "6", "67"
+    UNION ALL SELECT "7", "67"
+    UNION ALL SELECT "8", "89"
+    UNION ALL SELECT "9", "89"
+    UNION ALL SELECT "e", "ef"
+    UNION ALL SELECT "f", "ef"
+)
+,t_experiment_map AS
+(
+    -- ── apptype = 4 ──────────────────────────────────────────────────
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验 有问题" AS abcode, "20260413" AS start_dt, "20260415" AS end_dt
+    UNION ALL SELECT "4", "ab", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:bn_ros新损失函数",        "20260311", "20260319"
+    UNION ALL SELECT "4", "5d", "实验组:解构特征排序str模型",     "20260314", "20260406"
+    UNION ALL SELECT "4", "ef", "实验组:解构特征排序str模型&召回", "20260314", "20260320"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "299991231"
+
+    -- ── apptype = 0 ──────────────────────────────────────────────────
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验 有问题", "20260413", "20260415"
+    UNION ALL SELECT "0", "ab", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "34", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "67", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "5d", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+,t_base AS
+(
+    SELECT  sub.*
+            ,sg.suffix_group
+            ,COALESCE(m.abcode,"对照组") AS abcode
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,CASE WHEN a.rootsourceid = '' OR a.rootsourceid IS NULL THEN '内部' ELSE '外部' END AS source_type
+                        ,CASE WHEN GET_JSON_OBJECT(a.extend,'$.rootsessionid') = a.subsessionid THEN '首层' ELSE '裂变层' END AS layer_type
+                        ,a.mid
+                        ,a.subsessionid
+                        ,page
+                FROM    loghubods.dwd_recsys_alg_exposure_base_20250108 a
+                WHERE   dt="${dt}"
+                AND     apptype IN ("0","4")
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     (apptype = "4"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                AND     (apptype = "0"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+            ) sub
+    INNER JOIN t_suffix_group sg
+    ON      sub.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+    ON      sub.apptype = m.apptype
+    AND     sg.suffix_group = m.suffix_group
+    AND     '${dt}' BETWEEN m.start_dt AND m.end_dt
+)
+-- 按单尾号聚合:拆解 exp_per_dau
+,t_bucket AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix_group
+            ,suffix
+            ,COALESCE(source_type,'总体') AS source_type
+            ,COALESCE(layer_type,'总体') AS layer_type
+            -- ── 总量 ──
+            ,COUNT(1) AS exp
+            ,COUNT(DISTINCT mid) AS dau
+            ,COUNT(DISTINCT subsessionid) AS session_cnt
+            -- ── 核心拆解:exp_per_dau = sessions_per_dau × exp_per_session ──
+            ,COALESCE(COUNT(1) / COUNT(DISTINCT mid), 0) AS exp_per_dau
+            ,COALESCE(COUNT(DISTINCT subsessionid) / COUNT(DISTINCT mid), 0) AS sessions_per_dau
+            ,COALESCE(COUNT(1) / COUNT(DISTINCT subsessionid), 0) AS exp_per_session
+            -- ── 按页面类型拆曝光占比 ──
+            ,SUM(CASE WHEN page = '首页feed' THEN 1 ELSE 0 END) / COUNT(1) AS pct_homepage
+            ,SUM(CASE WHEN page = '详情后沉浸页' THEN 1 ELSE 0 END) / COUNT(1) AS pct_detail_immerse
+            ,SUM(CASE WHEN page = '回流后沉浸页&内页feed' THEN 1 ELSE 0 END) / COUNT(1) AS pct_return_immerse
+            ,SUM(CASE WHEN page = '详情页' THEN 1 ELSE 0 END) / COUNT(1) AS pct_detail
+            -- ── 按页面类型拆人均曝光 ──
+            ,SUM(CASE WHEN page = '首页feed' THEN 1 ELSE 0 END) / COUNT(DISTINCT mid) AS exp_per_dau_homepage
+            ,SUM(CASE WHEN page = '详情后沉浸页' THEN 1 ELSE 0 END) / COUNT(DISTINCT mid) AS exp_per_dau_detail_immerse
+            ,SUM(CASE WHEN page = '回流后沉浸页&内页feed' THEN 1 ELSE 0 END) / COUNT(DISTINCT mid) AS exp_per_dau_return_immerse
+            ,SUM(CASE WHEN page = '详情页' THEN 1 ELSE 0 END) / COUNT(DISTINCT mid) AS exp_per_dau_detail
+    FROM    t_base
+    GROUP BY dt, apptype, abcode, suffix_group, suffix, source_type, layer_type
+    GROUPING SETS (
+        (dt, apptype, abcode, suffix_group, suffix, source_type, layer_type),
+        (dt, apptype, abcode, suffix_group, suffix)
+    )
+)
+-- 按实验组求尾号均值
+,t_metrics AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix_group
+            ,source_type
+            ,layer_type
+            ,WM_CONCAT(DISTINCT ',', suffix) AS suffix
+            -- 总量
+            ,AVG(exp) AS exp
+            ,AVG(dau) AS dau
+            ,AVG(session_cnt) AS session_cnt
+            -- 核心拆解
+            ,ROUND(AVG(exp_per_dau), 2) AS exp_per_dau
+            ,ROUND(AVG(sessions_per_dau), 4) AS sessions_per_dau
+            ,ROUND(AVG(exp_per_session), 2) AS exp_per_session
+            -- 页面占比
+            ,ROUND(AVG(pct_homepage), 6) AS pct_homepage
+            ,ROUND(AVG(pct_detail_immerse), 6) AS pct_detail_immerse
+            ,ROUND(AVG(pct_return_immerse), 6) AS pct_return_immerse
+            ,ROUND(AVG(pct_detail), 6) AS pct_detail
+            -- 按页面拆人均曝光
+            ,ROUND(AVG(exp_per_dau_homepage), 2) AS exp_per_dau_homepage
+            ,ROUND(AVG(exp_per_dau_detail_immerse), 2) AS exp_per_dau_detail_immerse
+            ,ROUND(AVG(exp_per_dau_return_immerse), 2) AS exp_per_dau_return_immerse
+            ,ROUND(AVG(exp_per_dau_detail), 2) AS exp_per_dau_detail
+    FROM    t_bucket
+    GROUP BY dt, apptype, abcode, suffix_group, source_type, layer_type
+)
+-- 基线桶(89)
+,t_ctrl AS
+(
+    SELECT  dt, apptype, source_type, layer_type
+            ,exp_per_dau AS ctrl_exp_per_dau
+            ,sessions_per_dau AS ctrl_sessions_per_dau
+            ,exp_per_session AS ctrl_exp_per_session
+            ,exp_per_dau_homepage AS ctrl_exp_per_dau_homepage
+            ,exp_per_dau_detail_immerse AS ctrl_exp_per_dau_detail_immerse
+            ,exp_per_dau_return_immerse AS ctrl_exp_per_dau_return_immerse
+            ,exp_per_dau_detail AS ctrl_exp_per_dau_detail
+    FROM    t_metrics
+    WHERE   suffix_group = '89'
+)
+-- 最终输出
+SELECT  r.dt
+        ,r.apptype
+        ,r.abcode
+        ,r.suffix_group
+        ,r.source_type
+        ,r.layer_type
+        ,r.suffix
+        -- ── 总量 ──
+        ,r.exp
+        ,r.dau
+        ,r.session_cnt
+        -- ── 核心拆解 ──
+        ,r.exp_per_dau
+        ,r.sessions_per_dau
+        ,r.exp_per_session
+        -- ── 页面占比 ──
+        ,r.pct_homepage
+        ,r.pct_detail_immerse
+        ,r.pct_return_immerse
+        ,r.pct_detail
+        -- ── 按页面拆人均曝光 ──
+        ,r.exp_per_dau_homepage
+        ,r.exp_per_dau_detail_immerse
+        ,r.exp_per_dau_return_immerse
+        ,r.exp_per_dau_detail
+        -- ── vs 对照组 89 diff ──
+        ,ROUND(r.exp_per_dau / NULLIF(ctrl.ctrl_exp_per_dau, 0) - 1, 6) AS exp_per_dau_diff
+        ,ROUND(r.sessions_per_dau / NULLIF(ctrl.ctrl_sessions_per_dau, 0) - 1, 6) AS sessions_per_dau_diff
+        ,ROUND(r.exp_per_session / NULLIF(ctrl.ctrl_exp_per_session, 0) - 1, 6) AS exp_per_session_diff
+        ,ROUND(r.exp_per_dau_homepage / NULLIF(ctrl.ctrl_exp_per_dau_homepage, 0) - 1, 6) AS exp_per_dau_homepage_diff
+        ,ROUND(r.exp_per_dau_detail_immerse / NULLIF(ctrl.ctrl_exp_per_dau_detail_immerse, 0) - 1, 6) AS exp_per_dau_detail_immerse_diff
+        ,ROUND(r.exp_per_dau_return_immerse / NULLIF(ctrl.ctrl_exp_per_dau_return_immerse, 0) - 1, 6) AS exp_per_dau_return_immerse_diff
+        ,ROUND(r.exp_per_dau_detail / NULLIF(ctrl.ctrl_exp_per_dau_detail, 0) - 1, 6) AS exp_per_dau_detail_diff
+FROM    t_metrics r
+LEFT JOIN t_ctrl ctrl
+ON      r.dt = ctrl.dt
+AND     r.apptype = ctrl.apptype
+AND     r.source_type = ctrl.source_type
+AND     r.layer_type = ctrl.layer_type
+ORDER BY r.dt DESC, r.apptype, r.abcode, r.suffix_group, r.source_type, r.layer_type
+;

+ 199 - 0
tasks/00_尾号实验/探查_人均曝光按用户分级.sql

@@ -0,0 +1,199 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- exp_per_dau 按用户活跃度分级拆解
+-- 用户分级:过去7天在 useractive_log 中的活跃天数
+--   高活(5-7天) / 中活(2-4天) / 低活(1天) / 新用户(0天,��当天出现)
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT "a" AS suffix, "ab" AS suffix_group
+    UNION ALL SELECT "b", "ab"
+    UNION ALL SELECT "0", "01"
+    UNION ALL SELECT "1", "01"
+    UNION ALL SELECT "2", "2c"
+    UNION ALL SELECT "c", "2c"
+    UNION ALL SELECT "3", "34"
+    UNION ALL SELECT "4", "34"
+    UNION ALL SELECT "5", "5d"
+    UNION ALL SELECT "d", "5d"
+    UNION ALL SELECT "6", "67"
+    UNION ALL SELECT "7", "67"
+    UNION ALL SELECT "8", "89"
+    UNION ALL SELECT "9", "89"
+    UNION ALL SELECT "e", "ef"
+    UNION ALL SELECT "f", "ef"
+)
+,t_experiment_map AS
+(
+    -- ── apptype = 4 ──────────────────────────────────────────────────
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验 有问题" AS abcode, "20260413" AS start_dt, "20260415" AS end_dt
+    UNION ALL SELECT "4", "ab", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:bn_ros新损失函数",        "20260311", "20260319"
+    UNION ALL SELECT "4", "5d", "实验组:解构特征排序str模型",     "20260314", "20260406"
+    UNION ALL SELECT "4", "ef", "实验组:解构特征排序str模型&召回", "20260314", "20260320"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "299991231"
+
+    -- ── apptype = 0 ──────────────────────────────────────────────────
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验 有问题", "20260413", "20260415"
+    UNION ALL SELECT "0", "ab", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "34", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "67", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "5d", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+-- 过去7天用户活跃天数
+,t_user_history AS
+(
+    SELECT  machinecode AS mid
+            ,apptype
+            ,COUNT(DISTINCT dt) AS active_days_7d
+    FROM    loghubods.useractive_log
+    WHERE   dt >= TO_CHAR(DATEADD(TO_DATE('${dt}','yyyymmdd'), -7, 'dd'), 'yyyymmdd')
+    AND     dt <  '${dt}'
+    AND     apptype IN ("0","4")
+    GROUP BY machinecode, apptype
+)
+,t_base AS
+(
+    SELECT  sub.*
+            ,sg.suffix_group
+            ,COALESCE(m.abcode,"对照组") AS abcode
+            ,CASE
+                WHEN h.active_days_7d >= 5 THEN '1_高活'
+                WHEN h.active_days_7d >= 2 THEN '2_中活'
+                WHEN h.active_days_7d >= 1 THEN '3_低活'
+                ELSE '4_新用户'
+             END AS user_tier
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,a.mid
+                        ,a.vid
+                FROM    loghubods.dwd_recsys_alg_exposure_base_20250108 a
+                WHERE   dt="${dt}"
+                AND     apptype IN ("0","4")
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     (apptype = "4"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                AND     (apptype = "0"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+            ) sub
+    INNER JOIN t_suffix_group sg
+    ON      sub.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+    ON      sub.apptype = m.apptype
+    AND     sg.suffix_group = m.suffix_group
+    AND     '${dt}' BETWEEN m.start_dt AND m.end_dt
+    LEFT JOIN t_user_history h
+    ON      sub.mid = h.mid
+    AND     sub.apptype = h.apptype
+)
+-- 按单尾号 × user_tier 聚合
+,t_bucket AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix_group
+            ,suffix
+            ,user_tier
+            ,COUNT(1) AS exp
+            ,COUNT(DISTINCT mid) AS dau
+            ,COALESCE(COUNT(1) / COUNT(DISTINCT mid), 0) AS exp_per_dau
+    FROM    t_base
+    GROUP BY dt, apptype, abcode, suffix_group, suffix, user_tier
+)
+-- 按 suffix_group 求尾号均值
+,t_metrics AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix_group
+            ,user_tier
+            ,WM_CONCAT(DISTINCT ',', suffix) AS suffix
+            ,AVG(exp) AS exp
+            ,AVG(dau) AS dau
+            ,ROUND(AVG(exp_per_dau), 2) AS exp_per_dau
+            -- 各tier的dau占比需要跨tier算,在外层处理
+    FROM    t_bucket
+    GROUP BY dt, apptype, abcode, suffix_group, user_tier
+)
+-- 加上总 dau 算各 tier 占比
+,t_total_dau AS
+(
+    SELECT  dt, apptype, abcode, suffix_group
+            ,SUM(dau) AS total_dau
+    FROM    t_metrics
+    GROUP BY dt, apptype, abcode, suffix_group
+)
+,t_with_pct AS
+(
+    SELECT  m.*
+            ,ROUND(m.dau / t.total_dau, 6) AS dau_pct
+    FROM    t_metrics m
+    JOIN    t_total_dau t
+    ON      m.dt = t.dt
+    AND     m.apptype = t.apptype
+    AND     m.abcode = t.abcode
+    AND     m.suffix_group = t.suffix_group
+)
+-- 基线桶(89)
+,t_ctrl AS
+(
+    SELECT  dt, apptype, user_tier
+            ,exp_per_dau AS ctrl_exp_per_dau
+            ,dau_pct AS ctrl_dau_pct
+    FROM    t_with_pct
+    WHERE   suffix_group = '89'
+)
+SELECT  r.dt
+        ,r.apptype
+        ,r.abcode
+        ,r.suffix_group
+        ,r.suffix
+        ,r.user_tier
+        ,r.exp
+        ,r.dau
+        ,r.dau_pct
+        ,r.exp_per_dau
+        -- vs 89
+        ,ROUND(r.dau_pct - ctrl.ctrl_dau_pct, 6) AS dau_pct_diff
+        ,ROUND(r.exp_per_dau / NULLIF(ctrl.ctrl_exp_per_dau, 0) - 1, 6) AS exp_per_dau_diff
+FROM    t_with_pct r
+LEFT JOIN t_ctrl ctrl
+ON      r.dt = ctrl.dt
+AND     r.apptype = ctrl.apptype
+AND     r.user_tier = ctrl.user_tier
+ORDER BY r.dt DESC, r.apptype, r.suffix_group, r.user_tier
+;

+ 189 - 0
tasks/00_尾号实验/探查_头部视频曝光占比.sql

@@ -0,0 +1,189 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- 头部视频分析:按全局热度分档,看各档的曝光占比变化
+-- 分档:top100 / top1000 / top5000 / 长尾
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT "a" AS suffix, "ab" AS suffix_group
+    UNION ALL SELECT "b", "ab"
+    UNION ALL SELECT "0", "01"
+    UNION ALL SELECT "1", "01"
+    UNION ALL SELECT "2", "2c"
+    UNION ALL SELECT "c", "2c"
+    UNION ALL SELECT "3", "34"
+    UNION ALL SELECT "4", "34"
+    UNION ALL SELECT "5", "5d"
+    UNION ALL SELECT "d", "5d"
+    UNION ALL SELECT "6", "67"
+    UNION ALL SELECT "7", "67"
+    UNION ALL SELECT "8", "89"
+    UNION ALL SELECT "9", "89"
+    UNION ALL SELECT "e", "ef"
+    UNION ALL SELECT "f", "ef"
+)
+,t_experiment_map AS
+(
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验 有问题" AS abcode, "20260413" AS start_dt, "20260415" AS end_dt
+    UNION ALL SELECT "4", "ab", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:bn_ros新损失函数",        "20260311", "20260319"
+    UNION ALL SELECT "4", "5d", "实验组:解构特征排序str模型",     "20260314", "20260406"
+    UNION ALL SELECT "4", "ef", "实验组:解构特征排序str模型&召回", "20260314", "20260320"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "299991231"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验 有问题", "20260413", "20260415"
+    UNION ALL SELECT "0", "ab", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "34", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "67", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "5d", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+,t_base AS
+(
+    SELECT  sub.*
+            ,sg.suffix_group
+            ,COALESCE(m.abcode,"对照组") AS abcode
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,vid
+                FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
+                WHERE   dt="${dt}"
+                AND     apptype IN ("0","4")
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     (apptype = "4"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                AND     (apptype = "0"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+            ) sub
+    INNER JOIN t_suffix_group sg ON sub.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+    ON      sub.apptype = m.apptype
+    AND     sg.suffix_group = m.suffix_group
+    AND     '${dt}' BETWEEN m.start_dt AND m.end_dt
+)
+-- 全局视频热度排名
+,t_vid_rank AS
+(
+    SELECT  dt
+            ,apptype
+            ,vid
+            ,COUNT(1) AS vid_global_exp
+            ,ROW_NUMBER() OVER (PARTITION BY dt, apptype ORDER BY COUNT(1) DESC) AS pop_rank
+    FROM    t_base
+    GROUP BY dt, apptype, vid
+)
+-- 给每个视频打热度分档标签
+,t_vid_tier AS
+(
+    SELECT  *
+            ,CASE
+                WHEN pop_rank <= 100  THEN '1_top100'
+                WHEN pop_rank <= 1000 THEN '2_top1000'
+                WHEN pop_rank <= 5000 THEN '3_top5000'
+                ELSE '4_长尾'
+             END AS vid_tier
+    FROM    t_vid_rank
+)
+-- 按桶×视频档位聚合曝光
+,t_bucket AS
+(
+    SELECT  b.dt
+            ,b.apptype
+            ,b.abcode
+            ,b.suffix_group
+            ,b.suffix
+            ,v.vid_tier
+            ,COUNT(1) AS exp_cnt
+    FROM    t_base b
+    LEFT JOIN t_vid_tier v
+    ON      b.dt = v.dt
+    AND     b.apptype = v.apptype
+    AND     b.vid = v.vid
+    GROUP BY b.dt, b.apptype, b.abcode, b.suffix_group, b.suffix, v.vid_tier
+)
+-- 加上桶内总曝光算占比
+,t_total AS
+(
+    SELECT  dt, apptype, abcode, suffix_group, suffix
+            ,SUM(exp_cnt) AS total_exp
+    FROM    t_bucket
+    GROUP BY dt, apptype, abcode, suffix_group, suffix
+)
+,t_with_pct AS
+(
+    SELECT  b.*
+            ,ROUND(b.exp_cnt / t.total_exp, 6) AS exp_pct
+    FROM    t_bucket b
+    JOIN    t_total t
+    ON      b.dt = t.dt AND b.apptype = t.apptype
+    AND     b.abcode = t.abcode AND b.suffix_group = t.suffix_group
+    AND     b.suffix = t.suffix
+)
+-- 按 suffix_group 求尾号均值
+,t_metrics AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix_group
+            ,vid_tier
+            ,WM_CONCAT(DISTINCT ',', suffix) AS suffix
+            ,AVG(exp_cnt) AS exp_cnt
+            ,ROUND(AVG(exp_pct), 6) AS exp_pct
+    FROM    t_with_pct
+    GROUP BY dt, apptype, abcode, suffix_group, vid_tier
+)
+-- 基线桶(89)
+,t_ctrl AS
+(
+    SELECT  dt, apptype, vid_tier
+            ,exp_pct AS ctrl_exp_pct
+    FROM    t_metrics
+    WHERE   suffix_group = '89'
+)
+SELECT  r.dt
+        ,r.apptype
+        ,r.abcode
+        ,r.suffix_group
+        ,r.suffix
+        ,r.vid_tier
+        ,r.exp_cnt
+        ,r.exp_pct
+        ,ROUND(r.exp_pct - ctrl.ctrl_exp_pct, 6) AS exp_pct_diff
+FROM    t_metrics r
+LEFT JOIN t_ctrl ctrl
+ON      r.dt = ctrl.dt
+AND     r.apptype = ctrl.apptype
+AND     r.vid_tier = ctrl.vid_tier
+ORDER BY r.dt DESC, r.apptype, r.suffix_group, r.vid_tier
+;

+ 124 - 0
tasks/00_尾号实验/探查_视频重合度.sql

@@ -0,0 +1,124 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- 视频重合度:各实验组 vs 对照组(89) 的曝光视频 Jaccard 相似度
+-- Jaccard = |A ∩ B| / |A ∪ B|
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT "a" AS suffix, "ab" AS suffix_group
+    UNION ALL SELECT "b", "ab"
+    UNION ALL SELECT "0", "01"
+    UNION ALL SELECT "1", "01"
+    UNION ALL SELECT "2", "2c"
+    UNION ALL SELECT "c", "2c"
+    UNION ALL SELECT "3", "34"
+    UNION ALL SELECT "4", "34"
+    UNION ALL SELECT "5", "5d"
+    UNION ALL SELECT "d", "5d"
+    UNION ALL SELECT "6", "67"
+    UNION ALL SELECT "7", "67"
+    UNION ALL SELECT "8", "89"
+    UNION ALL SELECT "9", "89"
+    UNION ALL SELECT "e", "ef"
+    UNION ALL SELECT "f", "ef"
+)
+,t_experiment_map AS
+(
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验 有问题" AS abcode, "20260413" AS start_dt, "20260415" AS end_dt
+    UNION ALL SELECT "4", "ab", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:bn_ros新损失函数",        "20260311", "20260319"
+    UNION ALL SELECT "4", "5d", "实验组:解构特征排序str模型",     "20260314", "20260406"
+    UNION ALL SELECT "4", "ef", "实验组:解构特征排序str模型&召回", "20260314", "20260320"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "299991231"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验 有问题", "20260413", "20260415"
+    UNION ALL SELECT "0", "ab", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "34", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "67", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "5d", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+-- 按 suffix_group 去重 vid
+,t_group_vids AS
+(
+    SELECT  sub.dt
+            ,sub.apptype
+            ,sg.suffix_group
+            ,COALESCE(m.abcode,"对照组") AS abcode
+            ,sub.vid
+    FROM    (
+                SELECT  DISTINCT dt, apptype
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,vid
+                FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
+                WHERE   dt="${dt}"
+                AND     apptype IN ("0","4")
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     (apptype = "4"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                AND     (apptype = "0"
+                         OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+            ) sub
+    INNER JOIN t_suffix_group sg ON sub.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+    ON      sub.apptype = m.apptype
+    AND     sg.suffix_group = m.suffix_group
+    AND     '${dt}' BETWEEN m.start_dt AND m.end_dt
+    GROUP BY sub.dt, sub.apptype, sg.suffix_group, COALESCE(m.abcode,"对照组"), sub.vid
+)
+-- 对照组(89)的视频集合
+,t_ctrl_vids AS
+(
+    SELECT  dt, apptype, vid
+    FROM    t_group_vids
+    WHERE   suffix_group = '89'
+)
+-- 各组 vs 89 的交集和并集
+SELECT  a.dt
+        ,a.apptype
+        ,a.abcode
+        ,a.suffix_group
+        ,COUNT(DISTINCT a.vid) AS exp_vid_cnt
+        ,COUNT(DISTINCT c.vid) AS ctrl_vid_cnt
+        ,COUNT(DISTINCT CASE WHEN c.vid IS NOT NULL THEN a.vid END) AS intersection_cnt
+        ,COUNT(DISTINCT a.vid) + COUNT(DISTINCT c.vid)
+         - COUNT(DISTINCT CASE WHEN c.vid IS NOT NULL THEN a.vid END) AS union_cnt
+        ,ROUND(COUNT(DISTINCT CASE WHEN c.vid IS NOT NULL THEN a.vid END)
+         / (COUNT(DISTINCT a.vid) + COUNT(DISTINCT c.vid)
+            - COUNT(DISTINCT CASE WHEN c.vid IS NOT NULL THEN a.vid END)), 6) AS jaccard
+FROM    t_group_vids a
+LEFT JOIN t_ctrl_vids c
+ON      a.dt = c.dt
+AND     a.apptype = c.apptype
+AND     a.vid = c.vid
+GROUP BY a.dt, a.apptype, a.abcode, a.suffix_group
+ORDER BY a.dt DESC, a.apptype, a.suffix_group
+;

+ 20 - 0
tasks/00_尾号实验/策略打分诊断/探查_scoresmap字段全集.sql

@@ -0,0 +1,20 @@
+-- 验证:sample_all 表 scoresmap 实际 key 全集 vs SQL 清单
+-- 取每个 (apptype, abcode) 一条样本,便于读取 raw JSON 列举所有 key
+WITH t_sample AS
+(
+    SELECT  apptype
+            ,abcode
+            ,REPLACE(GET_JSON_OBJECT(extend_alg,'$.scoresMap'),"\\","") AS scoresmap
+            ,ROW_NUMBER() OVER (PARTITION BY apptype, abcode ORDER BY ts) AS rn
+    FROM    loghubods.dwd_recsys_alg_sample_all_20250212
+    WHERE   dt = '${dt}'
+    AND     apptype IN ('0','4')
+    AND     abcode IN ('ab0','ab1','ab2','ab3','ab4','ab5','ab6','ab7','ab8','ab9')
+    AND     extend_alg IS NOT NULL
+    AND     GET_JSON_OBJECT(extend_alg,'$.scoresMap') IS NOT NULL
+)
+SELECT  apptype, abcode, scoresmap
+FROM    t_sample
+WHERE   rn = 1
+ORDER BY apptype, abcode
+;

+ 51 - 0
tasks/00_尾号实验/策略打分诊断/探查_scoresmap字段按尾号桶覆盖率.sql

@@ -0,0 +1,51 @@
+-- 验证:scoresmap 各关键字段在每个 (apptype, suffix_group) 的写入次数
+-- 目的:直接证伪/证实"01/67 尾号有 newPLeave"是不是 565/566 改动溢出
+--   - 看每个尾号桶 has_new_pleave / total 比例
+--   - 横向对比:哪些字段在哪些桶被写入,模式如何
+WITH t_suffix_group AS
+(
+    SELECT 'a' AS suffix, 'ab' AS suffix_group
+    UNION ALL SELECT 'b', 'ab'
+    UNION ALL SELECT '0', '01'
+    UNION ALL SELECT '1', '01'
+    UNION ALL SELECT '2', '2c'
+    UNION ALL SELECT 'c', '2c'
+    UNION ALL SELECT '3', '34'
+    UNION ALL SELECT '4', '34'
+    UNION ALL SELECT '5', '5d'
+    UNION ALL SELECT 'd', '5d'
+    UNION ALL SELECT '6', '67'
+    UNION ALL SELECT '7', '67'
+    UNION ALL SELECT '8', '89'
+    UNION ALL SELECT '9', '89'
+    UNION ALL SELECT 'e', 'ef'
+    UNION ALL SELECT 'f', 'ef'
+)
+,t_base AS
+(
+    SELECT  apptype
+            ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),
+                    LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+            ,REPLACE(GET_JSON_OBJECT(extend_alg,'$.scoresMap'),"\\","") AS scoresmap
+    FROM    loghubods.dwd_recsys_alg_sample_all_20250212
+    WHERE   dt = '${dt}'
+    AND     apptype IN ('0','4')
+    AND     extend_alg IS NOT NULL
+    AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+)
+SELECT  a.apptype
+        ,sg.suffix_group
+        ,COUNT(1) AS exp
+        ,SUM(CASE WHEN GET_JSON_OBJECT(scoresmap,'$.fmRov')        IS NOT NULL THEN 1 ELSE 0 END) AS has_fmrov
+        ,SUM(CASE WHEN GET_JSON_OBJECT(scoresmap,'$.NorXGBScore')  IS NOT NULL THEN 1 ELSE 0 END) AS has_xgb
+        ,SUM(CASE WHEN GET_JSON_OBJECT(scoresmap,'$.NorDNNScore')  IS NOT NULL THEN 1 ELSE 0 END) AS has_dnn
+        ,SUM(CASE WHEN GET_JSON_OBJECT(scoresmap,'$.pLeave')       IS NOT NULL THEN 1 ELSE 0 END) AS has_pleave
+        ,SUM(CASE WHEN GET_JSON_OBJECT(scoresmap,'$.newPLeave')    IS NOT NULL THEN 1 ELSE 0 END) AS has_new_pleave
+        ,SUM(CASE WHEN GET_JSON_OBJECT(scoresmap,'$.cnRovnScore')  IS NOT NULL THEN 1 ELSE 0 END) AS has_cn
+        ,SUM(CASE WHEN GET_JSON_OBJECT(scoresmap,'$.dnRovnScore')  IS NOT NULL THEN 1 ELSE 0 END) AS has_dn
+FROM    t_base a
+INNER JOIN t_suffix_group sg
+ON      a.suffix = sg.suffix
+GROUP BY a.apptype, sg.suffix_group
+ORDER BY a.apptype, sg.suffix_group
+;

+ 6 - 0
tasks/00_尾号实验/策略打分诊断/策略打分阈值分布.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "DhgTD2",
+  "cols": null,
+  "append_cols": false
+}

+ 268 - 0
tasks/00_尾号实验/策略打分诊断/策略打分阈值分布.sql

@@ -0,0 +1,268 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- 策略打分阈值分布 [简化版]
+--   目的:为公式调权实验提供分数的"地形图"
+--        - 每个分数的 min / max / 分位数(p50/p95)→ 回答"改权重后分数落在哪"
+--        - 每个分数的 cov → 该分数对该策略实际贡献覆盖率
+--        - avg / std → 中心趋势 + 离散度
+--   行粒度:(dt, apptype, suffix_group) + GROUPING SETS 总体行
+--
+-- 与 base panel SQL 的差异:
+--   - 数据源仍是 dwd_recsys_alg_sample_all_20250212
+--   - 砍掉:dau2 / _diff / cc-dd / ECS-ARP / 分层(source_type/layer_type)
+--   - 加上:min / max / p50 / p95(PERCENTILE_APPROX 近似分位数)
+--
+-- 调权时怎么读:
+--   想调 ros_add(562→563 改 0.1→0.001):
+--     → 看 nor_dnn_score 的 p50(DNN 路径),ros_add 占乘子的比例 = ros_add / (ros_add + nor_dnn_p50)
+--     → 0.1 / (0.1 + 0.65) ≈ 13%(562 默认);0.001 / (0.001 + 0.65) ≈ 0.15%(563 上线后)
+--   想调 vor_w:
+--     → 看 vor 的 p50/p95,权重×p50 决定主流量级,权重×p95 决定尾部杠杆
+--   想调 leave_w/leave_exp(仅 565/566):
+--     → 看 p_leave 的 min/max/p50,newPLeave = (1-w·pLeave)^exp 在该分布上落到哪
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT 'a' AS suffix, 'ab' AS suffix_group
+    UNION ALL SELECT 'b', 'ab'
+    UNION ALL SELECT '0', '01'
+    UNION ALL SELECT '1', '01'
+    UNION ALL SELECT '2', '2c'
+    UNION ALL SELECT 'c', '2c'
+    UNION ALL SELECT '3', '34'
+    UNION ALL SELECT '4', '34'
+    UNION ALL SELECT '5', '5d'
+    UNION ALL SELECT 'd', '5d'
+    UNION ALL SELECT '6', '67'
+    UNION ALL SELECT '7', '67'
+    UNION ALL SELECT '8', '89'
+    UNION ALL SELECT '9', '89'
+    UNION ALL SELECT 'e', 'ef'
+    UNION ALL SELECT 'f', 'ef'
+)
+,t_experiment_map AS
+(
+    -- ── apptype = 4 ──
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验" AS abcode, "20260416" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "29991231"
+    -- ── apptype = 0 ──
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260426", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:曝光建模v1+DNN模型",      "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+,t_exp_code_map AS
+(
+    -- 流量配置 20260425.json:(apptype, suffix_group) → expCode
+    SELECT "0" AS apptype, "89" AS suffix_group, "839" AS expcode, "20260425" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "89", "839", "20260425", "29991231"
+    UNION ALL SELECT "4", "ef", "562", "20260425", "29991231"
+    UNION ALL SELECT "0", "2c", "562", "20260425", "29991231"
+    UNION ALL SELECT "4", "2c", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "5d", "565", "20260425", "29991231"
+    UNION ALL SELECT "0", "34", "566", "20260425", "29991231"
+)
+-- 单条曝光 + 解 13 个分数(不要业务 label,不要 cc/dd)
+,t_scored AS
+(
+    SELECT  a.dt
+            ,a.apptype
+            ,sg.suffix_group
+            ,COALESCE(m.abcode, "对照组") AS abcode
+            ,e.expcode
+            -- ── 13 个分数 ──
+            ,CAST(a.score AS DOUBLE)                                            AS final_score
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.fmRov')              AS DOUBLE) AS fmrov
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.fmRovOrigin')        AS DOUBLE) AS fmrov_origin
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.NorXGBScore')        AS DOUBLE) AS nor_xgb
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.NorDNNScore')        AS DOUBLE) AS nor_dnn
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.newNorDNNScore')     AS DOUBLE) AS new_nor_dnn
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.hasReturnRovScore')  AS DOUBLE) AS has_return_rov
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.vor')                AS DOUBLE) AS vor
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.c1RovnScore')        AS DOUBLE) AS c1_rovn
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.b0StrScore')         AS DOUBLE) AS b0_str
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.b0RorScore')         AS DOUBLE) AS b0_ror
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.cnRovnScore')        AS DOUBLE) AS cn_rovn
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.dnRovnScore')        AS DOUBLE) AS dn_rovn
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.pLeave')             AS DOUBLE) AS p_leave
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.newPLeave')          AS DOUBLE) AS new_p_leave
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.reduceCoefficient')  AS DOUBLE) AS reduce_coef
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),
+                                LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,score
+                        ,REPLACE(GET_JSON_OBJECT(extend_alg,'$.scoresMap'),"\\","") AS scoresmap
+                FROM    loghubods.dwd_recsys_alg_sample_all_20250212
+                WHERE   dt = '${dt}'
+                AND     apptype IN ('0','4')
+                AND     extend_alg IS NOT NULL
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     (apptype = "4" OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                AND     (apptype = "0" OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+            ) a
+    INNER JOIN t_suffix_group sg ON a.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+        ON  a.apptype = m.apptype
+        AND sg.suffix_group = m.suffix_group
+        AND '${dt}' BETWEEN m.start_dt AND m.end_dt
+    LEFT JOIN t_exp_code_map e
+        ON  a.apptype = e.apptype
+        AND sg.suffix_group = e.suffix_group
+        AND '${dt}' BETWEEN e.start_dt AND e.end_dt
+)
+-- 每个分数:avg / std / min / max / p50 / p95 / cov(7 列)
+SELECT  dt
+        ,apptype
+        ,COALESCE(suffix_group, '总体') AS suffix_group
+        ,MAX(abcode) AS abcode
+        ,MAX(expcode) AS expcode
+        ,COUNT(1) AS exp
+        -- ────── final_score(线上落盘 finalScore)──────
+        ,ROUND(AVG(final_score), 6)                          AS finalscore_avg
+        ,ROUND(STDDEV_POP(final_score), 6)                   AS finalscore_std
+        ,ROUND(MIN(final_score), 6)                          AS finalscore_min
+        ,ROUND(MAX(final_score), 6)                          AS finalscore_max
+        ,ROUND(PERCENTILE_APPROX(final_score, 0.50), 6)      AS finalscore_p50
+        ,ROUND(PERCENTILE_APPROX(final_score, 0.95), 6)      AS finalscore_p95
+        ,ROUND(SUM(CASE WHEN final_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS finalscore_cov
+        -- ────── fmRov(STR 预估,分享率)──────
+        ,ROUND(AVG(fmrov), 6)                                AS fmrov_avg
+        ,ROUND(STDDEV_POP(fmrov), 6)                         AS fmrov_std
+        ,ROUND(MIN(fmrov), 6)                                AS fmrov_min
+        ,ROUND(MAX(fmrov), 6)                                AS fmrov_max
+        ,ROUND(PERCENTILE_APPROX(fmrov, 0.50), 6)            AS fmrov_p50
+        ,ROUND(PERCENTILE_APPROX(fmrov, 0.95), 6)            AS fmrov_p95
+        ,ROUND(SUM(CASE WHEN fmrov IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS fmrov_cov
+        -- ────── fmRovOrigin(STR 反归一化前)──────
+        ,ROUND(AVG(fmrov_origin), 6)                         AS fmrovorig_avg
+        ,ROUND(STDDEV_POP(fmrov_origin), 6)                  AS fmrovorig_std
+        ,ROUND(MIN(fmrov_origin), 6)                         AS fmrovorig_min
+        ,ROUND(MAX(fmrov_origin), 6)                         AS fmrovorig_max
+        ,ROUND(PERCENTILE_APPROX(fmrov_origin, 0.50), 6)     AS fmrovorig_p50
+        ,ROUND(PERCENTILE_APPROX(fmrov_origin, 0.95), 6)     AS fmrovorig_p95
+        ,ROUND(SUM(CASE WHEN fmrov_origin IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS fmrovorig_cov
+        -- ────── NorXGBScore(XGB 路径 ROS 预估,839/566)──────
+        ,ROUND(AVG(nor_xgb), 6)                              AS norxgb_avg
+        ,ROUND(STDDEV_POP(nor_xgb), 6)                       AS norxgb_std
+        ,ROUND(MIN(nor_xgb), 6)                              AS norxgb_min
+        ,ROUND(MAX(nor_xgb), 6)                              AS norxgb_max
+        ,ROUND(PERCENTILE_APPROX(nor_xgb, 0.50), 6)          AS norxgb_p50
+        ,ROUND(PERCENTILE_APPROX(nor_xgb, 0.95), 6)          AS norxgb_p95
+        ,ROUND(SUM(CASE WHEN nor_xgb IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS norxgb_cov
+        -- ────── NorDNNScore(DNN 路径 ROS 预估,562/563/565)──────
+        ,ROUND(AVG(nor_dnn), 6)                              AS nordnn_avg
+        ,ROUND(STDDEV_POP(nor_dnn), 6)                       AS nordnn_std
+        ,ROUND(MIN(nor_dnn), 6)                              AS nordnn_min
+        ,ROUND(MAX(nor_dnn), 6)                              AS nordnn_max
+        ,ROUND(PERCENTILE_APPROX(nor_dnn, 0.50), 6)          AS nordnn_p50
+        ,ROUND(PERCENTILE_APPROX(nor_dnn, 0.95), 6)          AS nordnn_p95
+        ,ROUND(SUM(CASE WHEN nor_dnn IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS nordnn_cov
+        -- ────── newNorDNNScore(DNN 经 power 校准后)──────
+        ,ROUND(AVG(new_nor_dnn), 6)                          AS newnordnn_avg
+        ,ROUND(STDDEV_POP(new_nor_dnn), 6)                   AS newnordnn_std
+        ,ROUND(MIN(new_nor_dnn), 6)                          AS newnordnn_min
+        ,ROUND(MAX(new_nor_dnn), 6)                          AS newnordnn_max
+        ,ROUND(PERCENTILE_APPROX(new_nor_dnn, 0.50), 6)      AS newnordnn_p50
+        ,ROUND(PERCENTILE_APPROX(new_nor_dnn, 0.95), 6)      AS newnordnn_p95
+        ,ROUND(SUM(CASE WHEN new_nor_dnn IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS newnordnn_cov
+        -- ────── hasReturnRovScore(redis vid_hasreturn_vor:rov 历史回流率)──────
+        ,ROUND(AVG(has_return_rov), 6)                       AS hasretrov_avg
+        ,ROUND(STDDEV_POP(has_return_rov), 6)                AS hasretrov_std
+        ,ROUND(MIN(has_return_rov), 6)                       AS hasretrov_min
+        ,ROUND(MAX(has_return_rov), 6)                       AS hasretrov_max
+        ,ROUND(PERCENTILE_APPROX(has_return_rov, 0.50), 6)   AS hasretrov_p50
+        ,ROUND(PERCENTILE_APPROX(has_return_rov, 0.95), 6)   AS hasretrov_p95
+        ,ROUND(SUM(CASE WHEN has_return_rov IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS hasretrov_cov
+        -- ────── vor(redis vid_hasreturn_vor:vor 历史曝光裂变率)──────
+        ,ROUND(AVG(vor), 6)                                  AS vor_avg
+        ,ROUND(STDDEV_POP(vor), 6)                           AS vor_std
+        ,ROUND(MIN(vor), 6)                                  AS vor_min
+        ,ROUND(MAX(vor), 6)                                  AS vor_max
+        ,ROUND(PERCENTILE_APPROX(vor, 0.50), 6)              AS vor_p50
+        ,ROUND(PERCENTILE_APPROX(vor, 0.95), 6)              AS vor_p95
+        ,ROUND(SUM(CASE WHEN vor IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS vor_cov
+        -- ────── c1RovnScore(一级品类 1h+24h ROVN)──────
+        ,ROUND(AVG(c1_rovn), 6)                              AS c1rovn_avg
+        ,ROUND(STDDEV_POP(c1_rovn), 6)                       AS c1rovn_std
+        ,ROUND(MIN(c1_rovn), 6)                              AS c1rovn_min
+        ,ROUND(MAX(c1_rovn), 6)                              AS c1rovn_max
+        ,ROUND(PERCENTILE_APPROX(c1_rovn, 0.50), 6)          AS c1rovn_p50
+        ,ROUND(PERCENTILE_APPROX(c1_rovn, 0.95), 6)          AS c1rovn_p95
+        ,ROUND(SUM(CASE WHEN c1_rovn IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS c1rovn_cov
+        -- ────── b0StrScore(B0 流 1h+24h STR;当前权重=0 全为 0)──────
+        ,ROUND(AVG(b0_str), 6)                               AS b0str_avg
+        ,ROUND(STDDEV_POP(b0_str), 6)                        AS b0str_std
+        ,ROUND(MIN(b0_str), 6)                               AS b0str_min
+        ,ROUND(MAX(b0_str), 6)                               AS b0str_max
+        ,ROUND(PERCENTILE_APPROX(b0_str, 0.50), 6)           AS b0str_p50
+        ,ROUND(PERCENTILE_APPROX(b0_str, 0.95), 6)           AS b0str_p95
+        ,ROUND(SUM(CASE WHEN b0_str IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS b0str_cov
+        -- ────── b0RorScore(B0 流 1h+24h ROR;当前权重=0)──────
+        ,ROUND(AVG(b0_ror), 6)                               AS b0ror_avg
+        ,ROUND(STDDEV_POP(b0_ror), 6)                        AS b0ror_std
+        ,ROUND(MIN(b0_ror), 6)                               AS b0ror_min
+        ,ROUND(MAX(b0_ror), 6)                               AS b0ror_max
+        ,ROUND(PERCENTILE_APPROX(b0_ror, 0.50), 6)           AS b0ror_p50
+        ,ROUND(PERCENTILE_APPROX(b0_ror, 0.95), 6)           AS b0ror_p95
+        ,ROUND(SUM(CASE WHEN b0_ror IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS b0ror_cov
+        -- ────── cnRovnScore(CN 流 1h+24h ROVN;当前权重=0)──────
+        ,ROUND(AVG(cn_rovn), 6)                              AS cnrovn_avg
+        ,ROUND(STDDEV_POP(cn_rovn), 6)                       AS cnrovn_std
+        ,ROUND(MIN(cn_rovn), 6)                              AS cnrovn_min
+        ,ROUND(MAX(cn_rovn), 6)                              AS cnrovn_max
+        ,ROUND(PERCENTILE_APPROX(cn_rovn, 0.50), 6)          AS cnrovn_p50
+        ,ROUND(PERCENTILE_APPROX(cn_rovn, 0.95), 6)          AS cnrovn_p95
+        ,ROUND(SUM(CASE WHEN cn_rovn IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS cnrovn_cov
+        -- ────── dnRovnScore(DN 流 1h+24h ROVN;当前权重=0)──────
+        ,ROUND(AVG(dn_rovn), 6)                              AS dnrovn_avg
+        ,ROUND(STDDEV_POP(dn_rovn), 6)                       AS dnrovn_std
+        ,ROUND(MIN(dn_rovn), 6)                              AS dnrovn_min
+        ,ROUND(MAX(dn_rovn), 6)                              AS dnrovn_max
+        ,ROUND(PERCENTILE_APPROX(dn_rovn, 0.50), 6)          AS dnrovn_p50
+        ,ROUND(PERCENTILE_APPROX(dn_rovn, 0.95), 6)          AS dnrovn_p95
+        ,ROUND(SUM(CASE WHEN dn_rovn IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS dnrovn_cov
+        -- ────── pLeave(PAI 模型预测离开概率原值)──────
+        ,ROUND(AVG(p_leave), 6)                              AS pleave_avg
+        ,ROUND(STDDEV_POP(p_leave), 6)                       AS pleave_std
+        ,ROUND(MIN(p_leave), 6)                              AS pleave_min
+        ,ROUND(MAX(p_leave), 6)                              AS pleave_max
+        ,ROUND(PERCENTILE_APPROX(p_leave, 0.50), 6)          AS pleave_p50
+        ,ROUND(PERCENTILE_APPROX(p_leave, 0.95), 6)          AS pleave_p95
+        ,ROUND(SUM(CASE WHEN p_leave IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS pleave_cov
+        -- ────── newPLeave = (1-leaveW·pLeave)^leaveExp(仅 565/566 真用进 finalScore)──────
+        ,ROUND(AVG(new_p_leave), 6)                          AS newpleave_avg
+        ,ROUND(STDDEV_POP(new_p_leave), 6)                   AS newpleave_std
+        ,ROUND(MIN(new_p_leave), 6)                          AS newpleave_min
+        ,ROUND(MAX(new_p_leave), 6)                          AS newpleave_max
+        ,ROUND(PERCENTILE_APPROX(new_p_leave, 0.50), 6)      AS newpleave_p50
+        ,ROUND(PERCENTILE_APPROX(new_p_leave, 0.95), 6)      AS newpleave_p95
+        ,ROUND(SUM(CASE WHEN new_p_leave IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS newpleave_cov
+        -- ────── reduceCoefficient(重排品类/节日降权乘子)──────
+        ,ROUND(AVG(reduce_coef), 6)                          AS reduce_avg
+        ,ROUND(STDDEV_POP(reduce_coef), 6)                   AS reduce_std
+        ,ROUND(MIN(reduce_coef), 6)                          AS reduce_min
+        ,ROUND(MAX(reduce_coef), 6)                          AS reduce_max
+        ,ROUND(PERCENTILE_APPROX(reduce_coef, 0.50), 6)      AS reduce_p50
+        ,ROUND(PERCENTILE_APPROX(reduce_coef, 0.95), 6)      AS reduce_p95
+        ,ROUND(SUM(CASE WHEN reduce_coef IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS reduce_cov
+FROM    t_scored
+GROUP BY dt, apptype, suffix_group
+GROUPING SETS (
+    (dt, apptype),                          -- 整体(1 行/apptype)
+    (dt, apptype, suffix_group)             -- 分尾号桶(8 行/apptype)
+)
+ORDER BY dt DESC, apptype, suffix_group
+;

+ 317 - 0
tasks/00_尾号实验/策略打分诊断/策略打分阈值分布_统一字段.sql

@@ -0,0 +1,317 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- 策略打分阈值分布【统一字段版】
+--   字段命名按业务量分类(_pred 模型预估 / _stat 历史统计 / 其他),
+--   不再暴露模型实现细节(XGB vs DNN)。
+--
+--   ┌─ 字段映射表 ──────────────────────────────────────────────────────┐
+--   │  scoresMap key             →  本 SQL 字段        含义              │
+--   │  ── 模型预估(_pred)──                                            │
+--   │  fmRov                     →  str_pred           STR 分享率预估    │
+--   │  fmRovOrigin               →  str_pred_origin    STR 反归一化前    │
+--   │  NorXGBScore | NorDNNScore →  ros_pred           ROS 分享后回流率  │
+--   │  ── 历史统计(_stat)──                                            │
+--   │  vor                       →  vor_stat           视频历史曝光裂变  │
+--   │  hasReturnRovScore         →  ros_stat           视频历史回流率    │
+--   │  c1RovnScore               →  c1_rovn_stat       一级品类 ROVN     │
+--   │  b0StrScore                →  b0_str_stat        B0 流 STR         │
+--   │  b0RorScore                →  b0_ror_stat        B0 流 ROR         │
+--   │  cnRovnScore               →  cn_rovn_stat       CN 流 ROVN        │
+--   │  dnRovnScore               →  dn_rovn_stat       DN 流 ROVN        │
+--   │  ── 其他 ──                                                        │
+--   │  pLeave                    →  p_leave            离开概率原值      │
+--   │  newPLeave                 →  new_p_leave        离开概率变换      │
+--   │  reduceCoefficient         →  reduce_coef        重排降权系数      │
+--   │  sample_all.score          →  final_score        线上最终分        │
+--   └────────────────────────────────────────────────────────────────────┘
+--
+--   ros_pred 的 COALESCE 行为:
+--     ┌─ apptype × suffix_group → 模型路径 ──┐
+--     │ XGB 路径:(0/01,34,67,89,ab) (4/全部除 2c/ef) → ros_pred = NorXGBScore │
+--     │ DNN 路径:(0/2c,5d,ef) (4/2c,ef)              → ros_pred = NorDNNScore │
+--     └────────────────────────────────────────┘
+--     COALESCE(NorXGBScore, NorDNNScore) 在主流量行级可信;
+--     极少数(<1%)幻象写入会让 COALESCE 返回错误值——靠 cov 列识别(cov<5% 时 _avg 不可信)
+--
+--   每个分数字段输出 7 列:avg / std / min / max / p50 / p95 / cov
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT 'a' AS suffix, 'ab' AS suffix_group
+    UNION ALL SELECT 'b', 'ab'
+    UNION ALL SELECT '0', '01'
+    UNION ALL SELECT '1', '01'
+    UNION ALL SELECT '2', '2c'
+    UNION ALL SELECT 'c', '2c'
+    UNION ALL SELECT '3', '34'
+    UNION ALL SELECT '4', '34'
+    UNION ALL SELECT '5', '5d'
+    UNION ALL SELECT 'd', '5d'
+    UNION ALL SELECT '6', '67'
+    UNION ALL SELECT '7', '67'
+    UNION ALL SELECT '8', '89'
+    UNION ALL SELECT '9', '89'
+    UNION ALL SELECT 'e', 'ef'
+    UNION ALL SELECT 'f', 'ef'
+)
+,t_experiment_map AS
+(
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验" AS abcode, "20260416" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "29991231"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260426", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:曝光建模v1+DNN模型",      "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+,t_exp_code_map AS
+(
+    SELECT "0" AS apptype, "89" AS suffix_group, "839" AS expcode, "20260425" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "89", "839", "20260425", "29991231"
+    UNION ALL SELECT "4", "ef", "562", "20260425", "29991231"
+    UNION ALL SELECT "0", "2c", "562", "20260425", "29991231"
+    UNION ALL SELECT "4", "2c", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "5d", "565", "20260425", "29991231"
+    UNION ALL SELECT "0", "34", "566", "20260425", "29991231"
+)
+-- 单条曝光 + 解 scoresmap,按业务量统一字段
+,t_scored AS
+(
+    SELECT  a.dt
+            ,a.apptype
+            ,a.mid
+            ,a.vid
+            ,sg.suffix_group
+            ,COALESCE(m.abcode, "对照组") AS abcode
+            ,e.expcode
+            -- ── 业务 label 透传 ──
+            ,a.is_share
+            ,a.share_cnt
+            ,a.is_return_1
+            ,a.is_return_n
+            ,a.is_return_noself
+            ,a.return_n_uv
+            ,a.return_n_uv_noself
+            ,a.new_exposure_cnt
+            -- ── 模型预估 ──
+            ,CAST(a.score AS DOUBLE)                                          AS final_score
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.fmRov')            AS DOUBLE) AS str_pred
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.fmRovOrigin')      AS DOUBLE) AS str_pred_origin
+            ,COALESCE(
+                CAST(GET_JSON_OBJECT(scoresmap, '$.NorXGBScore')   AS DOUBLE)
+              , CAST(GET_JSON_OBJECT(scoresmap, '$.NorDNNScore')   AS DOUBLE)
+             )                                                                AS ros_pred
+            -- ── 历史统计 ──
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.vor')              AS DOUBLE) AS vor_stat
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.hasReturnRovScore') AS DOUBLE) AS ros_stat
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.c1RovnScore')      AS DOUBLE) AS c1_rovn_stat
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.b0StrScore')       AS DOUBLE) AS b0_str_stat
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.b0RorScore')       AS DOUBLE) AS b0_ror_stat
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.cnRovnScore')      AS DOUBLE) AS cn_rovn_stat
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.dnRovnScore')      AS DOUBLE) AS dn_rovn_stat
+            -- ── 其他 ──
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.pLeave')           AS DOUBLE) AS p_leave
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.newPLeave')        AS DOUBLE) AS new_p_leave
+            ,CAST(GET_JSON_OBJECT(scoresmap, '$.reduceCoefficient') AS DOUBLE) AS reduce_coef
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,mid
+                        ,vid
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),
+                                LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,score
+                        ,REPLACE(GET_JSON_OBJECT(extend_alg,'$.scoresMap'),"\\","") AS scoresmap
+                        -- ── 业务 label(每条曝光的真实结果)──
+                        ,is_share              -- 0/1 是否被分享
+                        ,share_cnt             -- 分享次数
+                        ,is_return_1           -- 0/1 是否首跳回流
+                        ,is_return_n           -- 0/1 是否多跳回流
+                        ,is_return_noself      -- 0/1 是否回流(不含自己)★ str_real_noself 对应
+                        ,return_n_uv           -- 多跳回流 UV
+                        ,return_n_uv_noself    -- 多跳回流 UV(不含自己)★ ros_real_noself 对应
+                        ,new_exposure_cnt      -- 新增曝光(vovh24)
+                FROM    loghubods.dwd_recsys_alg_sample_all_20250212
+                WHERE   dt = '${dt}'
+                AND     apptype IN ('0','4')
+                AND     extend_alg IS NOT NULL
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     (apptype = "4" OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                AND     (apptype = "0" OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+            ) a
+    INNER JOIN t_suffix_group sg ON a.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+        ON  a.apptype = m.apptype
+        AND sg.suffix_group = m.suffix_group
+        AND '${dt}' BETWEEN m.start_dt AND m.end_dt
+    LEFT JOIN t_exp_code_map e
+        ON  a.apptype = e.apptype
+        AND sg.suffix_group = e.suffix_group
+        AND '${dt}' BETWEEN e.start_dt AND e.end_dt
+)
+SELECT  dt
+        ,apptype
+        ,COALESCE(suffix_group, '总体') AS suffix_group
+        ,MAX(abcode) AS abcode
+        ,MAX(expcode) AS expcode
+        -- ────── 样本量 ──────
+        ,COUNT(1) AS exp
+        ,COUNT(DISTINCT mid) AS dau
+        ,COUNT(DISTINCT vid) AS distinct_vid
+        -- ────── 业务真实值(label 聚合)──────
+        ,COALESCE(SUM(is_share),0) AS share_cnt_uv      -- 分享 UV 数(is_share=1 的曝光)
+        ,COALESCE(SUM(share_cnt),0) AS share_cnt        -- 分享次数总和
+        ,COALESCE(SUM(is_return_1),0) AS return_1_cnt   -- 首跳回流曝光数
+        ,COALESCE(SUM(is_return_n),0) AS return_n_cnt   -- 多跳回流曝光数
+        ,COALESCE(SUM(is_return_noself),0) AS return_noself_cnt  -- 多跳回流曝光数(不含自己)
+        ,COALESCE(SUM(return_n_uv),0) AS return_n_uv_sum         -- 多跳回流 UV 总和
+        ,COALESCE(SUM(return_n_uv_noself),0) AS return_n_uv_noself_sum -- 多跳回流 UV 不含自己
+        ,COALESCE(SUM(new_exposure_cnt),0) AS viewh24            -- 24 小时新增曝光
+        -- ────── 业务真实率(_real)──────
+        ,ROUND(COALESCE(SUM(is_share) / COUNT(1), 0), 6) AS str_one_real        -- 一跳分享率
+        ,ROUND(COALESCE(SUM(share_cnt) / COUNT(1), 0), 6) AS str_real           -- 分享率(含多次)
+        ,ROUND(COALESCE(SUM(is_return_noself) / COUNT(1), 0), 6) AS str_real_noself  -- ★ str_pred 的真实对照
+        ,ROUND(COALESCE(SUM(return_n_uv) / NULLIF(SUM(share_cnt), 0), 0), 6) AS ros_real
+        ,ROUND(COALESCE(SUM(return_n_uv_noself) / NULLIF(SUM(is_return_noself), 0), 0), 6) AS ros_real_noself  -- ★ ros_pred 的真实对照
+        ,ROUND(COALESCE(SUM(return_n_uv) / COUNT(1), 0), 6) AS rov_real
+        ,ROUND(COALESCE(SUM(return_n_uv_noself) / COUNT(1), 0), 6) AS rov_real_noself
+        ,ROUND(COALESCE(SUM(new_exposure_cnt) / COUNT(1), 0), 6) AS vovh24_real
+        -- ────── final_score(线上最终分)──────
+        ,ROUND(AVG(final_score), 6)                          AS finalscore_avg
+        ,ROUND(STDDEV_POP(final_score), 6)                   AS finalscore_std
+        ,ROUND(MIN(final_score), 6)                          AS finalscore_min
+        ,ROUND(MAX(final_score), 6)                          AS finalscore_max
+        ,ROUND(PERCENTILE_APPROX(final_score, 0.50), 6)      AS finalscore_p50
+        ,ROUND(PERCENTILE_APPROX(final_score, 0.95), 6)      AS finalscore_p95
+        ,ROUND(SUM(CASE WHEN final_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS finalscore_cov
+        -- ────── str_pred(STR 分享率预估)──────
+        ,ROUND(AVG(str_pred), 6)                             AS strpred_avg
+        ,ROUND(STDDEV_POP(str_pred), 6)                      AS strpred_std
+        ,ROUND(MIN(str_pred), 6)                             AS strpred_min
+        ,ROUND(MAX(str_pred), 6)                             AS strpred_max
+        ,ROUND(PERCENTILE_APPROX(str_pred, 0.50), 6)         AS strpred_p50
+        ,ROUND(PERCENTILE_APPROX(str_pred, 0.95), 6)         AS strpred_p95
+        ,ROUND(SUM(CASE WHEN str_pred IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS strpred_cov
+        -- ★ str_copc = str_real_noself / AVG(str_pred),> 1 表示模型低估
+        ,ROUND(SUM(is_return_noself) / NULLIF(SUM(str_pred), 0), 4) AS str_copc
+        -- ────── str_pred_origin(STR 反归一化前)──────
+        ,ROUND(AVG(str_pred_origin), 6)                      AS strpredorig_avg
+        ,ROUND(STDDEV_POP(str_pred_origin), 6)               AS strpredorig_std
+        ,ROUND(MIN(str_pred_origin), 6)                      AS strpredorig_min
+        ,ROUND(MAX(str_pred_origin), 6)                      AS strpredorig_max
+        ,ROUND(PERCENTILE_APPROX(str_pred_origin, 0.50), 6)  AS strpredorig_p50
+        ,ROUND(PERCENTILE_APPROX(str_pred_origin, 0.95), 6)  AS strpredorig_p95
+        ,ROUND(SUM(CASE WHEN str_pred_origin IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS strpredorig_cov
+        -- ────── ros_pred(ROS 分享后回流率预估,统一 XGB/DNN)──────
+        ,ROUND(AVG(ros_pred), 6)                             AS rospred_avg
+        ,ROUND(STDDEV_POP(ros_pred), 6)                      AS rospred_std
+        ,ROUND(MIN(ros_pred), 6)                             AS rospred_min
+        ,ROUND(MAX(ros_pred), 6)                             AS rospred_max
+        ,ROUND(PERCENTILE_APPROX(ros_pred, 0.50), 6)         AS rospred_p50
+        ,ROUND(PERCENTILE_APPROX(ros_pred, 0.95), 6)         AS rospred_p95
+        ,ROUND(SUM(CASE WHEN ros_pred IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS rospred_cov
+        -- ★ ros_copc = ros_real_noself / AVG(ros_pred when is_return_noself=1),仅在已分享回流条件下对比
+        ,ROUND(
+            (SUM(return_n_uv_noself) / NULLIF(SUM(is_return_noself), 0))
+            / NULLIF(AVG(CASE WHEN is_return_noself = 1 THEN ros_pred END), 0)
+        , 4) AS ros_copc
+        -- ★ rov_copc = rov_real_noself / AVG(str_pred × ros_pred)
+        ,ROUND(SUM(return_n_uv_noself) / NULLIF(SUM(str_pred * ros_pred), 0), 4) AS rov_copc
+        -- ────── vor_stat(视频历史曝光裂变率)──────
+        ,ROUND(AVG(vor_stat), 6)                             AS vorstat_avg
+        ,ROUND(STDDEV_POP(vor_stat), 6)                      AS vorstat_std
+        ,ROUND(MIN(vor_stat), 6)                             AS vorstat_min
+        ,ROUND(MAX(vor_stat), 6)                             AS vorstat_max
+        ,ROUND(PERCENTILE_APPROX(vor_stat, 0.50), 6)         AS vorstat_p50
+        ,ROUND(PERCENTILE_APPROX(vor_stat, 0.95), 6)         AS vorstat_p95
+        ,ROUND(SUM(CASE WHEN vor_stat IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS vorstat_cov
+        -- ────── ros_stat(视频历史回流率)──────
+        ,ROUND(AVG(ros_stat), 6)                             AS rosstat_avg
+        ,ROUND(STDDEV_POP(ros_stat), 6)                      AS rosstat_std
+        ,ROUND(MIN(ros_stat), 6)                             AS rosstat_min
+        ,ROUND(MAX(ros_stat), 6)                             AS rosstat_max
+        ,ROUND(PERCENTILE_APPROX(ros_stat, 0.50), 6)         AS rosstat_p50
+        ,ROUND(PERCENTILE_APPROX(ros_stat, 0.95), 6)         AS rosstat_p95
+        ,ROUND(SUM(CASE WHEN ros_stat IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS rosstat_cov
+        -- ────── c1_rovn_stat(一级品类 ROVN 统计加权)──────
+        ,ROUND(AVG(c1_rovn_stat), 6)                         AS c1rovn_avg
+        ,ROUND(STDDEV_POP(c1_rovn_stat), 6)                  AS c1rovn_std
+        ,ROUND(MIN(c1_rovn_stat), 6)                         AS c1rovn_min
+        ,ROUND(MAX(c1_rovn_stat), 6)                         AS c1rovn_max
+        ,ROUND(PERCENTILE_APPROX(c1_rovn_stat, 0.50), 6)     AS c1rovn_p50
+        ,ROUND(PERCENTILE_APPROX(c1_rovn_stat, 0.95), 6)     AS c1rovn_p95
+        ,ROUND(SUM(CASE WHEN c1_rovn_stat IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS c1rovn_cov
+        -- ────── b0_str_stat(B0 流 STR 统计加权;当前权重=0)──────
+        ,ROUND(AVG(b0_str_stat), 6)                          AS b0str_avg
+        ,ROUND(STDDEV_POP(b0_str_stat), 6)                   AS b0str_std
+        ,ROUND(MIN(b0_str_stat), 6)                          AS b0str_min
+        ,ROUND(MAX(b0_str_stat), 6)                          AS b0str_max
+        ,ROUND(PERCENTILE_APPROX(b0_str_stat, 0.50), 6)      AS b0str_p50
+        ,ROUND(PERCENTILE_APPROX(b0_str_stat, 0.95), 6)      AS b0str_p95
+        ,ROUND(SUM(CASE WHEN b0_str_stat IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS b0str_cov
+        -- ────── b0_ror_stat(B0 流 ROR 统计加权;当前权重=0)──────
+        ,ROUND(AVG(b0_ror_stat), 6)                          AS b0ror_avg
+        ,ROUND(STDDEV_POP(b0_ror_stat), 6)                   AS b0ror_std
+        ,ROUND(MIN(b0_ror_stat), 6)                          AS b0ror_min
+        ,ROUND(MAX(b0_ror_stat), 6)                          AS b0ror_max
+        ,ROUND(PERCENTILE_APPROX(b0_ror_stat, 0.50), 6)      AS b0ror_p50
+        ,ROUND(PERCENTILE_APPROX(b0_ror_stat, 0.95), 6)      AS b0ror_p95
+        ,ROUND(SUM(CASE WHEN b0_ror_stat IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS b0ror_cov
+        -- ────── cn_rovn_stat(CN 流 ROVN;当前权重=0)──────
+        ,ROUND(AVG(cn_rovn_stat), 6)                         AS cnrovn_avg
+        ,ROUND(STDDEV_POP(cn_rovn_stat), 6)                  AS cnrovn_std
+        ,ROUND(MIN(cn_rovn_stat), 6)                         AS cnrovn_min
+        ,ROUND(MAX(cn_rovn_stat), 6)                         AS cnrovn_max
+        ,ROUND(PERCENTILE_APPROX(cn_rovn_stat, 0.50), 6)     AS cnrovn_p50
+        ,ROUND(PERCENTILE_APPROX(cn_rovn_stat, 0.95), 6)     AS cnrovn_p95
+        ,ROUND(SUM(CASE WHEN cn_rovn_stat IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS cnrovn_cov
+        -- ────── dn_rovn_stat(DN 流 ROVN;当前权重=0)──────
+        ,ROUND(AVG(dn_rovn_stat), 6)                         AS dnrovn_avg
+        ,ROUND(STDDEV_POP(dn_rovn_stat), 6)                  AS dnrovn_std
+        ,ROUND(MIN(dn_rovn_stat), 6)                         AS dnrovn_min
+        ,ROUND(MAX(dn_rovn_stat), 6)                         AS dnrovn_max
+        ,ROUND(PERCENTILE_APPROX(dn_rovn_stat, 0.50), 6)     AS dnrovn_p50
+        ,ROUND(PERCENTILE_APPROX(dn_rovn_stat, 0.95), 6)     AS dnrovn_p95
+        ,ROUND(SUM(CASE WHEN dn_rovn_stat IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS dnrovn_cov
+        -- ────── p_leave(PAI 模型预测离开概率原值)──────
+        ,ROUND(AVG(p_leave), 6)                              AS pleave_avg
+        ,ROUND(STDDEV_POP(p_leave), 6)                       AS pleave_std
+        ,ROUND(MIN(p_leave), 6)                              AS pleave_min
+        ,ROUND(MAX(p_leave), 6)                              AS pleave_max
+        ,ROUND(PERCENTILE_APPROX(p_leave, 0.50), 6)          AS pleave_p50
+        ,ROUND(PERCENTILE_APPROX(p_leave, 0.95), 6)          AS pleave_p95
+        ,ROUND(SUM(CASE WHEN p_leave IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS pleave_cov
+        -- ────── new_p_leave = (1-leaveW·pLeave)^leaveExp ──────
+        ,ROUND(AVG(new_p_leave), 6)                          AS newpleave_avg
+        ,ROUND(STDDEV_POP(new_p_leave), 6)                   AS newpleave_std
+        ,ROUND(MIN(new_p_leave), 6)                          AS newpleave_min
+        ,ROUND(MAX(new_p_leave), 6)                          AS newpleave_max
+        ,ROUND(PERCENTILE_APPROX(new_p_leave, 0.50), 6)      AS newpleave_p50
+        ,ROUND(PERCENTILE_APPROX(new_p_leave, 0.95), 6)      AS newpleave_p95
+        ,ROUND(SUM(CASE WHEN new_p_leave IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS newpleave_cov
+        -- ────── reduce_coef(重排品类/节日降权)──────
+        ,ROUND(AVG(reduce_coef), 6)                          AS reduce_avg
+        ,ROUND(STDDEV_POP(reduce_coef), 6)                   AS reduce_std
+        ,ROUND(MIN(reduce_coef), 6)                          AS reduce_min
+        ,ROUND(MAX(reduce_coef), 6)                          AS reduce_max
+        ,ROUND(PERCENTILE_APPROX(reduce_coef, 0.50), 6)      AS reduce_p50
+        ,ROUND(PERCENTILE_APPROX(reduce_coef, 0.95), 6)      AS reduce_p95
+        ,ROUND(SUM(CASE WHEN reduce_coef IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS reduce_cov
+FROM    t_scored
+GROUP BY dt, apptype, suffix_group
+GROUPING SETS (
+    (dt, apptype),
+    (dt, apptype, suffix_group)
+)
+ORDER BY dt DESC, apptype, suffix_group
+;

+ 374 - 0
tasks/00_尾号实验/策略打分诊断/策略调权底层表.sql

@@ -0,0 +1,374 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- 策略调权实验底层表
+--   目的:为公式调权实验提供"参数化"的底层数据
+--        - 真实值(label 聚合)+ 模型原始/校准预估 + 其他分数分布
+--        - apollo 配置作为 CTE 维护,SQL 公式参数化(不写死数字)
+--        - 提供 str_pred_recompute 校验列(SQL 重算 vs 线上 fmRov 应几乎相等)
+--
+--   ┌─ 字段命名约定 ────────────────────────────────────────────────────┐
+--   │  真实值(无后缀):            str / strx / ros / rosx / rov / vovh24 │
+--   │  模型校准后预估(_pred):     str_pred / ros_pred / rov_pred       │
+--   │  模型原始预估(_origin):     str_origin / ros_origin / rov_origin │
+--   │  不需校准的字段(无后缀):    vor / ros_stat / c1_rovn / b0_str /    │
+--   │                              b0_ror / cn_rovn / dn_rovn / p_leave / │
+--   │                              new_p_leave / reduce_coef / final_score │
+--   │  校验列:str_pred_recompute(SQL 用 apollo 重算 fmRov,对比 scoresMap)│
+--   │  标识列:expcode_known(apollo 配置是否覆盖该桶;0 = fallback 用代码默认)│
+--   └────────────────────────────────────────────────────────────────────┘
+--
+--   ┌─ 业务对照(调权时按 expCode 配 pair)──────────────────────────────┐
+--   │  expCode    str_pair        ros/rov_pair                            │
+--   │  839(基线)strx ↔ str_pred  rosx ↔ ros_pred                          │
+--   │  566(新建模)str ↔ str_pred  ros ↔ ros_pred                          │
+--   │  562/563/565(DNN)str ↔ str_pred  rov ↔ rov_pred                     │
+--   └────────────────────────────────────────────────────────────────────┘
+--
+--   ┌─ 调权 what-if 流程 ────────────────────────────────────────────────┐
+--   │  1. 改 t_apollo_weight 的某个值(如 ros_add 从 0.1 → 0.05)         │
+--   │  2. 重跑 SQL → 看 ros_pred 分布变化                                  │
+--   │  3. 如果新增 finalScore 重算列(todo),可对比"假设 finalScore"vs真实  │
+--   │  4. 上线前先确认 str_pred_recompute ≈ scoresMap.fmRov(公式对齐)    │
+--   └────────────────────────────────────────────────────────────────────┘
+--
+--   每个分数字段输出 7 列:avg / std / min / max / p50 / p95 / cov
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT 'a' AS suffix, 'ab' AS suffix_group
+    UNION ALL SELECT 'b', 'ab'
+    UNION ALL SELECT '0', '01'
+    UNION ALL SELECT '1', '01'
+    UNION ALL SELECT '2', '2c'
+    UNION ALL SELECT 'c', '2c'
+    UNION ALL SELECT '3', '34'
+    UNION ALL SELECT '4', '34'
+    UNION ALL SELECT '5', '5d'
+    UNION ALL SELECT 'd', '5d'
+    UNION ALL SELECT '6', '67'
+    UNION ALL SELECT '7', '67'
+    UNION ALL SELECT '8', '89'
+    UNION ALL SELECT '9', '89'
+    UNION ALL SELECT 'e', 'ef'
+    UNION ALL SELECT 'f', 'ef'
+)
+,t_experiment_map AS
+(
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验" AS abcode, "20260416" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "29991231"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260426", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:曝光建模v1+DNN模型",      "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+,t_exp_code_map AS
+(
+    SELECT "0" AS apptype, "89" AS suffix_group, "839" AS expcode, "20260425" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "89", "839", "20260425", "29991231"
+    UNION ALL SELECT "4", "ef", "562", "20260425", "29991231"
+    UNION ALL SELECT "0", "2c", "562", "20260425", "29991231"
+    UNION ALL SELECT "4", "2c", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "5d", "565", "20260425", "29991231"
+    UNION ALL SELECT "0", "34", "566", "20260425", "29991231"
+)
+-- ┌─ apollo 配置(来源:tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/)─┐
+-- │  apollo 改了 → 只更新这个 CTE,其他 SQL 不动                              │
+-- │  缺失字段:未在 apollo 显式配的 → 走代码默认值                            │
+-- └────────────────────────────────────────────────────────────────────────┘
+,t_apollo_weight AS
+(
+    -- expcode  | xgb_neg_rate | power_w | power_exp | ros_add | ros_w | vor_add | vor_w | leave_w | leave_exp | c1_1h_w | c1_24h_w
+    SELECT '839' AS expcode, 0.055 AS xgb_neg_rate, 1.22 AS power_w, 1.15 AS power_exp,
+           0.1 AS ros_add, 1.0 AS ros_w, 0.1 AS vor_add, 1.0 AS vor_w,
+           CAST(NULL AS DOUBLE) AS leave_w, CAST(NULL AS DOUBLE) AS leave_exp,
+           0.5 AS c1_1h_w, 0.5 AS c1_24h_w
+    UNION ALL SELECT '562', 0.036, 0,    1,    0.1,   1.0, 0.1, 1.0, NULL, NULL, 0.5, 0.5
+    UNION ALL SELECT '563', 0.036, 0,    1,    0.001, 1.0, 0.1, 1.0, NULL, NULL, 0.5, 0.5
+    UNION ALL SELECT '565', 0.036, 0,    1,    0.1,   1.0, 0.1, 1.0, 1.0,  1.0,  0.5, 0.5
+    UNION ALL SELECT '566', 0.036, 1,    1,    0.1,   1.0, 0.1, 1.0, 1.0,  1.0,  0.5, 0.5
+)
+-- ════════════════════════════════════════════════════════════════════════════
+-- 第一步:单条曝光 + 解 scoresmap + JOIN apollo + SQL 校验列
+-- ════════════════════════════════════════════════════════════════════════════
+,t_scored AS
+(
+    SELECT  a.dt
+            ,a.apptype
+            ,a.mid
+            ,a.vid
+            ,sg.suffix_group
+            ,COALESCE(m.abcode, "对照组") AS abcode
+            ,e.expcode
+            ,CASE WHEN e.expcode IS NOT NULL THEN 1 ELSE 0 END AS expcode_known
+            -- ── 业务 label 透传 ──
+            ,a.is_share
+            ,a.share_cnt
+            ,a.is_return_1
+            ,a.is_return_n
+            ,a.is_return_noself
+            ,a.return_n_uv
+            ,a.return_n_uv_noself
+            ,a.new_exposure_cnt
+            -- ── 模型原始预估(_origin = 模型直接输出)──
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin')      AS DOUBLE) AS str_origin
+            ,COALESCE(
+                CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE)
+              )                                                                  AS ros_origin     -- 仅 XGB 路径有值(839/566)
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorDNNScore')      AS DOUBLE) AS rov_origin     -- 仅 DNN 路径有值(562/563/565)
+            -- ── 模型校准后预估(_pred = 经线上代码任何处理后的"用值")──
+            -- str_pred = fmRov(线上已 restoreScore,从 scoresMap 直接拿)
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRov')            AS DOUBLE) AS str_pred
+            -- ros_pred = newNorXGBScore(SQL 用 apollo power 校准重算;线上未 put 到 scoresMap)
+            -- 公式:max(score, w · score^exp), 上限 100, 下限 = score
+            ,CASE WHEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE) IS NOT NULL THEN
+                LEAST(100.0,
+                      GREATEST(
+                          CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE),
+                          COALESCE(w.power_w, 1.22) * POW(
+                              CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE),
+                              COALESCE(w.power_exp, 1.15)
+                          )
+                      ))
+             END                                                                 AS ros_pred
+            -- rov_pred = newNorDNNScore(线上 562/563/565 已 put 到 scoresMap)
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.newNorDNNScore')   AS DOUBLE) AS rov_pred
+            -- ── 校验列:SQL 用 apollo 重算 str_pred,对比线上 scoresMap.fmRov 应几乎相等 ──
+            -- 公式:str_pred_recompute = (w · str_origin) / (1 - (1-w) · str_origin)
+            ,CASE WHEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE) IS NOT NULL
+                  AND CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE) < 1
+                  AND COALESCE(w.xgb_neg_rate, 0.036) > 0 THEN
+                (COALESCE(w.xgb_neg_rate, 0.036) * CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE))
+                / NULLIF(1 - (1 - COALESCE(w.xgb_neg_rate, 0.036)) * CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE), 0)
+             END                                                                 AS str_pred_recompute
+            -- ── 不需校准的字段 ──
+            ,CAST(a.score                                            AS DOUBLE) AS final_score
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.vor')              AS DOUBLE) AS vor
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.hasReturnRovScore') AS DOUBLE) AS ros_stat
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.c1RovnScore')      AS DOUBLE) AS c1_rovn
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.b0StrScore')       AS DOUBLE) AS b0_str
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.b0RorScore')       AS DOUBLE) AS b0_ror
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.cnRovnScore')      AS DOUBLE) AS cn_rovn
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.dnRovnScore')      AS DOUBLE) AS dn_rovn
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.pLeave')           AS DOUBLE) AS p_leave
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.newPLeave')        AS DOUBLE) AS new_p_leave
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.reduceCoefficient') AS DOUBLE) AS reduce_coef
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,mid
+                        ,vid
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),
+                                LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,score
+                        ,REPLACE(GET_JSON_OBJECT(extend_alg,'$.scoresMap'),"\\","") AS scoresmap
+                        ,is_share, share_cnt, is_return_1, is_return_n, is_return_noself
+                        ,return_n_uv, return_n_uv_noself, new_exposure_cnt
+                FROM    loghubods.dwd_recsys_alg_sample_all_20250212
+                WHERE   dt = '${dt}'
+                AND     apptype IN ('0','4')
+                AND     extend_alg IS NOT NULL
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     (apptype = "4" OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                AND     (apptype = "0" OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+            ) a
+    INNER JOIN t_suffix_group sg ON a.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+        ON  a.apptype = m.apptype
+        AND sg.suffix_group = m.suffix_group
+        AND '${dt}' BETWEEN m.start_dt AND m.end_dt
+    LEFT JOIN t_exp_code_map e
+        ON  a.apptype = e.apptype
+        AND sg.suffix_group = e.suffix_group
+        AND '${dt}' BETWEEN e.start_dt AND e.end_dt
+    LEFT JOIN t_apollo_weight w
+        ON  e.expcode = w.expcode
+)
+-- ════════════════════════════════════════════════════════════════════════════
+-- 第二步:聚合到 (dt, apptype, suffix_group) 输出
+-- ════════════════════════════════════════════════════════════════════════════
+SELECT  dt
+        ,apptype
+        ,COALESCE(suffix_group, '总体') AS suffix_group
+        ,MAX(abcode) AS abcode
+        ,MAX(expcode) AS expcode
+        ,MAX(expcode_known) AS expcode_known
+        -- ────── 样本量 ──────
+        ,COUNT(1) AS exp
+        ,COUNT(DISTINCT mid) AS dau
+        ,COUNT(DISTINCT vid) AS distinct_vid
+        -- ────── 业务真实计数 ──────
+        ,COALESCE(SUM(is_share),0) AS share_uv
+        ,COALESCE(SUM(share_cnt),0) AS share_cnt
+        ,COALESCE(SUM(is_return_1),0) AS return_1_cnt
+        ,COALESCE(SUM(is_return_n),0) AS return_n_cnt
+        ,COALESCE(SUM(is_return_noself),0) AS return_noself_cnt
+        ,COALESCE(SUM(return_n_uv),0) AS return_n_uv_sum
+        ,COALESCE(SUM(return_n_uv_noself),0) AS return_n_uv_noself_sum
+        ,COALESCE(SUM(new_exposure_cnt),0) AS viewh24
+        -- ────── 业务真实率(无 _real 后缀,按命名约定)──────
+        ,ROUND(COALESCE(SUM(is_share) / COUNT(1), 0), 6) AS str                                       -- 新建模/DNN 真实
+        ,ROUND(COALESCE(SUM(is_return_noself) / COUNT(1), 0), 6) AS strx                              -- 基线 839 真实
+        ,ROUND(COALESCE(SUM(return_n_uv_noself) / NULLIF(SUM(is_share), 0), 0), 6) AS ros             -- 新建模 566 真实
+        ,ROUND(COALESCE(SUM(return_n_uv_noself) / NULLIF(SUM(is_return_noself), 0), 0), 6) AS rosx    -- 基线 839 真实
+        ,ROUND(COALESCE(SUM(return_n_uv_noself) / COUNT(1), 0), 6) AS rov                             -- DNN 562/563/565 真实
+        ,ROUND(COALESCE(SUM(new_exposure_cnt) / COUNT(1), 0), 6) AS vovh24
+        -- ────── final_score(线上最终分)──────
+        ,ROUND(AVG(final_score), 6)                          AS finalscore_avg
+        ,ROUND(STDDEV_POP(final_score), 6)                   AS finalscore_std
+        ,ROUND(MIN(final_score), 6)                          AS finalscore_min
+        ,ROUND(MAX(final_score), 6)                          AS finalscore_max
+        ,ROUND(PERCENTILE_APPROX(final_score, 0.50), 6)      AS finalscore_p50
+        ,ROUND(PERCENTILE_APPROX(final_score, 0.95), 6)      AS finalscore_p95
+        ,ROUND(SUM(CASE WHEN final_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS finalscore_cov
+        -- ────── str_origin(STR 模型原始预估,fmRovOrigin)──────
+        ,ROUND(AVG(str_origin), 6)                           AS strorigin_avg
+        ,ROUND(STDDEV_POP(str_origin), 6)                    AS strorigin_std
+        ,ROUND(MIN(str_origin), 6)                           AS strorigin_min
+        ,ROUND(MAX(str_origin), 6)                           AS strorigin_max
+        ,ROUND(PERCENTILE_APPROX(str_origin, 0.50), 6)       AS strorigin_p50
+        ,ROUND(PERCENTILE_APPROX(str_origin, 0.95), 6)       AS strorigin_p95
+        ,ROUND(SUM(CASE WHEN str_origin IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS strorigin_cov
+        -- ────── str_pred(STR 反归一化校准,fmRov 线上值)──────
+        ,ROUND(AVG(str_pred), 6)                             AS strpred_avg
+        ,ROUND(STDDEV_POP(str_pred), 6)                      AS strpred_std
+        ,ROUND(MIN(str_pred), 6)                             AS strpred_min
+        ,ROUND(MAX(str_pred), 6)                             AS strpred_max
+        ,ROUND(PERCENTILE_APPROX(str_pred, 0.50), 6)         AS strpred_p50
+        ,ROUND(PERCENTILE_APPROX(str_pred, 0.95), 6)         AS strpred_p95
+        ,ROUND(SUM(CASE WHEN str_pred IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS strpred_cov
+        -- ────── str_pred 校验(SQL 用 apollo 重算 vs 线上 fmRov 的 AVG 比值差)──────
+        -- restoreScore 是确定性公式:相同 fmRovOrigin + 相同 neg_rate → 每条曝光都等
+        -- 整体偏移仅可能因 apollo neg_rate 错配或线上动态推送漂移;diff_pct 一列足够
+        -- 解读:≈ 0 → 公式对齐 ✓;显著 ≠ 0 → 检查 t_apollo_weight 的 xgb_neg_rate
+        ,ROUND(AVG(str_pred_recompute) / NULLIF(AVG(str_pred), 0) - 1, 6) AS strpredre_diff_pct
+        -- ────── ros_origin(XGB 模型原始预估,839+566)──────
+        ,ROUND(AVG(ros_origin), 6)                           AS rosorigin_avg
+        ,ROUND(STDDEV_POP(ros_origin), 6)                    AS rosorigin_std
+        ,ROUND(MIN(ros_origin), 6)                           AS rosorigin_min
+        ,ROUND(MAX(ros_origin), 6)                           AS rosorigin_max
+        ,ROUND(PERCENTILE_APPROX(ros_origin, 0.50), 6)       AS rosorigin_p50
+        ,ROUND(PERCENTILE_APPROX(ros_origin, 0.95), 6)       AS rosorigin_p95
+        ,ROUND(SUM(CASE WHEN ros_origin IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS rosorigin_cov
+        -- ────── ros_pred(XGB power 校准后;SQL 重算)──────
+        ,ROUND(AVG(ros_pred), 6)                             AS rospred_avg
+        ,ROUND(STDDEV_POP(ros_pred), 6)                      AS rospred_std
+        ,ROUND(MIN(ros_pred), 6)                             AS rospred_min
+        ,ROUND(MAX(ros_pred), 6)                             AS rospred_max
+        ,ROUND(PERCENTILE_APPROX(ros_pred, 0.50), 6)         AS rospred_p50
+        ,ROUND(PERCENTILE_APPROX(ros_pred, 0.95), 6)         AS rospred_p95
+        ,ROUND(SUM(CASE WHEN ros_pred IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS rospred_cov
+        -- ────── rov_origin(DNN 模型原始预估,562/563/565)──────
+        ,ROUND(AVG(rov_origin), 6)                           AS rovorigin_avg
+        ,ROUND(STDDEV_POP(rov_origin), 6)                    AS rovorigin_std
+        ,ROUND(MIN(rov_origin), 6)                           AS rovorigin_min
+        ,ROUND(MAX(rov_origin), 6)                           AS rovorigin_max
+        ,ROUND(PERCENTILE_APPROX(rov_origin, 0.50), 6)       AS rovorigin_p50
+        ,ROUND(PERCENTILE_APPROX(rov_origin, 0.95), 6)       AS rovorigin_p95
+        ,ROUND(SUM(CASE WHEN rov_origin IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS rovorigin_cov
+        -- ────── rov_pred(DNN power 校准后,newNorDNNScore)──────
+        ,ROUND(AVG(rov_pred), 6)                             AS rovpred_avg
+        ,ROUND(STDDEV_POP(rov_pred), 6)                      AS rovpred_std
+        ,ROUND(MIN(rov_pred), 6)                             AS rovpred_min
+        ,ROUND(MAX(rov_pred), 6)                             AS rovpred_max
+        ,ROUND(PERCENTILE_APPROX(rov_pred, 0.50), 6)         AS rovpred_p50
+        ,ROUND(PERCENTILE_APPROX(rov_pred, 0.95), 6)         AS rovpred_p95
+        ,ROUND(SUM(CASE WHEN rov_pred IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS rovpred_cov
+        -- ────── vor(视频历史曝光裂变率,redis)──────
+        ,ROUND(AVG(vor), 6)                                  AS vor_avg
+        ,ROUND(STDDEV_POP(vor), 6)                           AS vor_std
+        ,ROUND(MIN(vor), 6)                                  AS vor_min
+        ,ROUND(MAX(vor), 6)                                  AS vor_max
+        ,ROUND(PERCENTILE_APPROX(vor, 0.50), 6)              AS vor_p50
+        ,ROUND(PERCENTILE_APPROX(vor, 0.95), 6)              AS vor_p95
+        ,ROUND(SUM(CASE WHEN vor IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS vor_cov
+        -- ────── ros_stat(视频历史回流率,redis hasReturnRovScore)──────
+        ,ROUND(AVG(ros_stat), 6)                             AS rosstat_avg
+        ,ROUND(STDDEV_POP(ros_stat), 6)                      AS rosstat_std
+        ,ROUND(MIN(ros_stat), 6)                             AS rosstat_min
+        ,ROUND(MAX(ros_stat), 6)                             AS rosstat_max
+        ,ROUND(PERCENTILE_APPROX(ros_stat, 0.50), 6)         AS rosstat_p50
+        ,ROUND(PERCENTILE_APPROX(ros_stat, 0.95), 6)         AS rosstat_p95
+        ,ROUND(SUM(CASE WHEN ros_stat IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS rosstat_cov
+        -- ────── c1_rovn(一级品类 ROVN 加性项)──────
+        ,ROUND(AVG(c1_rovn), 6)                              AS c1rovn_avg
+        ,ROUND(STDDEV_POP(c1_rovn), 6)                       AS c1rovn_std
+        ,ROUND(MIN(c1_rovn), 6)                              AS c1rovn_min
+        ,ROUND(MAX(c1_rovn), 6)                              AS c1rovn_max
+        ,ROUND(PERCENTILE_APPROX(c1_rovn, 0.50), 6)          AS c1rovn_p50
+        ,ROUND(PERCENTILE_APPROX(c1_rovn, 0.95), 6)          AS c1rovn_p95
+        ,ROUND(SUM(CASE WHEN c1_rovn IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS c1rovn_cov
+        -- ────── b0_str(B0 流 STR;当前权重=0 不参与打分)──────
+        ,ROUND(AVG(b0_str), 6)                               AS b0str_avg
+        ,ROUND(STDDEV_POP(b0_str), 6)                        AS b0str_std
+        ,ROUND(MIN(b0_str), 6)                               AS b0str_min
+        ,ROUND(MAX(b0_str), 6)                               AS b0str_max
+        ,ROUND(PERCENTILE_APPROX(b0_str, 0.50), 6)           AS b0str_p50
+        ,ROUND(PERCENTILE_APPROX(b0_str, 0.95), 6)           AS b0str_p95
+        ,ROUND(SUM(CASE WHEN b0_str IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS b0str_cov
+        -- ────── b0_ror(B0 流 ROR;当前权重=0)──────
+        ,ROUND(AVG(b0_ror), 6)                               AS b0ror_avg
+        ,ROUND(STDDEV_POP(b0_ror), 6)                        AS b0ror_std
+        ,ROUND(MIN(b0_ror), 6)                               AS b0ror_min
+        ,ROUND(MAX(b0_ror), 6)                               AS b0ror_max
+        ,ROUND(PERCENTILE_APPROX(b0_ror, 0.50), 6)           AS b0ror_p50
+        ,ROUND(PERCENTILE_APPROX(b0_ror, 0.95), 6)           AS b0ror_p95
+        ,ROUND(SUM(CASE WHEN b0_ror IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS b0ror_cov
+        -- ────── cn_rovn(CN 流 ROVN;当前权重=0)──────
+        ,ROUND(AVG(cn_rovn), 6)                              AS cnrovn_avg
+        ,ROUND(STDDEV_POP(cn_rovn), 6)                       AS cnrovn_std
+        ,ROUND(MIN(cn_rovn), 6)                              AS cnrovn_min
+        ,ROUND(MAX(cn_rovn), 6)                              AS cnrovn_max
+        ,ROUND(PERCENTILE_APPROX(cn_rovn, 0.50), 6)          AS cnrovn_p50
+        ,ROUND(PERCENTILE_APPROX(cn_rovn, 0.95), 6)          AS cnrovn_p95
+        ,ROUND(SUM(CASE WHEN cn_rovn IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS cnrovn_cov
+        -- ────── dn_rovn(DN 流 ROVN;当前权重=0)──────
+        ,ROUND(AVG(dn_rovn), 6)                              AS dnrovn_avg
+        ,ROUND(STDDEV_POP(dn_rovn), 6)                       AS dnrovn_std
+        ,ROUND(MIN(dn_rovn), 6)                              AS dnrovn_min
+        ,ROUND(MAX(dn_rovn), 6)                              AS dnrovn_max
+        ,ROUND(PERCENTILE_APPROX(dn_rovn, 0.50), 6)          AS dnrovn_p50
+        ,ROUND(PERCENTILE_APPROX(dn_rovn, 0.95), 6)          AS dnrovn_p95
+        ,ROUND(SUM(CASE WHEN dn_rovn IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS dnrovn_cov
+        -- ────── p_leave(PAI 模型预测离开概率原值)──────
+        ,ROUND(AVG(p_leave), 6)                              AS pleave_avg
+        ,ROUND(STDDEV_POP(p_leave), 6)                       AS pleave_std
+        ,ROUND(MIN(p_leave), 6)                              AS pleave_min
+        ,ROUND(MAX(p_leave), 6)                              AS pleave_max
+        ,ROUND(PERCENTILE_APPROX(p_leave, 0.50), 6)          AS pleave_p50
+        ,ROUND(PERCENTILE_APPROX(p_leave, 0.95), 6)          AS pleave_p95
+        ,ROUND(SUM(CASE WHEN p_leave IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS pleave_cov
+        -- ────── new_p_leave = (1-leaveW·pLeave)^leaveExp ──────
+        ,ROUND(AVG(new_p_leave), 6)                          AS newpleave_avg
+        ,ROUND(STDDEV_POP(new_p_leave), 6)                   AS newpleave_std
+        ,ROUND(MIN(new_p_leave), 6)                          AS newpleave_min
+        ,ROUND(MAX(new_p_leave), 6)                          AS newpleave_max
+        ,ROUND(PERCENTILE_APPROX(new_p_leave, 0.50), 6)      AS newpleave_p50
+        ,ROUND(PERCENTILE_APPROX(new_p_leave, 0.95), 6)      AS newpleave_p95
+        ,ROUND(SUM(CASE WHEN new_p_leave IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS newpleave_cov
+        -- ────── reduce_coef(重排品类/节日降权)──────
+        ,ROUND(AVG(reduce_coef), 6)                          AS reduce_avg
+        ,ROUND(STDDEV_POP(reduce_coef), 6)                   AS reduce_std
+        ,ROUND(MIN(reduce_coef), 6)                          AS reduce_min
+        ,ROUND(MAX(reduce_coef), 6)                          AS reduce_max
+        ,ROUND(PERCENTILE_APPROX(reduce_coef, 0.50), 6)      AS reduce_p50
+        ,ROUND(PERCENTILE_APPROX(reduce_coef, 0.95), 6)      AS reduce_p95
+        ,ROUND(SUM(CASE WHEN reduce_coef IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS reduce_cov
+FROM    t_scored
+GROUP BY dt, apptype, suffix_group
+GROUPING SETS (
+    (dt, apptype),                          -- 整体(1 行/apptype)
+    (dt, apptype, suffix_group)             -- 分尾号桶(8 行/apptype)
+)
+ORDER BY dt DESC, apptype, suffix_group
+;

+ 6 - 0
tasks/00_尾号实验/策略打分诊断/策略调权简表.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "DhgTD2",
+  "cols": null,
+  "append_cols": false
+}

+ 283 - 0
tasks/00_尾号实验/策略打分诊断/策略调权简表.sql

@@ -0,0 +1,283 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- 策略调权简表(精简版)
+--   设计:只保留每个字段的 AVG,**字段名直接用原物理量名**(不加 _avg 后缀)
+--        cov 列保留(兄弟列,监控覆盖率防幻象均值),用 _cov 后缀
+--
+--   ┌─ 字段命名 ────────────────────────────────────────────────────────┐
+--   │  真实值:str / strx / ros / rosx / rov / vovh24                    │
+--   │  模型预估:str_origin / str_pred / ros_origin / ros_pred /         │
+--   │           rov_origin / rov_pred                                    │
+--   │  其他不校准:vor / ros_stat / c1_rovn / b0_str / b0_ror /          │
+--   │             cn_rovn / dn_rovn / p_leave / new_p_leave /            │
+--   │             reduce_coef / final_score                              │
+--   │  覆盖率:每个分数列配 *_cov                                          │
+--   │  校验:strpredre_diff_pct(SQL 重算 vs 线上 fmRov 偏差)            │
+--   └────────────────────────────────────────────────────────────────────┘
+--
+--   ┌─ apollo 参数化 ───────────────────────────────────────────────────┐
+--   │  t_apollo_weight CTE 维护每个 expCode 的权重                       │
+--   │  apollo 改了 → 只更新 CTE,其他 SQL 不动                            │
+--   │  expcode 缺失走代码默认值(1.22 / 1.15),expcode_known=0 标识      │
+--   └────────────────────────────────────────────────────────────────────┘
+--
+--   ┌─ 调权 pair(按 expCode 对照真实/预估)────────────────────────────┐
+--   │  839(XGB 基线):strx ↔ str_pred ;rosx ↔ ros_pred                │
+--   │  566(XGB 新建模):str ↔ str_pred;ros ↔ ros_pred                  │
+--   │  562/563/565(DNN):str ↔ str_pred;rov ↔ rov_pred                 │
+--   └────────────────────────────────────────────────────────────────────┘
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT 'a' AS suffix, 'ab' AS suffix_group
+    UNION ALL SELECT 'b', 'ab'
+    UNION ALL SELECT '0', '01'
+    UNION ALL SELECT '1', '01'
+    UNION ALL SELECT '2', '2c'
+    UNION ALL SELECT 'c', '2c'
+    UNION ALL SELECT '3', '34'
+    UNION ALL SELECT '4', '34'
+    UNION ALL SELECT '5', '5d'
+    UNION ALL SELECT 'd', '5d'
+    UNION ALL SELECT '6', '67'
+    UNION ALL SELECT '7', '67'
+    UNION ALL SELECT '8', '89'
+    UNION ALL SELECT '9', '89'
+    UNION ALL SELECT 'e', 'ef'
+    UNION ALL SELECT 'f', 'ef'
+)
+,t_experiment_map AS
+(
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验" AS abcode, "20260416" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "29991231"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260426", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:曝光建模v1+DNN模型",      "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+,t_exp_code_map AS
+(
+    SELECT "0" AS apptype, "89" AS suffix_group, "839" AS expcode, "20260425" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "89", "839", "20260425", "29991231"
+    UNION ALL SELECT "4", "ef", "562", "20260425", "29991231"
+    UNION ALL SELECT "0", "2c", "562", "20260425", "29991231"
+    UNION ALL SELECT "4", "2c", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "5d", "565", "20260425", "29991231"
+    UNION ALL SELECT "0", "34", "566", "20260425", "29991231"
+)
+-- apollo 配置:来源 tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/
+,t_apollo_weight AS
+(
+    SELECT '839' AS expcode, 0.055 AS xgb_neg_rate, 1.22 AS power_w, 1.15 AS power_exp,
+           0.1 AS ros_add, 1.0 AS ros_w, 0.1 AS vor_add, 1.0 AS vor_w,
+           CAST(NULL AS DOUBLE) AS leave_w, CAST(NULL AS DOUBLE) AS leave_exp,
+           0.5 AS c1_1h_w, 0.5 AS c1_24h_w
+    UNION ALL SELECT '562', 0.036, 0,    1,    0.1,   1.0, 0.1, 1.0, NULL, NULL, 0.5, 0.5
+    UNION ALL SELECT '563', 0.036, 0,    1,    0.001, 1.0, 0.1, 1.0, NULL, NULL, 0.5, 0.5
+    UNION ALL SELECT '565', 0.036, 0,    1,    0.1,   1.0, 0.1, 1.0, 1.0,  1.0,  0.5, 0.5
+    UNION ALL SELECT '566', 0.036, 1,    1,    0.1,   1.0, 0.1, 1.0, 1.0,  1.0,  0.5, 0.5
+)
+-- 单条曝光级:解 scoresmap + 模型预估字段
+,t_scored AS
+(
+    SELECT  a.dt
+            ,a.apptype
+            ,a.mid
+            ,a.vid
+            ,sg.suffix_group
+            ,COALESCE(m.abcode, "对照组") AS abcode
+            ,e.expcode
+            ,CASE WHEN e.expcode IS NOT NULL THEN 1 ELSE 0 END AS expcode_known
+            -- ── 业务 label 透传 ──
+            ,a.is_share
+            ,a.share_cnt
+            ,a.is_return_1
+            ,a.is_return_n
+            ,a.is_return_noself
+            ,a.return_n_uv
+            ,a.return_n_uv_noself
+            ,a.new_exposure_cnt
+            -- ── 模型预估(按物理量拆字段,按 expCode 填值;没预估的 NULL)──
+            -- raw 字段(先解出 scoresMap 原始值)
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin')      AS DOUBLE) AS _fmrov_origin
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRov')            AS DOUBLE) AS _fmrov
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore')      AS DOUBLE) AS _nor_xgb
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorDNNScore')      AS DOUBLE) AS _nor_dnn
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.newNorDNNScore')   AS DOUBLE) AS _new_nor_dnn
+            -- power 校准后的 XGB(SQL 重算 newNorXGBScore,apollo 参数化)
+            ,CASE WHEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE) IS NOT NULL THEN
+                LEAST(100.0,
+                      GREATEST(
+                          CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE),
+                          COALESCE(w.power_w, 1.22) * POW(
+                              CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE),
+                              COALESCE(w.power_exp, 1.15)
+                          )
+                      ))
+             END                                                                  AS _new_nor_xgb
+            -- 按 expCode 分配字段(origin = 模型直出,pred = 校准后)
+            ,CASE WHEN e.expcode = '839' THEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE) END AS strx_origin
+            ,CASE WHEN e.expcode = '839' THEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRov')       AS DOUBLE) END AS strx_pred
+            ,CASE WHEN e.expcode IN ('562','563','565','566') THEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE) END AS str_origin
+            ,CASE WHEN e.expcode IN ('562','563','565','566') THEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRov')       AS DOUBLE) END AS str_pred
+            ,CASE WHEN e.expcode = '839' THEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE) END AS rosx_origin
+            ,CASE WHEN e.expcode = '566' THEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE) END AS ros_origin
+            ,CASE WHEN e.expcode IN ('562','563','565') THEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorDNNScore') AS DOUBLE) END AS rovx_origin
+            -- _pred 用 power 校准后值
+            ,CASE WHEN e.expcode = '839' THEN
+                LEAST(100.0, GREATEST(
+                    CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE),
+                    COALESCE(w.power_w, 1.22) * POW(CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE), COALESCE(w.power_exp, 1.15))
+                )) END AS rosx_pred
+            ,CASE WHEN e.expcode = '566' THEN
+                LEAST(100.0, GREATEST(
+                    CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE),
+                    COALESCE(w.power_w, 1.22) * POW(CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE), COALESCE(w.power_exp, 1.15))
+                )) END AS ros_pred
+            ,CASE WHEN e.expcode IN ('562','563','565') THEN
+                CAST(GET_JSON_OBJECT(a.scoresmap, '$.newNorDNNScore') AS DOUBLE) END AS rovx_pred
+            -- ── rov_pred 单条曝光级派生(统一物理量 = return_n_uv_noself / pv 预估)──
+            -- 839: strx_pred × rosx_pred
+            -- 566: str_pred × ros_pred
+            -- DNN(562/563/565): str_pred × rovx_pred
+            ,CASE
+                WHEN e.expcode = '839' THEN
+                    CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRov') AS DOUBLE) *
+                    LEAST(100.0, GREATEST(
+                        CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE),
+                        COALESCE(w.power_w, 1.22) * POW(CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE), COALESCE(w.power_exp, 1.15))
+                    ))
+                WHEN e.expcode = '566' THEN
+                    CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRov') AS DOUBLE) *
+                    LEAST(100.0, GREATEST(
+                        CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE),
+                        COALESCE(w.power_w, 1.22) * POW(CAST(GET_JSON_OBJECT(a.scoresmap, '$.NorXGBScore') AS DOUBLE), COALESCE(w.power_exp, 1.15))
+                    ))
+                WHEN e.expcode IN ('562','563','565') THEN
+                    CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRov') AS DOUBLE) *
+                    CAST(GET_JSON_OBJECT(a.scoresmap, '$.newNorDNNScore') AS DOUBLE)
+             END                                                                  AS rov_pred
+            -- ── 校验列:SQL 重算 str_pred ──
+            ,CASE WHEN CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE) IS NOT NULL
+                  AND CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE) < 1
+                  AND COALESCE(w.xgb_neg_rate, 0.036) > 0 THEN
+                (COALESCE(w.xgb_neg_rate, 0.036) * CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE))
+                / NULLIF(1 - (1 - COALESCE(w.xgb_neg_rate, 0.036)) * CAST(GET_JSON_OBJECT(a.scoresmap, '$.fmRovOrigin') AS DOUBLE), 0)
+             END                                                                  AS str_pred_recompute
+            -- ── 不需校准的字段 ──
+            ,CAST(a.score                                            AS DOUBLE) AS final_score
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.vor')              AS DOUBLE) AS vor
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.hasReturnRovScore') AS DOUBLE) AS ros_stat
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.c1RovnScore')      AS DOUBLE) AS c1_rovn
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.b0StrScore')       AS DOUBLE) AS b0_str
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.b0RorScore')       AS DOUBLE) AS b0_ror
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.cnRovnScore')      AS DOUBLE) AS cn_rovn
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.dnRovnScore')      AS DOUBLE) AS dn_rovn
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.pLeave')           AS DOUBLE) AS p_leave
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.newPLeave')        AS DOUBLE) AS new_p_leave
+            ,CAST(GET_JSON_OBJECT(a.scoresmap, '$.reduceCoefficient') AS DOUBLE) AS reduce_coef
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,mid
+                        ,vid
+                        ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),
+                                LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                        ,score
+                        ,REPLACE(GET_JSON_OBJECT(extend_alg,'$.scoresMap'),"\\","") AS scoresmap
+                        ,is_share, share_cnt, is_return_1, is_return_n, is_return_noself
+                        ,return_n_uv, return_n_uv_noself, new_exposure_cnt
+                FROM    loghubods.dwd_recsys_alg_sample_all_20250212
+                WHERE   dt = '${dt}'
+                AND     apptype IN ('0','4')
+                AND     extend_alg IS NOT NULL
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode NOT IN ("ab100")
+                AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
+            ) a
+    INNER JOIN t_suffix_group sg ON a.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+        ON  a.apptype = m.apptype
+        AND sg.suffix_group = m.suffix_group
+        AND '${dt}' BETWEEN m.start_dt AND m.end_dt
+    LEFT JOIN t_exp_code_map e
+        ON  a.apptype = e.apptype
+        AND sg.suffix_group = e.suffix_group
+        AND '${dt}' BETWEEN e.start_dt AND e.end_dt
+    LEFT JOIN t_apollo_weight w ON e.expcode = w.expcode
+)
+-- 聚合输出:每个分数只 AVG(字段名 = 原物理量名,不加 _avg),配 *_cov
+SELECT  dt
+        ,apptype
+        ,COALESCE(suffix_group, '总体') AS suffix_group
+        ,MAX(abcode) AS abcode
+        ,MAX(expcode) AS expcode
+        ,MAX(expcode_known) AS expcode_known
+        -- ── 样本量 ──
+        ,COUNT(1) AS exp
+        ,COUNT(DISTINCT mid) AS dau
+        ,COUNT(DISTINCT vid) AS distinct_vid
+        -- ── 业务真实计数(字段名 = 原 label 名,聚合是 SUM)──
+        ,COALESCE(SUM(is_share),0) AS is_share
+        ,COALESCE(SUM(share_cnt),0) AS share_cnt
+        ,COALESCE(SUM(is_return_noself),0) AS is_return_noself
+        ,COALESCE(SUM(return_n_uv_noself),0) AS return_n_uv_noself
+        ,COALESCE(SUM(new_exposure_cnt),0) AS new_exposure_cnt
+        -- ── 业务真实率(无后缀)──
+        ,ROUND(COALESCE(SUM(is_share) / COUNT(1), 0), 6) AS str
+        ,ROUND(COALESCE(SUM(is_return_noself) / COUNT(1), 0), 6) AS strx
+        ,ROUND(COALESCE(SUM(return_n_uv_noself) / NULLIF(SUM(is_share), 0), 0), 6) AS ros
+        ,ROUND(COALESCE(SUM(return_n_uv_noself) / NULLIF(SUM(is_return_noself), 0), 0), 6) AS rosx
+        ,ROUND(COALESCE(SUM(return_n_uv_noself) / COUNT(1), 0), 6) AS rov
+        ,ROUND(COALESCE(SUM(new_exposure_cnt) / COUNT(1), 0), 6) AS vovh24
+        -- ── 模型预估 AVG(按物理量拆,按 expCode 自动 NULL 不该填的)──
+        -- 基线 839 路径
+        ,ROUND(AVG(strx_origin), 6)  AS strx_origin
+        ,ROUND(AVG(strx_pred), 6)    AS strx_pred
+        ,ROUND(AVG(rosx_origin), 6)  AS rosx_origin
+        ,ROUND(AVG(rosx_pred), 6)    AS rosx_pred
+        -- 新建模 + DNN 路径(str 共享)
+        ,ROUND(AVG(str_origin), 6)   AS str_origin
+        ,ROUND(AVG(str_pred), 6)     AS str_pred
+        -- 新建模 566 路径
+        ,ROUND(AVG(ros_origin), 6)   AS ros_origin
+        ,ROUND(AVG(ros_pred), 6)     AS ros_pred
+        -- DNN 562/563/565 路径
+        ,ROUND(AVG(rovx_origin), 6)  AS rovx_origin
+        ,ROUND(AVG(rovx_pred), 6)    AS rovx_pred
+        -- 派生:单条曝光级 str×ros(或 strx×rosx 或 str×rovx)求平均,跨 expCode 物理量统一
+        ,ROUND(AVG(rov_pred), 6)     AS rov_pred
+        -- ── 校验:SQL 重算 vs 线上 fmRov 偏差,≈0 = 公式对齐 ──
+        ,ROUND(AVG(str_pred_recompute) / NULLIF(AVG(_fmrov), 0) - 1, 6) AS strpredre_diff_pct
+        -- ── 其他不校准字段 AVG ──
+        ,ROUND(AVG(final_score), 6)  AS final_score
+        ,ROUND(AVG(vor), 6)          AS vor
+        ,ROUND(AVG(ros_stat), 6)     AS ros_stat
+        ,ROUND(AVG(c1_rovn), 6)      AS c1_rovn
+        ,ROUND(AVG(b0_str), 6)       AS b0_str
+        ,ROUND(AVG(b0_ror), 6)       AS b0_ror
+        ,ROUND(AVG(cn_rovn), 6)      AS cn_rovn
+        ,ROUND(AVG(dn_rovn), 6)      AS dn_rovn
+        ,ROUND(AVG(p_leave), 6)      AS p_leave
+        ,ROUND(AVG(new_p_leave), 6)  AS new_p_leave
+        ,ROUND(AVG(reduce_coef), 6)  AS reduce_coef
+        -- ── 全局数据质量监控 ──
+        ,ROUND(SUM(CASE WHEN final_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1), 4) AS scoresmap_coverage
+FROM    t_scored
+GROUP BY dt, apptype, suffix_group
+GROUPING SETS (
+    (dt, apptype),
+    (dt, apptype, suffix_group)
+)
+ORDER BY dt DESC, apptype, suffix_group
+;

+ 10 - 0
tasks/00_尾号实验/策略打分诊断/策略阶段分数panel.json

@@ -0,0 +1,10 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "xNAGkd",
+  "sort": "dt:desc,apptype:asc,suffix_group:asc,source_type:asc,layer_type:asc",
+  "order": {
+      "suffix_group": ["ab", "34", "2c", "67", "01", "5d", "ef", "89"]
+  },
+  "cols": null,
+  "append_cols": false
+}

+ 959 - 0
tasks/00_尾号实验/策略打分诊断/策略阶段分数panel.sql

@@ -0,0 +1,959 @@
+-- ════════════════════════════════════════════════════════════════════════════
+-- 策略阶段分数 panel(底层宽表)
+--   目的:分析各个 expCode 策略的「最终打分 + 阶段子分数」
+--        - 是否正常(AVG/STDDEV 时序,分布稳定性)
+--        - 策略间差异(横向对比 fmRov / NorXXScore / vor / c1Rovn / b0Str / ... 各阶段)
+--
+--   行粒度沿用 base_all_new_v3_分层.sql:
+--     dt × apptype × abcode × suffix_group × source_type × layer_type
+--   分数 _diff 不在底层做(diff 由上层分析视图按需即席算);业务 _diff 保留
+--
+-- ┌─ 数据源切换 ────────────────────────────────────────────────────────┐
+-- │  原 base SQL:dwd_recsys_alg_exposure_base_20250108                 │
+-- │  本   SQL:dwd_recsys_alg_sample_all_20250212                      │
+-- │  二者关系:sample_all = base + LEFT JOIN statistics_log + 各特征表 │
+-- │           曝光行集合一致;scoresMap 装在 sample_all.extend_alg     │
+-- │           finalScore 装在 sample_all.score(STRING,CAST DOUBLE)  │
+-- │  scoresMap=NULL(埋点丢失)的曝光不过滤:                           │
+-- │    - 业务指标(dau/exp/str/ros/...)和 base SQL 完全对齐            │
+-- │    - 分数列 AVG/STDDEV 自动 IGNORE NULLS                            │
+-- │    - 单列 scoresmap_coverage 监控覆盖率                             │
+-- └────────────────────────────────────────────────────────────────────┘
+--
+-- ┌─ scoresMap 字段口径(直读 RankStrategy*.java + raw scoresmap 验证)──┐
+-- │  expCode             839   562   563   565   566   ★备注              │
+-- │  ── 召回分 ──                                                         │
+-- │  fmRovOrigin         ✅    ✅    ✅    ✅    ✅   FM 反归一化前       │
+-- │  fmRov               ✅    ✅    ✅    ✅    ✅   = restoreScore(...)   │
+-- │  ── 排序模型分(XGB 与 DNN 互斥;Scorer pipeline 自动写入)──         │
+-- │  NorXGBScore         ✅(*1) -     -     -    ✅(*1) Scorer 写         │
+-- │  NorDNNScore         -    ✅    ✅    ✅    -    Scorer 写            │
+-- │  newNorDNNScore      -    ✅    ✅    ✅    -    norPower 校准后       │
+-- │  ── 业务先验 ──                                                       │
+-- │  hasReturnRovScore   ✅    ✅    ✅    ✅    ✅   redis vid:rov         │
+-- │  vor                 ✅    ✅    ✅    ✅    ✅   redis vid:vor         │
+-- │  ── 加性项 (1h+24h 加权和) ──                                         │
+-- │  c1RovnScore         ✅    ✅    ✅    ✅    ✅                        │
+-- │  b0StrScore          ✅    ✅    ✅    ✅    ✅   线上权重当前=0       │
+-- │  b0RorScore          ✅    ✅    ✅    ✅    ✅   线上权重当前=0       │
+-- │  cnRovnScore         -    ✅    ✅    ✅    ✅   线上权重当前=0       │
+-- │  dnRovnScore         -    ✅    ✅    ✅    ✅   线上权重当前=0       │
+-- │  ── 离开概率 ──                                                       │
+-- │  pLeave              ⚠️(*2) -     -    ✅    ✅   原始离开概率         │
+-- │  newPLeave           -     -     -    ✅    ✅   = (1-w·pL)^exp      │
+-- │  ── 重排阶段降权 (RankProcessorBoost) ──                              │
+-- │  reduceCoefficient   ✅    ✅    ✅    ✅    ✅   ★乘进 finalScore     │
+-- │  ── 最终分(独立列 sample_all.score)──                               │
+-- │  finalScore          ✅    ✅    ✅    ✅    ✅                        │
+-- │                                                                       │
+-- │  (*1) newNorXGBScore 在 839/566 中算了但**未写回 scoresMap**         │
+-- │       想用必须 SQL 重算 weight × pow(NorXGBScore, exp)(含钳位)      │
+-- │  (*2) apptype=4 的 839 的 pLeave≈0.52 是 Scorer fallback 值,**不是   │
+-- │       真实离开概率模型输出**——跨 expCode 比较时要排除该行            │
+-- │                                                                       │
+-- │  线上 finalScore 计算(按 expCode 分):                              │
+-- │    score_pre =                                                        │
+-- │      839: fmRov × (rosAdd+rosW·newNorXGBScore)                       │
+-- │           × (vorAdd+vorW·vor)                                         │
+-- │           + c1+b0Str+b0Ror                                            │
+-- │      562/563: fmRov × (rosAdd+rosW·newNorDNNScore)                   │
+-- │               × (vorAdd+vorW·vor)                                     │
+-- │               + c1+b0Str+b0Ror+cn+dn                                  │
+-- │      565: fmRov × (rosAdd+rosW·newNorDNNScore)                        │
+-- │           × (vorAdd+vorW·vor) × newPLeave                             │
+-- │           + c1+b0Str+b0Ror+cn+dn                                      │
+-- │      566: fmRov × (rosAdd+rosW·newNorXGBScore)                        │
+-- │           × (vorAdd+vorW·vor) × newPLeave                             │
+-- │           + c1+b0Str+b0Ror+cn+dn                                      │
+-- │    finalScore = score_pre × reduceCoefficient  ← 重排阶段最后乘       │
+-- └────────────────────────────────────────────────────────────────────┘
+--
+-- ┌─ 流量配置维护 ──────────────────────────────────────────────────────┐
+-- │  t_exp_code_map 仅录入 20260425 当前生效配置                         │
+-- │  来源:tasks/00_尾号实验/线上实验配置/流量配置/{date}.json           │
+-- │  实验切流时追加新行(同 t_experiment_map 的 SCD Type 2 模式)       │
+-- └────────────────────────────────────────────────────────────────────┘
+-- ════════════════════════════════════════════════════════════════════════════
+WITH t_suffix_group AS
+(
+    SELECT "a" AS suffix, "ab" AS suffix_group
+    UNION ALL SELECT "b", "ab"
+    UNION ALL SELECT "0", "01"
+    UNION ALL SELECT "1", "01"
+    UNION ALL SELECT "2", "2c"
+    UNION ALL SELECT "c", "2c"
+    UNION ALL SELECT "3", "34"
+    UNION ALL SELECT "4", "34"
+    UNION ALL SELECT "5", "5d"
+    UNION ALL SELECT "d", "5d"
+    UNION ALL SELECT "6", "67"
+    UNION ALL SELECT "7", "67"
+    UNION ALL SELECT "8", "89"
+    UNION ALL SELECT "9", "89"
+    UNION ALL SELECT "e", "ef"
+    UNION ALL SELECT "f", "ef"
+)
+,t_experiment_map AS
+(
+    -- ── apptype = 4 ──
+    SELECT "4" AS apptype, "ab" AS suffix_group, "实验组:变更str*ros建模目标实验 有问题" AS abcode, "20260413" AS start_dt, "20260415" AS end_dt
+    UNION ALL SELECT "4", "ab", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "67", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "5d", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "4", "34", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "4", "67", "实验组:bn_ros新损失函数",        "20260311", "20260319"
+    UNION ALL SELECT "4", "5d", "实验组:解构特征排序str模型",     "20260314", "20260406"
+    UNION ALL SELECT "4", "ef", "实验组:解构特征排序str模型&召回", "20260314", "20260320"
+    UNION ALL SELECT "4", "ef", "实验组:DNN模型",                 "20260407", "29991231"
+    UNION ALL SELECT "4", "2c", "实验组:DNN模型-调参",            "20260413", "29991231"
+    UNION ALL SELECT "4", "89", "对照组",                          "20260301", "299991231"
+
+    -- ── apptype = 0 ──
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验 有问题", "20260413", "20260415"
+    UNION ALL SELECT "0", "ab", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "ab", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260320", "20260410"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "01", "实验组:变更str*ros建模目标实验", "20260416", "29991231"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "34", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260417", "20260424"
+    UNION ALL SELECT "0", "34", "实验组:曝光建模v1+变更str*ros建模目标实验", "20260425", "20260425"
+    UNION ALL SELECT "0", "34", "实验组:变更str*ros建模目标实验", "20260426", "29991231"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260330", "20260410"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "67", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "67", "实验组:变更str*ros建模目标实验", "20260417", "29991231"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260407", "20260410"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验 有问题", "20260411", "20260415"
+    UNION ALL SELECT "0", "5d", "实验组:DNN模型-调参", "20260416", "20260416"
+    UNION ALL SELECT "0", "5d", "实验组:变更str*ros建模目标实验", "20260417", "20260424"
+    UNION ALL SELECT "0", "5d", "实验组:曝光建模v1+DNN模型", "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "实验组:DNN模型-调参",            "20260410", "29991231"
+    UNION ALL SELECT "0", "2c", "实验组:DNN模型",                 "20260413", "29991231"
+    UNION ALL SELECT "0", "89", "对照组",                          "20260301", "29991231"
+)
+-- ┌─ 流量配置 → expCode 映射 ──────────────────────────────────────────┐
+-- │  来源:tasks/00_尾号实验/线上实验配置/流量配置/20260425.json        │
+-- │  仅录入 20260425 起当前生效;流量切流时按 SCD Type 2 追加新行       │
+-- └────────────────────────────────────────────────────────────────────┘
+,t_exp_code_map AS
+(
+    SELECT "0" AS apptype, "89" AS suffix_group, "839" AS expcode, "20260425" AS start_dt, "29991231" AS end_dt
+    UNION ALL SELECT "4", "89", "839", "20260425", "29991231"
+    UNION ALL SELECT "4", "ef", "562", "20260425", "29991231"
+    UNION ALL SELECT "0", "2c", "562", "20260425", "29991231"
+    UNION ALL SELECT "4", "2c", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "ef", "563", "20260425", "29991231"
+    UNION ALL SELECT "0", "5d", "565", "20260425", "29991231"
+    UNION ALL SELECT "0", "34", "566", "20260425", "29991231"
+)
+,t_base AS
+(
+    SELECT  sub.*
+            ,sg.suffix_group
+            ,COALESCE(m.abcode,"对照组") AS abcode
+    FROM    (
+                -- 第二层:从 scoresmap 解 12 个子分数(scoresmap 已在内层解出来一次,避免重复 GET_JSON_OBJECT)
+                SELECT  inner_sub.*
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.fmRov')              AS DOUBLE) AS fmrov
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.fmRovOrigin')        AS DOUBLE) AS fmrov_origin
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.NorXGBScore')        AS DOUBLE) AS nor_xgb_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.NorDNNScore')        AS DOUBLE) AS nor_dnn_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.newNorDNNScore')     AS DOUBLE) AS new_nor_dnn_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.hasReturnRovScore')  AS DOUBLE) AS has_return_rov_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.vor')                AS DOUBLE) AS vor_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.c1RovnScore')        AS DOUBLE) AS c1_rovn_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.b0StrScore')         AS DOUBLE) AS b0_str_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.b0RorScore')         AS DOUBLE) AS b0_ror_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.cnRovnScore')        AS DOUBLE) AS cn_rovn_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.dnRovnScore')        AS DOUBLE) AS dn_rovn_score
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.pLeave')             AS DOUBLE) AS p_leave
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.newPLeave')          AS DOUBLE) AS new_p_leave
+                        -- reduceCoefficient: 重排阶段的视频降权系数(品类降权/节日降权),
+                        -- 直接乘进 sample_all.score 列。<1 表示该曝光被降权
+                        ,CAST(GET_JSON_OBJECT(scoresmap, '$.reduceCoefficient')  AS DOUBLE) AS reduce_coefficient
+                FROM    (
+                            -- 第一层:从 sample_all 拉曝光 + label + cc/dd + 解 final_score / scoresmap raw
+                            SELECT  dt
+                                    ,apptype
+                                    ,SUBSTR(GET_JSON_OBJECT(extend,'$.rootsessionid'),LENGTH(GET_JSON_OBJECT(extend,'$.rootsessionid')),1) AS suffix
+                                    ,CASE   WHEN page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页") THEN "推荐"
+                                            WHEN page IN ("回流页","其他") THEN "非推荐"
+                                            ELSE "其他"
+                                    END AS page
+                                    ,CASE WHEN a.rootsourceid = '' OR a.rootsourceid IS NULL THEN '内部' ELSE '外部' END AS source_type
+                                    ,CASE WHEN GET_JSON_OBJECT(a.extend,'$.rootsessionid') = a.subsessionid THEN '首层' ELSE '裂变层' END AS layer_type
+                                    ,a.mid
+                                    ,a.vid
+                                    ,is_share
+                                    ,share_cnt
+                                    ,is_return_1
+                                    ,is_return_n
+                                    ,is_return_noself
+                                    ,return_1_uv
+                                    ,return_n_uv
+                                    ,return_n_uv_noself
+                                    ,new_exposure_cnt
+                                    ,flowpool
+                                    ,cc.cn
+                                    ,cc.c1
+                                    ,dd.dn
+                                    ,dd.d1
+                                    -- 新增:finalScore + scoresMap raw(scoresMap 在 extend_alg 里)
+                                    ,CAST(a.score AS DOUBLE) AS final_score
+                                    ,REPLACE(GET_JSON_OBJECT(a.extend_alg,'$.scoresMap'),"\\","") AS scoresmap
+                            FROM    loghubods.dwd_recsys_alg_sample_all_20250212 a
+                            LEFT JOIN   (
+                                            -- c1/cn:分享后被点击的回流 UV(同 base SQL)
+                                            SELECT  a.machinecode AS mid
+                                                    ,a.subsessionid
+                                                    ,a.videoid AS vid
+                                                    ,COUNT(DISTINCT CASE WHEN b1.machinecode <> b2.machinecode THEN b2.machinecode END) AS cn
+                                                    ,COUNT(DISTINCT CASE WHEN b2.sharedepth = 1 AND b1.machinecode <> b2.machinecode THEN b2.machinecode END) AS c1
+                                            FROM    (
+                                                        SELECT  DISTINCT machinecode
+                                                                ,shareobjectid AS videoid
+                                                                ,recomTraceId
+                                                                ,subsessionid
+                                                                ,sharedepth
+                                                                ,shareid
+                                                        FROM    loghubods.user_share_log
+                                                        WHERE   dt = '${dt}'
+                                                        AND     topic = 'share'
+                                                        AND     pagesource REGEXP 'category$|recommend$|-pages/user-videos-detail$'
+                                                    ) a
+                                            LEFT JOIN   (
+                                                            SELECT  DISTINCT machinecode
+                                                                    ,clickobjectid
+                                                                    ,recomTraceId
+                                                                    ,subsessionid
+                                                                    ,sharedepth
+                                                                    ,rootshareid
+                                                            FROM    loghubods.user_share_log
+                                                            WHERE   dt = '${dt}'
+                                                            AND     topic = 'click'
+                                                        ) b
+                                            ON      a.shareid = b.rootshareid
+                                            LEFT JOIN   (
+                                                            SELECT  DISTINCT machinecode
+                                                                    ,shareobjectid
+                                                                    ,recomTraceId
+                                                                    ,subsessionid
+                                                                    ,sharedepth
+                                                                    ,shareid
+                                                            FROM    loghubods.user_share_log
+                                                            WHERE   dt = '${dt}'
+                                                            AND     topic = 'share'
+                                                            AND     pagesource REGEXP 'category$|recommend$|-pages/user-videos-detail$'
+                                                        ) b1
+                                            ON      b.machinecode = b1.machinecode
+                                            AND     b.subsessionid = b1.subsessionid
+                                            LEFT JOIN   (
+                                                            SELECT  DISTINCT machinecode
+                                                                    ,clickobjectid
+                                                                    ,recomTraceId
+                                                                    ,subsessionid
+                                                                    ,sharedepth
+                                                                    ,shareid
+                                                                    ,rootshareid
+                                                            FROM    loghubods.user_share_log
+                                                            WHERE   dt = '${dt}'
+                                                            AND     topic = 'click'
+                                                        ) b2
+                                            ON      b1.shareid = b2.rootshareid
+                                            GROUP BY a.machinecode
+                                                     ,a.subsessionid
+                                                     ,a.videoid
+                                        ) cc
+                            ON      a.mid = cc.mid
+                            AND     a.subsessionid = cc.subsessionid
+                            AND     a.vid = cc.vid
+                            LEFT JOIN   (
+                                            -- d1/dn:下一条视频带来的回流(同 base SQL)
+                                            SELECT  *
+                                                    ,LAG(回流,1,0) OVER (PARTITION BY mid,subsessionid ORDER BY rn DESC) AS dn
+                                                    ,LAG(回流1,1,0) OVER (PARTITION BY mid,subsessionid ORDER BY rn DESC) AS d1
+                                            FROM    (
+                                                        SELECT  a.mid AS mid
+                                                                ,a.subsessionid
+                                                                ,a.videoid AS vid
+                                                                ,COUNT(DISTINCT b.shareid) AS 分享次数
+                                                                ,COUNT(DISTINCT CASE WHEN c.machinecode <> b.machinecode THEN c.machinecode END) AS 回流
+                                                                ,COUNT(DISTINCT CASE WHEN c.machinecode <> b.machinecode AND c.sharedepth = 1 THEN c.machinecode END) AS 回流1
+                                                                ,ROW_NUMBER() OVER (PARTITION BY a.subsessionid ORDER BY a.logtimestamp ASC) AS rn
+                                                        FROM    (
+                                                                    SELECT  *
+                                                                    FROM    (
+                                                                                SELECT  DISTINCT mid
+                                                                                        ,subsessionid
+                                                                                        ,videoid
+                                                                                        ,logtimestamp
+                                                                                        ,ROW_NUMBER() OVER (PARTITION BY mid,subsessionid,videoid ORDER BY logtimestamp ASC) AS rn
+                                                                                FROM    loghubods.video_action_log_rp
+                                                                                WHERE   dt = '${dt}'
+                                                                                AND     businesstype = 'videoView'
+                                                                                AND     pagesource REGEXP 'category$|recommend$|-pages/user-videos-detail$'
+                                                                            )
+                                                                    WHERE   rn = 1
+                                                                ) a
+                                                        LEFT JOIN   (
+                                                                        SELECT  DISTINCT machinecode
+                                                                                ,shareobjectid AS videoid
+                                                                                ,recomTraceId
+                                                                                ,subsessionid
+                                                                                ,sharedepth
+                                                                                ,shareid
+                                                                                ,clienttimestamp
+                                                                        FROM    loghubods.user_share_log
+                                                                        WHERE   dt = '${dt}'
+                                                                        AND     topic = 'share'
+                                                                        AND     pagesource REGEXP 'category$|recommend$|-pages/user-videos-detail$'
+                                                                    ) b
+                                                        ON      a.mid = b.machinecode
+                                                        AND     a.subsessionid = b.subsessionid
+                                                        AND     a.videoid = b.videoid
+                                                        LEFT JOIN   (
+                                                                        SELECT  DISTINCT machinecode
+                                                                                ,clickobjectid
+                                                                                ,recomTraceId
+                                                                                ,subsessionid
+                                                                                ,sharedepth
+                                                                                ,rootshareid
+                                                                        FROM    loghubods.user_share_log
+                                                                        WHERE   dt = '${dt}'
+                                                                        AND     topic = 'click'
+                                                                    ) c
+                                                        ON      b.shareid = c.rootshareid
+                                                        GROUP BY a.mid
+                                                                 ,a.subsessionid
+                                                                 ,a.videoid
+                                                                 ,a.logtimestamp
+                                                    )
+                                        ) dd
+                            ON      a.mid = dd.mid
+                            AND     a.subsessionid = dd.subsessionid
+                            AND     a.vid = dd.vid
+                            WHERE   dt="${dt}"
+                            AND     apptype IN ("0","4")
+                            AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页","回流页","其他")
+                            -- apptype=4: ab0-ab9; apptype=0: ab0-ab4,ab8,ab9(无 ab5/ab6/ab7)
+                            AND     abcode NOT IN ("ab100")
+                            AND     (apptype = "4"
+                                     OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab8","ab9"))
+                            AND     (apptype = "0"
+                                     OR abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+                        ) inner_sub
+            ) sub
+    -- INNER JOIN: 合法尾号才进分析
+    INNER JOIN t_suffix_group sg
+    ON      sub.suffix = sg.suffix
+    -- LEFT JOIN: 无实验匹配 → COALESCE 为"对照组"
+    LEFT JOIN t_experiment_map m
+    ON      sub.apptype = m.apptype
+    AND     sg.suffix_group = m.suffix_group
+    AND     '${dt}' BETWEEN m.start_dt AND m.end_dt
+)
+-- 桶内每个 vid 的曝光数(ECS / ARP 共同中间件)
+,t_vid_exp AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix
+            ,COALESCE(source_type,'总体') AS source_type
+            ,COALESCE(layer_type,'总体') AS layer_type
+            ,vid
+            ,COUNT(1) AS vid_exp_cnt
+    FROM    t_base
+    WHERE   page = "推荐"
+    GROUP BY dt, apptype, abcode, suffix, vid, source_type, layer_type
+    GROUPING SETS (
+        (dt, apptype, abcode, suffix, vid, source_type, layer_type),
+        (dt, apptype, abcode, suffix, vid)
+    )
+)
+,t_bucket_ecs AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix
+            ,source_type
+            ,layer_type
+            ,2 * SUM(p * rn) - 1 AS ecs
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,abcode
+                        ,suffix
+                        ,source_type
+                        ,layer_type
+                        ,vid_exp_cnt / SUM(vid_exp_cnt) OVER (
+                            PARTITION BY dt, apptype, abcode, suffix, source_type, layer_type
+                        ) AS p
+                        ,ROW_NUMBER() OVER (
+                            PARTITION BY dt, apptype, abcode, suffix, source_type, layer_type
+                            ORDER BY vid_exp_cnt DESC
+                        ) AS rn
+                FROM    t_vid_exp
+            ) t
+    GROUP BY dt, apptype, abcode, suffix, source_type, layer_type
+)
+,t_vid_global_pop AS
+(
+    SELECT  dt
+            ,apptype
+            ,COALESCE(source_type,'总体') AS source_type
+            ,COALESCE(layer_type,'总体') AS layer_type
+            ,vid
+            ,COUNT(1) AS vid_global_pop
+    FROM    t_base
+    WHERE   page = "推荐"
+    GROUP BY dt, apptype, vid, source_type, layer_type
+    GROUPING SETS (
+        (dt, apptype, vid, source_type, layer_type),
+        (dt, apptype, vid)
+    )
+)
+,t_bucket_arp AS
+(
+    SELECT  v.dt
+            ,v.apptype
+            ,v.abcode
+            ,v.suffix
+            ,v.source_type
+            ,v.layer_type
+            ,SUM(v.vid_exp_cnt * g.vid_global_pop) / SUM(v.vid_exp_cnt) AS arp
+    FROM    t_vid_exp v
+    LEFT JOIN t_vid_global_pop g
+    ON      v.dt = g.dt
+    AND     v.apptype = g.apptype
+    AND     v.source_type = g.source_type
+    AND     v.layer_type = g.layer_type
+    AND     v.vid = g.vid
+    GROUP BY v.dt, v.apptype, v.abcode, v.suffix, v.source_type, v.layer_type
+)
+-- dau2:按单尾号聚合
+,t_dau2_bucket AS
+(
+    SELECT  SUBSTR(sub.dt,1,8) AS dt
+            ,sub.apptype
+            ,COALESCE(m.abcode,"对照组") AS abcode
+            ,sg.suffix_group
+            ,sub.suffix
+            ,COALESCE(sub.source_type,'总体') AS source_type
+            ,COALESCE(sub.layer_type,'总体') AS layer_type
+            ,COUNT(DISTINCT sub.machinecode) AS dau2
+    FROM    (
+                SELECT  dt
+                        ,apptype
+                        ,machinecode
+                        ,SUBSTR(GET_JSON_OBJECT(extparams,'$.rootSessionId'),LENGTH(GET_JSON_OBJECT(extparams,'$.rootSessionId')),1) AS suffix
+                        ,CASE WHEN GET_JSON_OBJECT(extparams,'$.rootSourceId') != '' AND GET_JSON_OBJECT(extparams,'$.rootSourceId') IS NOT NULL THEN '外部' ELSE '内部' END AS source_type
+                        ,CASE WHEN GET_JSON_OBJECT(extparams,'$.rootSessionId') = subsessionid
+                                OR GET_JSON_OBJECT(extparams,'$.rootSessionId') = sessionid THEN '首层' ELSE '裂变层' END AS layer_type
+                FROM    loghubods.useractive_log
+                WHERE   dt="${dt}"
+                AND     apptype IN ("0","4")
+                AND     (apptype = "4"
+                         OR GET_JSON_OBJECT(extparams,'$.eventInfos.ab_test003') IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9"))
+                AND     (apptype = "4"
+                         OR GET_JSON_OBJECT(extparams,'$.eventInfos.ab_test003') NOT IN ("ab100"))
+            ) sub
+    INNER JOIN t_suffix_group sg
+    ON      sub.suffix = sg.suffix
+    LEFT JOIN t_experiment_map m
+    ON      sub.apptype = m.apptype
+    AND     sg.suffix_group = m.suffix_group
+    AND     '${dt}' BETWEEN m.start_dt AND m.end_dt
+    GROUP BY SUBSTR(sub.dt,1,8), sub.apptype, COALESCE(m.abcode,"对照组"), sg.suffix_group, sub.suffix
+             ,sub.source_type, sub.layer_type
+    GROUPING SETS (
+        (SUBSTR(sub.dt,1,8), sub.apptype, COALESCE(m.abcode,"对照组"), sg.suffix_group, sub.suffix, sub.source_type, sub.layer_type),
+        (SUBSTR(sub.dt,1,8), sub.apptype, COALESCE(m.abcode,"对照组"), sg.suffix_group, sub.suffix)
+    )
+)
+,t_dau2 AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix_group
+            ,source_type
+            ,layer_type
+            ,AVG(dau2) AS dau2
+    FROM    t_dau2_bucket
+    GROUP BY dt, apptype, abcode, suffix_group, source_type, layer_type
+)
+-- 桶级聚合:业务指标 + 分数 AVG/STDDEV + 埋点覆盖率
+,t_bucket AS
+(
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,suffix_group
+            ,suffix
+            ,COALESCE(source_type,'总体') AS source_type
+            ,COALESCE(layer_type,'总体') AS layer_type
+            -- 业务指标(同 base SQL)
+            ,COALESCE(COUNT(1) / COUNT(DISTINCT mid),0) AS exp_per_dau
+            ,COALESCE(SUM(is_share) / COUNT(1),0) AS str_one
+            ,COALESCE(SUM(return_n_uv) / SUM(is_share),0) AS ros_one
+            ,COALESCE(SUM(share_cnt) / COUNT(1),0) AS str
+            ,COALESCE(SUM(return_n_uv) / SUM(share_cnt),0) AS ros
+            ,COALESCE(SUM(is_return_1) / COUNT(1),0) AS str_plus
+            ,COALESCE(SUM(return_n_uv) / SUM(is_return_1),0) AS ros_minus
+            ,COALESCE(SUM(return_n_uv) / COUNT(1),0) AS bn_rov
+            ,COALESCE(SUM(c1) / COUNT(1),0) AS c1_rov
+            ,COALESCE(SUM(cn) / COUNT(1),0) AS cn_rov
+            ,COALESCE(SUM(d1) / COUNT(1),0) AS d1_rov
+            ,COALESCE(SUM(dn) / COUNT(1),0) AS dn_rov
+            ,COALESCE((SUM(return_n_uv) + SUM(cn) + SUM(dn)) / COUNT(1),0) AS total_rov
+            ,COALESCE(SUM(new_exposure_cnt) / COUNT(1),0) AS vovh24
+            ,COUNT(DISTINCT mid) AS dau
+            ,COUNT(1) AS exp
+            ,COUNT(DISTINCT vid) AS distinct_vid_cnt
+            ,COALESCE(SUM(is_share),0) AS is_share
+            ,COALESCE(SUM(share_cnt),0) AS share_cnt
+            ,COALESCE(SUM(is_return_1),0) AS is_return_1
+            ,COALESCE(SUM(return_n_uv),0) AS return_n_uv
+            ,COALESCE(SUM(new_exposure_cnt),0) AS viewh24
+            ,COALESCE(SUM(return_n_uv_noself),0) AS return_n_uv_noself
+            ,COALESCE(SUM(cn),0) AS cn
+            ,COALESCE(SUM(c1),0) AS c1
+            ,COALESCE(SUM(dn),0) AS dn
+            ,COALESCE(SUM(d1),0) AS d1
+            -- ── 新增:分数 AVG / STDDEV / COVERAGE(NULLable 字段 cov<<1 时 _avg 是统计幻象) ──
+            ,AVG(final_score)            AS final_score_avg
+            ,STDDEV_POP(final_score)     AS final_score_std
+            ,AVG(fmrov)                  AS fmrov_avg
+            ,STDDEV_POP(fmrov)           AS fmrov_std
+            ,AVG(fmrov_origin)           AS fmrov_origin_avg
+            ,STDDEV_POP(fmrov_origin)    AS fmrov_origin_std
+            ,SUM(CASE WHEN fmrov_origin IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS fmrov_origin_cov
+            ,AVG(nor_xgb_score)          AS nor_xgb_score_avg
+            ,STDDEV_POP(nor_xgb_score)   AS nor_xgb_score_std
+            ,SUM(CASE WHEN nor_xgb_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS nor_xgb_score_cov
+            ,AVG(nor_dnn_score)          AS nor_dnn_score_avg
+            ,STDDEV_POP(nor_dnn_score)   AS nor_dnn_score_std
+            ,SUM(CASE WHEN nor_dnn_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS nor_dnn_score_cov
+            ,AVG(new_nor_dnn_score)      AS new_nor_dnn_score_avg
+            ,STDDEV_POP(new_nor_dnn_score) AS new_nor_dnn_score_std
+            ,SUM(CASE WHEN new_nor_dnn_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS new_nor_dnn_score_cov
+            ,AVG(has_return_rov_score)   AS has_return_rov_score_avg
+            ,STDDEV_POP(has_return_rov_score) AS has_return_rov_score_std
+            ,AVG(vor_score)              AS vor_score_avg
+            ,STDDEV_POP(vor_score)       AS vor_score_std
+            ,AVG(c1_rovn_score)          AS c1_rovn_score_avg
+            ,STDDEV_POP(c1_rovn_score)   AS c1_rovn_score_std
+            ,AVG(b0_str_score)           AS b0_str_score_avg
+            ,STDDEV_POP(b0_str_score)    AS b0_str_score_std
+            ,AVG(b0_ror_score)           AS b0_ror_score_avg
+            ,STDDEV_POP(b0_ror_score)    AS b0_ror_score_std
+            ,AVG(cn_rovn_score)          AS cn_rovn_score_avg
+            ,STDDEV_POP(cn_rovn_score)   AS cn_rovn_score_std
+            ,SUM(CASE WHEN cn_rovn_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS cn_rovn_score_cov
+            ,AVG(dn_rovn_score)          AS dn_rovn_score_avg
+            ,STDDEV_POP(dn_rovn_score)   AS dn_rovn_score_std
+            ,SUM(CASE WHEN dn_rovn_score IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS dn_rovn_score_cov
+            ,AVG(p_leave)                AS p_leave_avg
+            ,STDDEV_POP(p_leave)         AS p_leave_std
+            ,SUM(CASE WHEN p_leave IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS p_leave_cov
+            ,AVG(new_p_leave)            AS new_p_leave_avg
+            ,STDDEV_POP(new_p_leave)     AS new_p_leave_std
+            ,SUM(CASE WHEN new_p_leave IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS new_p_leave_cov
+            ,AVG(reduce_coefficient)     AS reduce_coefficient_avg
+            ,STDDEV_POP(reduce_coefficient) AS reduce_coefficient_std
+            ,SUM(CASE WHEN reduce_coefficient IS NOT NULL THEN 1 ELSE 0 END) / COUNT(1) AS reduce_coefficient_cov
+            -- 埋点覆盖率(监控 sample_all LEFT JOIN statistics_log 的丢失程度)
+            ,SUM(CASE WHEN scoresmap IS NOT NULL AND scoresmap <> '' THEN 1 ELSE 0 END) / COUNT(1) AS scoresmap_coverage
+    FROM    t_base
+    WHERE   page = "推荐"
+    GROUP BY dt, apptype, abcode, suffix_group, suffix, source_type, layer_type
+    GROUPING SETS (
+        (dt, apptype, abcode, suffix_group, suffix, source_type, layer_type),
+        (dt, apptype, abcode, suffix_group, suffix)
+    )
+)
+-- 实验组级 metrics:从尾号桶 AVG(业务指标) + 桶内分数 AVG 再求平均
+,t_metrics AS
+(
+    SELECT  b.dt
+            ,b.apptype
+            ,b.abcode
+            ,b.suffix_group
+            ,b.source_type
+            ,b.layer_type
+            -- 业务指标(同 base SQL)
+            ,ROUND(AVG(b.exp_per_dau),2) AS exp_per_dau
+            ,ROUND(AVG(b.str_one),6) AS str_one
+            ,ROUND(AVG(b.ros_one),6) AS ros_one
+            ,ROUND(AVG(b.str),6) AS str
+            ,ROUND(AVG(b.ros),6) AS ros
+            ,ROUND(AVG(b.str_plus),6) AS str_plus
+            ,ROUND(AVG(b.ros_minus),6) AS ros_minus
+            ,ROUND(AVG(b.bn_rov),6) AS bn_rov
+            ,ROUND(AVG(b.c1_rov),6) AS c1_rov
+            ,ROUND(AVG(b.cn_rov),6) AS cn_rov
+            ,ROUND(AVG(b.d1_rov),6) AS d1_rov
+            ,ROUND(AVG(b.dn_rov),6) AS dn_rov
+            ,ROUND(AVG(b.total_rov),6) AS total_rov
+            ,ROUND(AVG(b.vovh24),6) AS vovh24
+            ,AVG(b.dau) AS dau
+            ,AVG(b.exp) AS exp
+            ,ROUND(AVG(b.distinct_vid_cnt),0) AS distinct_vid_cnt
+            ,ROUND(AVG(e.ecs),1) AS ecs
+            ,ROUND(AVG(e.ecs) / NULLIF(AVG(b.distinct_vid_cnt),0),6) AS ecs_ratio
+            ,ROUND(1 - AVG(e.ecs) / NULLIF(AVG(b.distinct_vid_cnt),0),6) AS gini
+            ,ROUND(AVG(a.arp),0) AS arp
+            ,AVG(b.is_share) AS is_share
+            ,AVG(b.share_cnt) AS share_cnt
+            ,AVG(b.is_return_1) AS is_return_1
+            ,AVG(b.return_n_uv) AS return_n_uv
+            ,AVG(b.viewh24) AS viewh24
+            ,AVG(b.return_n_uv_noself) AS return_n_uv_noself
+            ,AVG(b.cn) AS cn
+            ,AVG(b.c1) AS c1
+            ,AVG(b.dn) AS dn
+            ,AVG(b.d1) AS d1
+            ,WM_CONCAT(DISTINCT ',',b.suffix) AS suffix
+            -- ── 新增:分数 AVG / STDDEV(桶内 AVG/STDDEV 再求实验组平均)──
+            -- AVG 含义:实验组内分数均值
+            -- STDDEV 含义:实验组内"桶内分数离散度"的均值(监控分布坍塌的核心信号)
+            ,ROUND(AVG(b.final_score_avg),6) AS final_score_avg
+            ,ROUND(AVG(b.final_score_std),6) AS final_score_std
+            ,ROUND(AVG(b.fmrov_avg),6) AS fmrov_avg
+            ,ROUND(AVG(b.fmrov_std),6) AS fmrov_std
+            ,ROUND(AVG(b.fmrov_origin_avg),6) AS fmrov_origin_avg
+            ,ROUND(AVG(b.fmrov_origin_std),6) AS fmrov_origin_std
+            ,ROUND(AVG(b.fmrov_origin_cov),4) AS fmrov_origin_cov
+            ,ROUND(AVG(b.nor_xgb_score_avg),6) AS nor_xgb_score_avg
+            ,ROUND(AVG(b.nor_xgb_score_std),6) AS nor_xgb_score_std
+            ,ROUND(AVG(b.nor_xgb_score_cov),4) AS nor_xgb_score_cov
+            ,ROUND(AVG(b.nor_dnn_score_avg),6) AS nor_dnn_score_avg
+            ,ROUND(AVG(b.nor_dnn_score_std),6) AS nor_dnn_score_std
+            ,ROUND(AVG(b.nor_dnn_score_cov),4) AS nor_dnn_score_cov
+            ,ROUND(AVG(b.new_nor_dnn_score_avg),6) AS new_nor_dnn_score_avg
+            ,ROUND(AVG(b.new_nor_dnn_score_std),6) AS new_nor_dnn_score_std
+            ,ROUND(AVG(b.new_nor_dnn_score_cov),4) AS new_nor_dnn_score_cov
+            ,ROUND(AVG(b.has_return_rov_score_avg),6) AS has_return_rov_score_avg
+            ,ROUND(AVG(b.has_return_rov_score_std),6) AS has_return_rov_score_std
+            ,ROUND(AVG(b.vor_score_avg),6) AS vor_score_avg
+            ,ROUND(AVG(b.vor_score_std),6) AS vor_score_std
+            ,ROUND(AVG(b.c1_rovn_score_avg),6) AS c1_rovn_score_avg
+            ,ROUND(AVG(b.c1_rovn_score_std),6) AS c1_rovn_score_std
+            ,ROUND(AVG(b.b0_str_score_avg),6) AS b0_str_score_avg
+            ,ROUND(AVG(b.b0_str_score_std),6) AS b0_str_score_std
+            ,ROUND(AVG(b.b0_ror_score_avg),6) AS b0_ror_score_avg
+            ,ROUND(AVG(b.b0_ror_score_std),6) AS b0_ror_score_std
+            ,ROUND(AVG(b.cn_rovn_score_avg),6) AS cn_rovn_score_avg
+            ,ROUND(AVG(b.cn_rovn_score_std),6) AS cn_rovn_score_std
+            ,ROUND(AVG(b.cn_rovn_score_cov),4) AS cn_rovn_score_cov
+            ,ROUND(AVG(b.dn_rovn_score_avg),6) AS dn_rovn_score_avg
+            ,ROUND(AVG(b.dn_rovn_score_std),6) AS dn_rovn_score_std
+            ,ROUND(AVG(b.dn_rovn_score_cov),4) AS dn_rovn_score_cov
+            ,ROUND(AVG(b.p_leave_avg),6) AS p_leave_avg
+            ,ROUND(AVG(b.p_leave_std),6) AS p_leave_std
+            ,ROUND(AVG(b.p_leave_cov),4) AS p_leave_cov
+            ,ROUND(AVG(b.new_p_leave_avg),6) AS new_p_leave_avg
+            ,ROUND(AVG(b.new_p_leave_std),6) AS new_p_leave_std
+            ,ROUND(AVG(b.new_p_leave_cov),4) AS new_p_leave_cov
+            ,ROUND(AVG(b.reduce_coefficient_avg),6) AS reduce_coefficient_avg
+            ,ROUND(AVG(b.reduce_coefficient_std),6) AS reduce_coefficient_std
+            ,ROUND(AVG(b.reduce_coefficient_cov),4) AS reduce_coefficient_cov
+            ,ROUND(AVG(b.scoresmap_coverage),4) AS scoresmap_coverage
+    FROM    t_bucket b
+    LEFT JOIN t_bucket_ecs e
+    ON      b.dt = e.dt
+    AND     b.apptype = e.apptype
+    AND     b.abcode = e.abcode
+    AND     b.suffix = e.suffix
+    AND     b.source_type = e.source_type
+    AND     b.layer_type = e.layer_type
+    LEFT JOIN t_bucket_arp a
+    ON      b.dt = a.dt
+    AND     b.apptype = a.apptype
+    AND     b.abcode = a.abcode
+    AND     b.suffix = a.suffix
+    AND     b.source_type = a.source_type
+    AND     b.layer_type = a.layer_type
+    GROUP BY b.dt, b.apptype, b.abcode, b.suffix_group, b.source_type, b.layer_type
+)
+-- ════════════════════════════════════════════════════════════════════════════
+-- 基线对比层(业务指标的 _diff,分数列不参与)
+-- ════════════════════════════════════════════════════════════════════════════
+,t_dau2_base5 AS
+(
+    -- ── apptype = 0 ──
+    SELECT "0" AS apptype, "01" AS suffix_group, "内部"  AS source_type, "裂变层" AS layer_type, 15293.4  AS dau2_base5
+    UNION ALL SELECT "0", "01", "内部",  "首层",   5649.5
+    UNION ALL SELECT "0", "01", "外部",  "裂变层", 187201.8
+    UNION ALL SELECT "0", "01", "外部",  "首层",   44738.8
+    UNION ALL SELECT "0", "01", "总体",  "总体",   250063.2
+    UNION ALL SELECT "0", "2c", "内部",  "裂变层", 16274.4
+    UNION ALL SELECT "0", "2c", "内部",  "首层",   5638.2
+    UNION ALL SELECT "0", "2c", "外部",  "裂变层", 197492.2
+    UNION ALL SELECT "0", "2c", "外部",  "首层",   44625.3
+    UNION ALL SELECT "0", "2c", "总体",  "总体",   261125.5
+    UNION ALL SELECT "0", "34", "内部",  "裂变层", 15779.9
+    UNION ALL SELECT "0", "34", "内部",  "首层",   5646.3
+    UNION ALL SELECT "0", "34", "外部",  "裂变层", 194802.8
+    UNION ALL SELECT "0", "34", "外部",  "首层",   44646.0
+    UNION ALL SELECT "0", "34", "总体",  "总体",   258002.4
+    UNION ALL SELECT "0", "5d", "内部",  "裂变层", 15828.0
+    UNION ALL SELECT "0", "5d", "内部",  "首层",   5639.7
+    UNION ALL SELECT "0", "5d", "外部",  "裂变层", 190163.7
+    UNION ALL SELECT "0", "5d", "外部",  "首层",   44828.3
+    UNION ALL SELECT "0", "5d", "总体",  "总体",   253589.2
+    UNION ALL SELECT "0", "67", "内部",  "裂变层", 15757.9
+    UNION ALL SELECT "0", "67", "内部",  "首层",   5627.2
+    UNION ALL SELECT "0", "67", "外部",  "裂变层", 195371.1
+    UNION ALL SELECT "0", "67", "外部",  "首层",   44620.4
+    UNION ALL SELECT "0", "67", "总体",  "总体",   258466.2
+    UNION ALL SELECT "0", "89", "内部",  "裂变层", 15889.8
+    UNION ALL SELECT "0", "89", "内部",  "首层",   5628.7
+    UNION ALL SELECT "0", "89", "外部",  "裂变层", 187814.3
+    UNION ALL SELECT "0", "89", "外部",  "首层",   44561.2
+    UNION ALL SELECT "0", "89", "总体",  "总体",   251052.3
+    UNION ALL SELECT "0", "ab", "内部",  "裂变层", 16179.7
+    UNION ALL SELECT "0", "ab", "内部",  "首层",   5661.8
+    UNION ALL SELECT "0", "ab", "外部",  "裂变层", 184483.2
+    UNION ALL SELECT "0", "ab", "外部",  "首层",   44617.9
+    UNION ALL SELECT "0", "ab", "总体",  "总体",   248110.7
+    UNION ALL SELECT "0", "ef", "内部",  "裂变层", 15500.8
+    UNION ALL SELECT "0", "ef", "内部",  "首层",   5664.6
+    UNION ALL SELECT "0", "ef", "外部",  "裂变层", 184847.8
+    UNION ALL SELECT "0", "ef", "外部",  "首层",   44637.9
+    UNION ALL SELECT "0", "ef", "总体",  "总体",   247799.1
+    -- ── apptype = 4 ──
+    UNION ALL SELECT "4", "01", "内部",  "裂变层", 9358.8
+    UNION ALL SELECT "4", "01", "内部",  "首层",   3953.4
+    UNION ALL SELECT "4", "01", "外部",  "裂变层", 129526.8
+    UNION ALL SELECT "4", "01", "外部",  "首层",   82839.8
+    UNION ALL SELECT "4", "01", "总体",  "总体",   221923.1
+    UNION ALL SELECT "4", "2c", "内部",  "裂变层", 9556.8
+    UNION ALL SELECT "4", "2c", "内部",  "首层",   3935.1
+    UNION ALL SELECT "4", "2c", "外部",  "裂变层", 131426.8
+    UNION ALL SELECT "4", "2c", "外部",  "首层",   82767.1
+    UNION ALL SELECT "4", "2c", "总体",  "总体",   223926.3
+    UNION ALL SELECT "4", "34", "内部",  "裂变层", 11739.7
+    UNION ALL SELECT "4", "34", "内部",  "首层",   3892.0
+    UNION ALL SELECT "4", "34", "外部",  "裂变层", 126370.7
+    UNION ALL SELECT "4", "34", "外部",  "首层",   82681.9
+    UNION ALL SELECT "4", "34", "总体",  "总体",   220940.6
+    UNION ALL SELECT "4", "5d", "内部",  "裂变层", 9999.3
+    UNION ALL SELECT "4", "5d", "内部",  "首层",   3950.1
+    UNION ALL SELECT "4", "5d", "外部",  "裂变层", 128746.6
+    UNION ALL SELECT "4", "5d", "外部",  "首层",   82744.1
+    UNION ALL SELECT "4", "5d", "总体",  "总体",   221669.4
+    UNION ALL SELECT "4", "67", "内部",  "裂变层", 9685.2
+    UNION ALL SELECT "4", "67", "内部",  "首层",   3942.3
+    UNION ALL SELECT "4", "67", "外部",  "裂变层", 125356.4
+    UNION ALL SELECT "4", "67", "外部",  "首层",   82720.8
+    UNION ALL SELECT "4", "67", "总体",  "总体",   217974.6
+    UNION ALL SELECT "4", "89", "内部",  "裂变层", 11370.5
+    UNION ALL SELECT "4", "89", "内部",  "首层",   3964.6
+    UNION ALL SELECT "4", "89", "外部",  "裂变层", 130128.5
+    UNION ALL SELECT "4", "89", "外部",  "首层",   82614.5
+    UNION ALL SELECT "4", "89", "总体",  "总体",   224279.4
+    UNION ALL SELECT "4", "ab", "内部",  "裂变层", 9481.3
+    UNION ALL SELECT "4", "ab", "内部",  "首层",   3933.9
+    UNION ALL SELECT "4", "ab", "外部",  "裂变层", 129952.9
+    UNION ALL SELECT "4", "ab", "外部",  "首层",   82784.3
+    UNION ALL SELECT "4", "ab", "总体",  "总体",   222393.9
+    UNION ALL SELECT "4", "ef", "内部",  "裂变层", 9533.7
+    UNION ALL SELECT "4", "ef", "内部",  "首层",   3947.6
+    UNION ALL SELECT "4", "ef", "外部",  "裂变层", 127244.0
+    UNION ALL SELECT "4", "ef", "外部",  "首层",   82754.4
+    UNION ALL SELECT "4", "ef", "总体",  "总体",   219735.4
+)
+-- 合并主表 + dau2 + dau_vs_5d + expCode
+,t_combined AS
+(
+    SELECT  a.*
+            ,b.dau2
+            ,ROUND(b.dau2 / NULLIF(c.dau2_base5, 0), 6) AS dau_vs_5d
+            ,e.expcode
+    FROM    t_metrics a
+    LEFT JOIN t_dau2 b
+    ON      a.dt = b.dt
+    AND     a.apptype = b.apptype
+    AND     a.abcode = b.abcode
+    AND     a.suffix_group = b.suffix_group
+    AND     a.source_type = b.source_type
+    AND     a.layer_type = b.layer_type
+    LEFT JOIN t_dau2_base5 c
+    ON      a.apptype = c.apptype
+    AND     a.suffix_group = c.suffix_group
+    AND     a.source_type = c.source_type
+    AND     a.layer_type = c.layer_type
+    LEFT JOIN t_exp_code_map e
+    ON      a.apptype = e.apptype
+    AND     a.suffix_group = e.suffix_group
+    AND     a.dt BETWEEN e.start_dt AND e.end_dt
+)
+-- 基线桶(89)每日业务指标,作为横向对比基准(分数列不在此参与,留给上层视图)
+,t_ctrl AS
+(
+    SELECT  dt
+            ,apptype
+            ,source_type
+            ,layer_type
+            ,dau_vs_5d  AS ctrl_dau_vs_5d
+            ,exp        AS ctrl_exp
+            ,exp_per_dau AS ctrl_exp_per_dau
+            ,str_one    AS ctrl_str_one
+            ,ros_one    AS ctrl_ros_one
+            ,str        AS ctrl_str
+            ,ros        AS ctrl_ros
+            ,vovh24     AS ctrl_vovh24
+            ,str_plus   AS ctrl_str_plus
+            ,ros_minus  AS ctrl_ros_minus
+            ,bn_rov     AS ctrl_bn_rov
+            ,c1_rov     AS ctrl_c1_rov
+            ,cn_rov     AS ctrl_cn_rov
+            ,d1_rov     AS ctrl_d1_rov
+            ,dn_rov     AS ctrl_dn_rov
+            ,total_rov  AS ctrl_total_rov
+            ,ecs        AS ctrl_ecs
+            ,ecs_ratio  AS ctrl_ecs_ratio
+            ,arp        AS ctrl_arp
+    FROM    t_combined
+    WHERE   suffix_group = '89'
+)
+-- ════════════════════════════════════════════════════════════════════════════
+-- 最终输出
+--   - 业务指标 + 业务 _diff(vs 89 桶;同 base SQL)
+--   - 13 个分数 _avg / _std(IGNORE NULLS)
+--   - scoresmap_coverage(埋点覆盖率监控)
+--   - expcode(流量配置策略号)
+-- ════════════════════════════════════════════════════════════════════════════
+SELECT  r.dt
+        ,r.apptype
+        ,r.expcode
+        ,r.abcode
+        ,r.suffix_group
+        ,r.source_type
+        ,r.layer_type
+        ,r.suffix
+        -- ── 业务指标(同 base SQL)──
+        ,r.exp_per_dau
+        ,r.str_one
+        ,r.ros_one
+        ,r.str
+        ,r.ros
+        ,r.str_plus
+        ,r.ros_minus
+        ,r.bn_rov
+        ,r.c1_rov
+        ,r.cn_rov
+        ,r.d1_rov
+        ,r.dn_rov
+        ,r.total_rov
+        ,r.vovh24
+        ,r.dau
+        ,r.exp
+        ,r.distinct_vid_cnt
+        ,r.ecs
+        ,r.ecs_ratio
+        ,r.gini
+        ,r.arp
+        ,r.is_share
+        ,r.share_cnt
+        ,r.is_return_1
+        ,r.return_n_uv
+        ,r.viewh24
+        ,r.return_n_uv_noself
+        ,r.cn
+        ,r.c1
+        ,r.dn
+        ,r.d1
+        ,r.dau2
+        -- ── 模型分数 panel(13 × 2 = 26 列)──
+        ,r.final_score_avg
+        ,r.final_score_std
+        ,r.fmrov_avg
+        ,r.fmrov_std
+        ,r.fmrov_origin_avg
+        ,r.fmrov_origin_std
+        ,r.fmrov_origin_cov
+        ,r.nor_xgb_score_avg
+        ,r.nor_xgb_score_std
+        ,r.nor_xgb_score_cov
+        ,r.nor_dnn_score_avg
+        ,r.nor_dnn_score_std
+        ,r.nor_dnn_score_cov
+        ,r.new_nor_dnn_score_avg
+        ,r.new_nor_dnn_score_std
+        ,r.new_nor_dnn_score_cov
+        ,r.has_return_rov_score_avg
+        ,r.has_return_rov_score_std
+        ,r.vor_score_avg
+        ,r.vor_score_std
+        ,r.c1_rovn_score_avg
+        ,r.c1_rovn_score_std
+        ,r.b0_str_score_avg
+        ,r.b0_str_score_std
+        ,r.b0_ror_score_avg
+        ,r.b0_ror_score_std
+        ,r.cn_rovn_score_avg
+        ,r.cn_rovn_score_std
+        ,r.cn_rovn_score_cov
+        ,r.dn_rovn_score_avg
+        ,r.dn_rovn_score_std
+        ,r.dn_rovn_score_cov
+        ,r.p_leave_avg
+        ,r.p_leave_std
+        ,r.p_leave_cov
+        ,r.new_p_leave_avg
+        ,r.new_p_leave_std
+        ,r.new_p_leave_cov
+        ,r.reduce_coefficient_avg
+        ,r.reduce_coefficient_std
+        ,r.reduce_coefficient_cov
+        -- ── 埋点覆盖率(监控 scoresMap=NULL 的曝光占比,越接近 0 越说明 sample_all LEFT JOIN 丢失严重)──
+        ,r.scoresmap_coverage
+        -- ── DAU2 纵向对比 ──
+        ,r.dau_vs_5d
+        -- ── 业务指标横向 _diff(vs 89 对照桶)──
+        ,ROUND(r.dau_vs_5d / NULLIF(ctrl.ctrl_dau_vs_5d, 0) - 1, 6) AS dau_vs_5d_diff
+        ,ROUND(r.exp / NULLIF(ctrl.ctrl_exp, 0) - 1, 6) AS exp_diff
+        ,ROUND((1 + r.exp_per_dau / NULLIF(ctrl.ctrl_exp_per_dau, 0) - 1)
+             * (1 + r.total_rov / NULLIF(ctrl.ctrl_total_rov, 0) - 1)
+             - 1, 6) AS exp_rov_combined_diff
+        ,ROUND(r.exp_per_dau / NULLIF(ctrl.ctrl_exp_per_dau, 0) - 1, 6) AS exp_per_dau_diff
+        ,ROUND(r.str_one / NULLIF(ctrl.ctrl_str_one, 0) - 1, 6) AS str_one_diff
+        ,ROUND(r.ros_one / NULLIF(ctrl.ctrl_ros_one, 0) - 1, 6) AS ros_one_diff
+        ,ROUND(r.str / NULLIF(ctrl.ctrl_str, 0) - 1, 6) AS str_diff
+        ,ROUND(r.ros / NULLIF(ctrl.ctrl_ros, 0) - 1, 6) AS ros_diff
+        ,ROUND(r.vovh24 / NULLIF(ctrl.ctrl_vovh24, 0) - 1, 6) AS vovh24_diff
+        ,ROUND(r.str_plus / NULLIF(ctrl.ctrl_str_plus, 0) - 1, 6) AS str_plus_diff
+        ,ROUND(r.ros_minus / NULLIF(ctrl.ctrl_ros_minus, 0) - 1, 6) AS ros_minus_diff
+        ,ROUND(r.bn_rov / NULLIF(ctrl.ctrl_bn_rov, 0) - 1, 6) AS bn_rov_diff
+        ,ROUND(r.c1_rov / NULLIF(ctrl.ctrl_c1_rov, 0) - 1, 6) AS c1_rov_diff
+        ,ROUND(r.cn_rov / NULLIF(ctrl.ctrl_cn_rov, 0) - 1, 6) AS cn_rov_diff
+        ,ROUND(r.d1_rov / NULLIF(ctrl.ctrl_d1_rov, 0) - 1, 6) AS d1_rov_diff
+        ,ROUND(r.dn_rov / NULLIF(ctrl.ctrl_dn_rov, 0) - 1, 6) AS dn_rov_diff
+        ,ROUND(r.total_rov / NULLIF(ctrl.ctrl_total_rov, 0) - 1, 6) AS total_rov_diff
+        ,ROUND(r.ecs / NULLIF(ctrl.ctrl_ecs, 0) - 1, 6) AS ecs_diff
+        ,ROUND(r.ecs_ratio / NULLIF(ctrl.ctrl_ecs_ratio, 0) - 1, 6) AS ecs_ratio_diff
+        ,ROUND(r.arp / NULLIF(ctrl.ctrl_arp, 0) - 1, 6) AS arp_diff
+FROM    t_combined r
+LEFT JOIN t_ctrl ctrl
+ON      r.dt = ctrl.dt
+AND     r.apptype = ctrl.apptype
+AND     r.source_type = ctrl.source_type
+AND     r.layer_type = ctrl.layer_type
+ORDER BY r.dt DESC, r.apptype, r.expcode, r.abcode, r.suffix_group, r.source_type, r.layer_type
+;

+ 37 - 0
tasks/00_尾号实验/线上实验配置/流量配置/20260425.json

@@ -0,0 +1,37 @@
+[
+  {
+    "appType": [0, 4],
+    "tail": ["8", "9"],
+    "expCodes": ["839"]
+  },
+  {
+    "appType": [4],
+    "tail": ["e", "f"],
+    "expCodes": ["562"]
+  },
+  {
+    "appType": [4],
+    "tail": ["2", "c"],
+    "expCodes": ["563"]
+  },
+  {
+    "appType": [0],
+    "tail": ["e", "f"],
+    "expCodes": ["563"]
+  },
+  {
+    "appType": [0],
+    "tail": ["2", "c"],
+    "expCodes": ["562"]
+  },
+  {
+    "appType": [0],
+    "tail": ["5", "d"],
+    "expCodes": ["565"]
+  },
+  {
+    "appType": [0],
+    "tail": ["3", "4"],
+    "expCodes": ["566"]
+  }
+]

+ 15 - 0
tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv562.json

@@ -0,0 +1,15 @@
+{
+  "headCate1RecallN": 3,
+  "headCate2RecallN": 3,
+  "cate1RecallN": 10,
+  "cate2RecallN": 10,
+  "xgbNorPowerWeight": 0,
+  "xgbNorPowerExp": 1,
+  "prioriProvinceRov": 6,
+  "prioriProvinceStr": 3,
+  "xgbRovNegRate": 0.036,
+  "vor_w": 1,
+  "vor_add": 0.1,
+  "c1_rovn_1h_w": 0.5,
+  "c1_rovn_24h_w": 0.5
+}

+ 17 - 0
tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv563.json

@@ -0,0 +1,17 @@
+{
+    "headCate1RecallN": 3,
+    "headCate2RecallN": 3,
+    "cate1RecallN": 10,
+    "cate2RecallN": 10,
+    "xgbNorPowerWeight": 0,
+    "xgbNorPowerExp": 1,
+    "prioriProvinceRov": 6,
+    "prioriProvinceStr": 3,
+    "xgbRovNegRate": 0.036,
+    "ros_add": 0.001,
+    "ros_w": 1,
+    "vor_w": 1,
+    "vor_add": 0.1,
+    "c1_rovn_1h_w": 0.5,
+    "c1_rovn_24h_w": 0.5
+}

+ 15 - 0
tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv565.json

@@ -0,0 +1,15 @@
+{
+  "headCate1RecallN": 3,
+  "headCate2RecallN": 3,
+  "cate1RecallN": 10,
+  "cate2RecallN": 10,
+  "xgbNorPowerWeight": 0,
+  "xgbNorPowerExp": 1,
+  "prioriProvinceRov": 6,
+  "prioriProvinceStr": 3,
+  "xgbRovNegRate": 0.036,
+  "vor_w": 1,
+  "vor_add": 0.1,
+  "c1_rovn_1h_w": 0.5,
+  "c1_rovn_24h_w": 0.5
+}

+ 15 - 0
tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv566.json

@@ -0,0 +1,15 @@
+{
+  "headCate1RecallN": 3,
+  "headCate2RecallN": 3,
+  "cate1RecallN": 10,
+  "cate2RecallN": 10,
+  "xgbNorPowerWeight": 1,
+  "xgbNorPowerExp": 1,
+  "prioriProvinceRov": 6,
+  "prioriProvinceStr": 3,
+  "xgbRovNegRate": 0.036,
+  "vor_w": 1,
+  "vor_add": 0.1,
+  "c1_rovn_1h_w": 0.5,
+  "c1_rovn_24h_w": 0.5
+}

+ 15 - 0
tasks/00_尾号实验/线上实验配置/策略权重-apollo配置/rank.score.merge.weightv839.json

@@ -0,0 +1,15 @@
+{
+    "headCate1RecallN": 3,
+    "headCate2RecallN": 3,
+    "cate1RecallN": 10,
+    "cate2RecallN": 10,
+    "xgbNorPowerWeight": 1.22,
+    "xgbNorPowerExp": 1.15,
+    "prioriProvinceRov": 6,
+    "prioriProvinceStr": 3,
+    "xgbRovNegRate": 0.055,
+    "vor_w":1,
+    "vor_add":0.1,
+    "c1_rovn_1h_w":0.5,
+    "c1_rovn_24h_w":0.5
+}

+ 178 - 0
tasks/召回策略效果/base.sql

@@ -0,0 +1,178 @@
+WITH base_tab AS 
+(
+    SELECT  dt
+            ,hh
+            ,apptype
+            ,vid
+            ,mid
+            ,is_share
+            ,share_pv
+            ,is_return_1
+            ,return_n_uv
+            ,return_n_uv_noself
+            ,new_exposure_cnt
+            ,CASE   WHEN page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页") THEN "推荐"
+                    WHEN page IN ("回流页","其他") THEN "非推荐"
+                    ELSE "其他"
+            END AS page
+            ,CASE   WHEN apptype IN ("0") AND abcode IN ("ab0","ab1") THEN "实验组-社交i2i召回"
+                    WHEN apptype IN ("0") AND abcode IN ("ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9") THEN "对照组"
+                    ELSE "其他"
+            END AS abcode
+            ,push_from_array
+    FROM    (
+                SELECT  dt
+                        ,hh
+                        ,apptype
+                        ,vid
+                        ,mid
+                        ,abcode
+                        ,is_share
+                        ,COALESCE(share_cnt,0) AS share_pv
+                        ,is_return_1
+                        ,COALESCE(return_n_uv,0) AS return_n_uv
+                        ,COALESCE(return_n_uv_noself,0) AS return_n_uv_noself
+                        ,COALESCE(new_exposure_cnt,0) AS new_exposure_cnt
+                        ,SPLIT(
+                              REGEXP_REPLACE(GET_JSON_OBJECT(recommendlogvo,'$.pushFromIndexList[*].pushFrom'),'(\\[|\\]|")','')
+                        ,',') AS push_from_array
+                        ,page
+                        ,extend
+                        ,rootsourceid
+                        ,subsessionid
+                        ,sessionid
+                FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
+                WHERE   CONCAT(dt,hh) >= '${start_dt_hh}'
+                AND     CONCAT(dt,hh) <= '${end_dt_hh}'
+                AND     apptype IN ('0')
+                AND     recommendlogvo IS NOT NULL
+                AND     GET_JSON_OBJECT(recommendlogvo,'$.pushFromIndexList') IS NOT NULL
+                AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页")
+                AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
+                AND     abcode NOT IN ("ab100")
+            ) 
+)
+,total_tab AS 
+(
+    SELECT  COALESCE(dt,"sum") AS dt
+            ,page
+            ,abcode
+            ,COUNT(DISTINCT mid) AS total_exp_uv
+            ,COUNT(1) AS total_exp_pv
+            ,SUM(share_pv) AS total_share_pv
+            ,SUM(return_n_uv) AS total_return_n_uv
+            ,SUM(return_n_uv_noself) AS total_return_n_uv_noself
+            ,SUM(new_exposure_cnt) AS total_new_exposure_cnt
+            ,COUNT(DISTINCT vid) AS total_vid_cnt
+    FROM    base_tab
+    GROUP BY dt
+             ,page
+             ,abcode
+    GROUPING SETS ((dt,page,abcode)
+                  ,(page,abcode))
+)
+,detail_table AS 
+(
+    SELECT  dt
+            ,page
+            ,abcode
+            ,single_push_from
+            ,COALESCE(exp_uv,0) AS exp_uv
+            ,COALESCE(exp_pv,0) AS exp_pv
+            ,COALESCE(share_pv,0) AS share_pv
+            ,COALESCE(return_n_uv,0) AS return_n_uv
+            ,COALESCE(return_n_uv_noself,0) AS return_n_uv_noself
+            ,COALESCE(new_exposure_cnt,0) AS new_exposure_cnt
+            ,COALESCE(vid_cnt,0) AS vid_cnt
+            ,ROUND(COALESCE(视频平均曝光次数,0),4) AS 视频平均曝光次数
+            ,ROUND(COALESCE(share_pv / exp_pv,0),4) AS str
+            ,ROUND(COALESCE(return_n_uv / share_pv,0),4) AS rosn
+            ,ROUND(COALESCE(return_n_uv / exp_pv,0),4) AS rovn
+            ,ROUND(COALESCE(return_n_uv_noself / share_pv,0),4) AS rosn_noself
+            ,ROUND(COALESCE(return_n_uv_noself / exp_pv,0),4) AS rovn_noself
+            ,ROUND(COALESCE(new_exposure_cnt / exp_pv,0),4) AS vovh24
+            ,max_return_n_uv
+    FROM    (
+                SELECT  COALESCE(dt,"sum") AS dt
+                        ,page
+                        ,abcode
+                        ,single_push_from
+                        ,COUNT(DISTINCT mid) AS exp_uv
+                        ,COUNT(1) AS exp_pv
+                        ,SUM(share_pv) AS share_pv
+                        ,SUM(return_n_uv) AS return_n_uv
+                        ,SUM(return_n_uv_noself) AS return_n_uv_noself
+                        ,SUM(new_exposure_cnt) AS new_exposure_cnt
+                        ,COUNT(DISTINCT vid) AS vid_cnt
+                        ,COUNT(1) / COUNT(DISTINCT vid) AS 视频平均曝光次数
+                        ,MAX(CAST(return_n_uv AS BIGINT)) AS max_return_n_uv
+                FROM    (
+                            SELECT  dt
+                                    ,hh
+                                    ,vid
+                                    ,mid
+                                    ,is_share
+                                    ,share_pv
+                                    ,is_return_1
+                                    ,return_n_uv
+                                    ,return_n_uv_noself
+                                    ,new_exposure_cnt
+                                    ,page
+                                    ,abcode
+                                    ,single_push_from
+                            FROM    base_tab
+                            LATERAL VIEW EXPLODE(push_from_array) t AS single_push_from
+                        ) 
+                GROUP BY dt
+                         ,page
+                         ,abcode
+                         ,single_push_from
+                GROUPING SETS ((dt,page,abcode,single_push_from)
+                              ,(page,abcode,single_push_from))
+            ) 
+)
+SELECT  t1.dt AS 日期
+        ,t1.page AS 页面
+        ,t1.single_push_from AS 召回源
+        ,t1.abcode AS ab分组
+        ,t1.str
+        ,t1.rosn
+        ,t1.rovn
+        ,t1.rosn_noself
+        ,t1.rovn_noself
+        ,t1.vovh24
+        ,t1.exp_uv
+        ,t2.total_exp_uv
+        ,ROUND(t1.exp_uv / t2.total_exp_uv,4) AS exp_uv_rate
+        ,t1.exp_pv
+        ,t2.total_exp_pv
+        ,ROUND(t1.exp_pv / t2.total_exp_pv,4) AS exp_pv_rate
+        ,t1.share_pv
+        ,t2.total_share_pv
+        ,ROUND(t1.share_pv / t2.total_share_pv,4) AS share_pv_rate
+        ,t1.return_n_uv
+        ,t2.total_return_n_uv
+        ,ROUND(t1.return_n_uv / t2.total_return_n_uv,4) AS return_n_uv_rate
+        ,t1.return_n_uv_noself
+        ,t2.total_return_n_uv_noself
+        ,ROUND(t1.return_n_uv_noself / t2.total_return_n_uv_noself,4) AS return_n_uv_rate_noself
+        ,t1.new_exposure_cnt
+        ,t2.total_new_exposure_cnt
+        ,ROUND(t1.new_exposure_cnt / t2.total_new_exposure_cnt,4) AS new_exposure_rate
+        ,t1.vid_cnt
+        ,t2.total_vid_cnt
+        ,ROUND(t1.vid_cnt / t2.total_vid_cnt,4) AS vid_cnt_rate
+        ,ROUND(t1.exp_pv / t1.exp_uv,4) AS 人均曝光pv
+        ,ROUND(t1.share_pv / t1.exp_uv,4) AS 人均分享pv
+        ,t1.视频平均曝光次数
+        ,t1.max_return_n_uv
+FROM    detail_table t1
+JOIN    total_tab t2
+ON      t1.dt = t2.dt
+AND     t1.page = t2.page
+AND     t1.abcode = t2.abcode
+WHERE   t1.page IN ("推荐")
+AND     t1.exp_pv > 100
+ORDER BY t1.dt DESC,t1.page,t1.single_push_from,t1.abcode
+LIMIT   1000
+;