Просмотр исходного кода

feat: 添加曝光回流收益 SQL (v1~v4) 及 AB 效果分析任务

- table_gen: 曝光回流 B+C 多跳计算 v1~v3,v4 新增 D 链(session 内后续曝光传播)
- table_gen: 曝光基础表建表 SQL
- AB效果: 推荐 AB 实时/天级效果、对比对照组、分小时/分seq/含多跳等任务 SQL 及配置

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
yangxiaohui 1 месяц назад
Родитель
Сommit
99634714d2

+ 324 - 0
table_gen/exposure_return_Bn.sql

@@ -0,0 +1,324 @@
+--*********************
+-- 曝光回流收益计算 (B + C 多跳版)
+-- 数学公式:
+--   B_i      = 不换视频回流人数(用 rootshareid 计算)
+--   C_1(i)   = Σ B_j, j 在 E_i 回流用户的 session 中(1跳)
+--   C_2(i)   = Σ B_k, k 在 C_1 涉及曝光的回流用户 session 中(2跳)
+--   C_3(i)   = 同理(3跳)
+--   V_total  = B + C_1 + C_2 + C_3
+--
+-- 相比递推版:
+--   1. 去掉 D(session内累积),避免指数级膨胀
+--   2. 每层 C 独立计算,不依赖上一层结果
+--   3. CTE 从 ~18 个减到 ~12 个
+--*********************
+
+WITH
+--========================================
+-- 1. 基础数据准备
+--========================================
+
+-- 1.1 回流数据(用户通过分享链接回流)
+-- 时间范围:${dt}${hh} 往后 24 小时
+t_return AS (
+    SELECT  *
+            ,CONCAT(dthh,":",shareid,":",vid,":",dthh_id) AS id
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,clickobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,shareid
+                        ,rootshareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,clickobjectid,sessionid,subsessionid,shareid,rootshareid ORDER BY clienttimestamp DESC ) AS rn
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),shareid,clickobjectid ORDER BY clienttimestamp ) AS dthh_id
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 24),'YYYYMMDDHH')
+                AND     __topic__ = 'click'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     clickobjectid IS NOT NULL
+                AND     pagesource REGEXP "-pages/user-videos-share$"
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.2 分享数据
+-- 时间范围:${dt}${hh} 往后 24 小时
+,t_share_from_sharelog AS (
+    SELECT  *
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,shareobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,pagesource
+                        ,shareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,shareobjectid,sessionid,subsessionid,pagesource,shareid ORDER BY clienttimestamp DESC ) AS rn
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 24),'YYYYMMDDHH')
+                AND     __topic__ = 'share'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     shareobjectid IS NOT NULL
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.3 曝光数据
+-- 时间范围:${dt}${hh} 单小时(曝光起点)
+,t_exposure AS (
+    SELECT  dthh_id
+            ,dthh
+            ,apptype
+            ,uid
+            ,mid
+            ,vid
+            ,sessionid
+            ,subsessionid
+            ,pagesource
+            ,ts
+            ,id
+            ,dt
+            ,hh
+    FROM    loghubods.dwd_recsys_alg_exposure_base_view_20250402
+    WHERE   CONCAT(dt,hh) = '${dt}${hh}'
+)
+
+-- 1.4 详情页曝光(用于非常规分享关联)
+,t_exposure_detail AS (
+    SELECT  *
+    FROM    t_exposure
+    WHERE   pagesource REGEXP "-pages/user-videos-detail$|pages/detail-recommend$"
+)
+
+--========================================
+-- 2. 曝光关联分享(单次 JOIN + 优先级选择)
+--========================================
+
+-- 2.1 常规分享关联曝光(一次性匹配所有优先级)
+,t_normal_share_exposure AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                -- 优先级:subsession+pagesource+ts > session+pagesource+ts > ...
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                    WHEN s.subsessionid = e.subsessionid THEN 5
+                    WHEN s.sessionid = e.sessionid THEN 6
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                            WHEN s.subsessionid = e.subsessionid THEN 5
+                            WHEN s.sessionid = e.sessionid THEN 6
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog s
+        LEFT JOIN t_exposure e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource NOT REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+-- 2.2 非常规分享关联曝光(detail页面,一次性匹配)
+,t_no_normal_share_exposure AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid THEN 3
+                    WHEN s.sessionid = e.sessionid THEN 4
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid THEN 3
+                            WHEN s.sessionid = e.sessionid THEN 4
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog s
+        LEFT JOIN t_exposure_detail e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+--========================================
+-- 3. 合并所有分享-曝光关联
+--========================================
+,t_share_exposure AS (
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_normal_share_exposure
+    UNION ALL
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_no_normal_share_exposure
+)
+
+--========================================
+-- 4. 分享关联回流 + B 值计算
+--========================================
+
+-- 4.1 分享关联回流(exposure_id → return_subsessionid)
+,t_share_return AS (
+    SELECT  se.exposure_id
+            ,se.shareid
+            ,se.vid
+            ,se.apptype
+            ,se.subsessionid
+            ,r.subsessionid AS return_subsessionid
+            ,r.mid AS return_mid
+    FROM    t_share_exposure se
+    JOIN    t_return r
+    ON      se.shareid = r.rootshareid
+    AND     se.vid = r.vid
+    AND     se.apptype = r.apptype
+)
+
+-- 4.2 每个曝光的 B 值和 bn_subsessions
+,t_exposure_bn AS (
+    SELECT  e.id AS exposure_id
+            ,e.subsessionid
+            ,e.ts
+            ,e.vid
+            ,e.uid
+            ,e.mid
+            ,COALESCE(bn.B, 0) AS B
+            ,bn.bn_subsessions
+    FROM    t_exposure e
+    LEFT JOIN (
+        SELECT  exposure_id
+                ,COUNT(DISTINCT return_mid) AS B
+                ,COLLECT_SET(return_subsessionid) AS bn_subsessions
+        FROM    t_share_return
+        GROUP BY exposure_id
+    ) bn
+    ON      e.id = bn.exposure_id
+)
+
+--========================================
+-- 5. 多跳计算(直接 JOIN,无递推)
+--========================================
+
+-- C_1: 1跳(exposure → 回流session → 那些session中曝光的B之和)
+,t_c1 AS (
+    SELECT  sr.exposure_id
+            ,SUM(eb.B) AS C_1
+    FROM    t_share_return sr
+    JOIN    t_exposure_bn eb
+    ON      sr.return_subsessionid = eb.subsessionid
+    GROUP BY sr.exposure_id
+)
+
+-- C_2: 2跳
+,t_c2 AS (
+    SELECT  sr1.exposure_id
+            ,SUM(eb2.B) AS C_2
+    FROM    t_share_return sr1
+    JOIN    t_exposure_bn eb1
+    ON      sr1.return_subsessionid = eb1.subsessionid
+    JOIN    t_share_return sr2
+    ON      eb1.exposure_id = sr2.exposure_id
+    JOIN    t_exposure_bn eb2
+    ON      sr2.return_subsessionid = eb2.subsessionid
+    GROUP BY sr1.exposure_id
+)
+
+-- C_3: 3跳
+,t_c3 AS (
+    SELECT  sr1.exposure_id
+            ,SUM(eb3.B) AS C_3
+    FROM    t_share_return sr1
+    JOIN    t_exposure_bn eb1
+    ON      sr1.return_subsessionid = eb1.subsessionid
+    JOIN    t_share_return sr2
+    ON      eb1.exposure_id = sr2.exposure_id
+    JOIN    t_exposure_bn eb2
+    ON      sr2.return_subsessionid = eb2.subsessionid
+    JOIN    t_share_return sr3
+    ON      eb2.exposure_id = sr3.exposure_id
+    JOIN    t_exposure_bn eb3
+    ON      sr3.return_subsessionid = eb3.subsessionid
+    GROUP BY sr1.exposure_id
+)
+
+--========================================
+-- 6. 最终输出
+--========================================
+SELECT  e.id AS exposure_id
+        ,e.vid
+        ,v.title AS video_title
+        ,e.uid
+        ,e.mid
+        ,e.ts
+        ,CASE WHEN se.exposure_id IS NOT NULL THEN 1 ELSE 0 END AS is_share
+        ,COALESCE(bn.B, 0) AS B
+        ,COALESCE(c1.C_1, 0) AS C_1
+        ,COALESCE(c2.C_2, 0) AS C_2
+        ,COALESCE(c3.C_3, 0) AS C_3
+        ,COALESCE(bn.B, 0) + COALESCE(c1.C_1, 0) + COALESCE(c2.C_2, 0) + COALESCE(c3.C_3, 0) AS V_total
+FROM    t_exposure e
+LEFT JOIN (SELECT DISTINCT exposure_id FROM t_share_exposure) se
+ON      e.id = se.exposure_id
+LEFT JOIN t_exposure_bn bn
+ON      e.id = bn.exposure_id
+LEFT JOIN t_c1 c1
+ON      e.id = c1.exposure_id
+LEFT JOIN t_c2 c2
+ON      e.id = c2.exposure_id
+LEFT JOIN t_c3 c3
+ON      e.id = c3.exposure_id
+LEFT JOIN videoods.wx_video v
+ON      e.vid = CAST(v.id AS STRING)
+;

+ 378 - 0
table_gen/exposure_return_Bn_v2.sql

@@ -0,0 +1,378 @@
+--*********************
+-- 曝光回流收益计算 (B + C 多跳版, BFS 去环)
+-- 数学公式:
+--   B_i      = 不换视频回流人数(用 rootshareid 计算)
+--   C_1(i)   = Σ B_j, j ∈ frontier_1(直接触达的 subsession)
+--   C_2(i)   = Σ B_k, k ∈ frontier_2(排除 hop1 已访问的)
+--   C_3(i)   = 同理(排除 hop1 + hop2 已访问的)
+--   V_total  = B + C_1 + C_2 + C_3
+--
+-- 改进: BFS frontier + anti-join 去环
+--   每个 subsession 只在最短跳数被计入,不重复
+--   解决 C_1=C_2=C_3 的环路膨胀问题
+--*********************
+
+WITH
+--========================================
+-- 1. 基础数据准备
+--========================================
+
+-- 1.1 回流数据(用户通过分享链接回流)
+-- 时间范围:${dt}${hh} 往后 24 小时
+t_return AS (
+    SELECT  *
+            ,CONCAT(dthh,":",shareid,":",vid,":",dthh_id) AS id
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,clickobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,shareid
+                        ,rootshareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,clickobjectid,sessionid,subsessionid,shareid,rootshareid ORDER BY clienttimestamp DESC ) AS rn
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),shareid,clickobjectid ORDER BY clienttimestamp ) AS dthh_id
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 24),'YYYYMMDDHH')
+                AND     __topic__ = 'click'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     clickobjectid IS NOT NULL
+                AND     pagesource REGEXP "-pages/user-videos-share$"
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.2 分享数据
+-- 时间范围:${dt}${hh} 往后 24 小时
+,t_share_from_sharelog AS (
+    SELECT  *
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,shareobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,pagesource
+                        ,shareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,shareobjectid,sessionid,subsessionid,pagesource,shareid ORDER BY clienttimestamp DESC ) AS rn
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 24),'YYYYMMDDHH')
+                AND     __topic__ = 'share'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     shareobjectid IS NOT NULL
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.3 曝光数据
+-- 时间范围:${dt}${hh} 单小时(曝光起点)
+,t_exposure AS (
+    SELECT  dthh_id
+            ,dthh
+            ,apptype
+            ,uid
+            ,mid
+            ,vid
+            ,sessionid
+            ,subsessionid
+            ,pagesource
+            ,ts
+            ,id
+            ,dt
+            ,hh
+    FROM    loghubods.dwd_recsys_alg_exposure_base_view_20250402
+    WHERE   CONCAT(dt,hh) = '${dt}${hh}'
+)
+
+-- 1.4 详情页曝光(用于非常规分享关联)
+,t_exposure_detail AS (
+    SELECT  *
+    FROM    t_exposure
+    WHERE   pagesource REGEXP "-pages/user-videos-detail$|pages/detail-recommend$"
+)
+
+--========================================
+-- 2. 曝光关联分享(单次 JOIN + 优先级选择)
+--========================================
+
+-- 2.1 常规分享关联曝光(一次性匹配所有优先级)
+,t_normal_share_exposure AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                -- 优先级:subsession+pagesource+ts > session+pagesource+ts > ...
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                    WHEN s.subsessionid = e.subsessionid THEN 5
+                    WHEN s.sessionid = e.sessionid THEN 6
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                            WHEN s.subsessionid = e.subsessionid THEN 5
+                            WHEN s.sessionid = e.sessionid THEN 6
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog s
+        LEFT JOIN t_exposure e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource NOT REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+-- 2.2 非常规分享关联曝光(detail页面,一次性匹配)
+,t_no_normal_share_exposure AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid THEN 3
+                    WHEN s.sessionid = e.sessionid THEN 4
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid THEN 3
+                            WHEN s.sessionid = e.sessionid THEN 4
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog s
+        LEFT JOIN t_exposure_detail e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+--========================================
+-- 3. 合并所有分享-曝光关联
+--========================================
+,t_share_exposure AS (
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_normal_share_exposure
+    UNION ALL
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_no_normal_share_exposure
+)
+
+--========================================
+-- 4. 分享关联回流 + B 值计算
+--========================================
+
+-- 4.1 分享关联回流(exposure_id → return_subsessionid)
+,t_share_return AS (
+    SELECT  se.exposure_id
+            ,se.shareid
+            ,se.vid
+            ,se.apptype
+            ,se.subsessionid
+            ,r.subsessionid AS return_subsessionid
+            ,r.mid AS return_mid
+    FROM    t_share_exposure se
+    JOIN    t_return r
+    ON      se.shareid = r.rootshareid
+    AND     se.vid = r.vid
+    AND     se.apptype = r.apptype
+)
+
+-- 4.2 每个曝光的 B 值和 bn_subsessions
+,t_exposure_bn AS (
+    SELECT  e.id AS exposure_id
+            ,e.subsessionid
+            ,e.ts
+            ,e.vid
+            ,e.uid
+            ,e.mid
+            ,COALESCE(bn.B, 0) AS B
+            ,bn.bn_subsessions
+    FROM    t_exposure e
+    LEFT JOIN (
+        SELECT  exposure_id
+                ,COUNT(DISTINCT return_mid) AS B
+                ,COLLECT_SET(return_subsessionid) AS bn_subsessions
+        FROM    t_share_return
+        GROUP BY exposure_id
+    ) bn
+    ON      e.id = bn.exposure_id
+)
+
+--========================================
+-- 5. 多跳计算(BFS frontier + anti-join 去环)
+--   每个 subsession 只在最短跳数被计入
+--========================================
+
+-- Frontier 1: 源曝光直接触达的 subsession(去重)
+,t_frontier_1 AS (
+    SELECT DISTINCT exposure_id AS source_id, return_subsessionid AS reached_sub
+    FROM   t_share_return
+)
+
+-- C_1: hop1 触达的 subsession 中曝光的 B 之和
+,t_c1 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_1
+    FROM    t_frontier_1 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+
+-- C_1 涉及的回流 MID(去重)
+,t_c1_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,CONCAT_WS(',', COLLECT_SET(sr.return_mid)) AS C_1_mids
+    FROM    t_frontier_1 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+-- Frontier 2: 从 hop1 延伸一跳,排除 hop1 已访问的 subsession
+,t_frontier_2 AS (
+    SELECT DISTINCT f1.source_id, sr2.return_subsessionid AS reached_sub
+    FROM    t_frontier_1 f1
+    JOIN    t_exposure_bn eb1 ON f1.reached_sub = eb1.subsessionid
+    JOIN    t_share_return sr2 ON eb1.exposure_id = sr2.exposure_id
+    LEFT JOIN t_frontier_1 v1
+        ON  f1.source_id = v1.source_id
+        AND sr2.return_subsessionid = v1.reached_sub
+    WHERE   v1.source_id IS NULL
+)
+
+-- C_2: hop2 触达的 subsession 中曝光的 B 之和
+,t_c2 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_2
+    FROM    t_frontier_2 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+
+-- C_2 涉及的回流 MID(去重)
+,t_c2_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,CONCAT_WS(',', COLLECT_SET(sr.return_mid)) AS C_2_mids
+    FROM    t_frontier_2 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+-- Frontier 3: 从 hop2 延伸一跳,排除 hop1 + hop2 已访问的
+,t_frontier_3 AS (
+    SELECT DISTINCT f2.source_id, sr3.return_subsessionid AS reached_sub
+    FROM    t_frontier_2 f2
+    JOIN    t_exposure_bn eb2 ON f2.reached_sub = eb2.subsessionid
+    JOIN    t_share_return sr3 ON eb2.exposure_id = sr3.exposure_id
+    LEFT JOIN t_frontier_1 v1
+        ON  f2.source_id = v1.source_id
+        AND sr3.return_subsessionid = v1.reached_sub
+    LEFT JOIN t_frontier_2 v2
+        ON  f2.source_id = v2.source_id
+        AND sr3.return_subsessionid = v2.reached_sub
+    WHERE   v1.source_id IS NULL AND v2.source_id IS NULL
+)
+
+-- C_3: hop3 触达的 subsession 中曝光的 B 之和
+,t_c3 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_3
+    FROM    t_frontier_3 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+
+-- C_3 涉及的回流 MID(去重)
+,t_c3_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,CONCAT_WS(',', COLLECT_SET(sr.return_mid)) AS C_3_mids
+    FROM    t_frontier_3 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+--========================================
+-- 6. 最终输出
+--========================================
+SELECT  e.id AS exposure_id
+        ,e.vid
+        ,v.title AS video_title
+        ,e.uid
+        ,e.mid
+        ,e.ts
+        ,CASE WHEN se.exposure_id IS NOT NULL THEN 1 ELSE 0 END AS is_share
+        ,COALESCE(bn.B, 0) AS B
+        ,COALESCE(c1.C_1, 0) AS C_1
+        ,c1m.C_1_mids
+        ,COALESCE(c2.C_2, 0) AS C_2
+        ,c2m.C_2_mids
+        ,COALESCE(c3.C_3, 0) AS C_3
+        ,c3m.C_3_mids
+        ,COALESCE(bn.B, 0) + COALESCE(c1.C_1, 0) + COALESCE(c2.C_2, 0) + COALESCE(c3.C_3, 0) AS V_total
+FROM    t_exposure e
+LEFT JOIN (SELECT DISTINCT exposure_id FROM t_share_exposure) se
+ON      e.id = se.exposure_id
+LEFT JOIN t_exposure_bn bn
+ON      e.id = bn.exposure_id
+LEFT JOIN t_c1 c1
+ON      e.id = c1.exposure_id
+LEFT JOIN t_c1_mids c1m
+ON      e.id = c1m.exposure_id
+LEFT JOIN t_c2 c2
+ON      e.id = c2.exposure_id
+LEFT JOIN t_c2_mids c2m
+ON      e.id = c2m.exposure_id
+LEFT JOIN t_c3 c3
+ON      e.id = c3.exposure_id
+LEFT JOIN t_c3_mids c3m
+ON      e.id = c3m.exposure_id
+LEFT JOIN videoods.wx_video v
+ON      e.vid = CAST(v.id AS STRING)
+;

+ 654 - 0
table_gen/exposure_return_Bn_v3.sql

@@ -0,0 +1,654 @@
+--*********************
+-- 曝光回流收益计算 (B + C 多跳版, BFS 去环, 24h + 48h)
+-- 同时输出 24h 和 48h 窗口的 B/C/mids
+--*********************
+
+WITH
+--========================================
+-- 1. 基础数据准备
+--========================================
+
+-- 1.1 回流数据 24h
+t_return AS (
+    SELECT  *
+            ,CONCAT(dthh,":",shareid,":",vid,":",dthh_id) AS id
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,clickobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,shareid
+                        ,rootshareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,clickobjectid,sessionid,subsessionid,shareid,rootshareid ORDER BY clienttimestamp DESC ) AS rn
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),shareid,clickobjectid ORDER BY clienttimestamp ) AS dthh_id
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 24),'YYYYMMDDHH')
+                AND     __topic__ = 'click'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     clickobjectid IS NOT NULL
+                AND     pagesource REGEXP "-pages/user-videos-share$"
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.1b 回流数据 48h
+,t_return_48h AS (
+    SELECT  *
+            ,CONCAT(dthh,":",shareid,":",vid,":",dthh_id) AS id
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,clickobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,shareid
+                        ,rootshareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,clickobjectid,sessionid,subsessionid,shareid,rootshareid ORDER BY clienttimestamp DESC ) AS rn
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),shareid,clickobjectid ORDER BY clienttimestamp ) AS dthh_id
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 48),'YYYYMMDDHH')
+                AND     __topic__ = 'click'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     clickobjectid IS NOT NULL
+                AND     pagesource REGEXP "-pages/user-videos-share$"
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.2 分享数据 24h
+,t_share_from_sharelog AS (
+    SELECT  *
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,shareobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,pagesource
+                        ,shareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,shareobjectid,sessionid,subsessionid,pagesource,shareid ORDER BY clienttimestamp DESC ) AS rn
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 24),'YYYYMMDDHH')
+                AND     __topic__ = 'share'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     shareobjectid IS NOT NULL
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.2b 分享数据 48h
+,t_share_from_sharelog_48h AS (
+    SELECT  *
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,shareobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,pagesource
+                        ,shareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,shareobjectid,sessionid,subsessionid,pagesource,shareid ORDER BY clienttimestamp DESC ) AS rn
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 48),'YYYYMMDDHH')
+                AND     __topic__ = 'share'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     shareobjectid IS NOT NULL
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.3 曝光数据(共用)
+,t_exposure AS (
+    SELECT  dthh_id
+            ,dthh
+            ,apptype
+            ,uid
+            ,mid
+            ,vid
+            ,sessionid
+            ,subsessionid
+            ,pagesource
+            ,ts
+            ,id
+            ,dt
+            ,hh
+    FROM    loghubods.dwd_recsys_alg_exposure_base_view_20250402
+    WHERE   CONCAT(dt,hh) = '${dt}${hh}'
+)
+
+-- 1.4 详情页曝光(共用)
+,t_exposure_detail AS (
+    SELECT  *
+    FROM    t_exposure
+    WHERE   pagesource REGEXP "-pages/user-videos-detail$|pages/detail-recommend$"
+)
+
+--========================================
+-- 2. 曝光关联分享 24h
+--========================================
+,t_normal_share_exposure AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                    WHEN s.subsessionid = e.subsessionid THEN 5
+                    WHEN s.sessionid = e.sessionid THEN 6
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                            WHEN s.subsessionid = e.subsessionid THEN 5
+                            WHEN s.sessionid = e.sessionid THEN 6
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog s
+        LEFT JOIN t_exposure e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource NOT REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+,t_no_normal_share_exposure AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid THEN 3
+                    WHEN s.sessionid = e.sessionid THEN 4
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid THEN 3
+                            WHEN s.sessionid = e.sessionid THEN 4
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog s
+        LEFT JOIN t_exposure_detail e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+,t_share_exposure AS (
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_normal_share_exposure
+    UNION ALL
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_no_normal_share_exposure
+)
+
+--========================================
+-- 2b. 曝光关联分享 48h
+--========================================
+,t_normal_share_exposure_48h AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                    WHEN s.subsessionid = e.subsessionid THEN 5
+                    WHEN s.sessionid = e.sessionid THEN 6
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                            WHEN s.subsessionid = e.subsessionid THEN 5
+                            WHEN s.sessionid = e.sessionid THEN 6
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog_48h s
+        LEFT JOIN t_exposure e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource NOT REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+,t_no_normal_share_exposure_48h AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid THEN 3
+                    WHEN s.sessionid = e.sessionid THEN 4
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid THEN 3
+                            WHEN s.sessionid = e.sessionid THEN 4
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog_48h s
+        LEFT JOIN t_exposure_detail e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+,t_share_exposure_48h AS (
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_normal_share_exposure_48h
+    UNION ALL
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_no_normal_share_exposure_48h
+)
+
+--========================================
+-- 3. 分享关联回流 + B 值计算 (24h)
+--========================================
+,t_share_return AS (
+    SELECT  se.exposure_id
+            ,se.shareid
+            ,se.vid
+            ,se.apptype
+            ,se.subsessionid
+            ,r.subsessionid AS return_subsessionid
+            ,r.mid AS return_mid
+    FROM    t_share_exposure se
+    JOIN    t_return r
+    ON      se.shareid = r.rootshareid
+    AND     se.vid = r.vid
+    AND     se.apptype = r.apptype
+)
+
+,t_exposure_bn AS (
+    SELECT  e.id AS exposure_id
+            ,e.subsessionid
+            ,e.ts
+            ,e.vid
+            ,e.uid
+            ,e.mid
+            ,COALESCE(bn.B, 0) AS B
+            ,bn.B_mids
+    FROM    t_exposure e
+    LEFT JOIN (
+        SELECT  exposure_id
+                ,COUNT(DISTINCT return_mid) AS B
+                ,COLLECT_SET(return_mid) AS B_mids
+        FROM    t_share_return
+        GROUP BY exposure_id
+    ) bn
+    ON      e.id = bn.exposure_id
+)
+
+--========================================
+-- 3b. 分享关联回流 + B 值计算 (48h)
+--========================================
+,t_share_return_48h AS (
+    SELECT  se.exposure_id
+            ,se.shareid
+            ,se.vid
+            ,se.apptype
+            ,se.subsessionid
+            ,r.subsessionid AS return_subsessionid
+            ,r.mid AS return_mid
+    FROM    t_share_exposure_48h se
+    JOIN    t_return_48h r
+    ON      se.shareid = r.rootshareid
+    AND     se.vid = r.vid
+    AND     se.apptype = r.apptype
+)
+
+,t_exposure_bn_48h AS (
+    SELECT  e.id AS exposure_id
+            ,e.subsessionid
+            ,COALESCE(bn.B, 0) AS B
+            ,bn.B_mids
+    FROM    t_exposure e
+    LEFT JOIN (
+        SELECT  exposure_id
+                ,COUNT(DISTINCT return_mid) AS B
+                ,COLLECT_SET(return_mid) AS B_mids
+        FROM    t_share_return_48h
+        GROUP BY exposure_id
+    ) bn
+    ON      e.id = bn.exposure_id
+)
+
+--========================================
+-- 4. 多跳计算 24h(BFS frontier + subsession 去环)
+--   MID 跨层去重在最终输出用 ARRAY_EXCEPT 计算
+--========================================
+
+,t_frontier_1 AS (
+    SELECT DISTINCT exposure_id AS source_id, return_subsessionid AS reached_sub
+    FROM   t_share_return
+)
+,t_c1 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_1
+    FROM    t_frontier_1 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c1_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_1_mids
+    FROM    t_frontier_1 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+,t_frontier_2 AS (
+    SELECT DISTINCT f1.source_id, sr2.return_subsessionid AS reached_sub
+    FROM    t_frontier_1 f1
+    JOIN    t_exposure_bn eb1 ON f1.reached_sub = eb1.subsessionid
+    JOIN    t_share_return sr2 ON eb1.exposure_id = sr2.exposure_id
+    LEFT JOIN t_frontier_1 v1
+        ON  f1.source_id = v1.source_id
+        AND sr2.return_subsessionid = v1.reached_sub
+    WHERE   v1.source_id IS NULL
+)
+,t_c2 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_2
+    FROM    t_frontier_2 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c2_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_2_mids
+    FROM    t_frontier_2 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+,t_frontier_3 AS (
+    SELECT DISTINCT f2.source_id, sr3.return_subsessionid AS reached_sub
+    FROM    t_frontier_2 f2
+    JOIN    t_exposure_bn eb2 ON f2.reached_sub = eb2.subsessionid
+    JOIN    t_share_return sr3 ON eb2.exposure_id = sr3.exposure_id
+    LEFT JOIN t_frontier_1 v1
+        ON  f2.source_id = v1.source_id
+        AND sr3.return_subsessionid = v1.reached_sub
+    LEFT JOIN t_frontier_2 v2
+        ON  f2.source_id = v2.source_id
+        AND sr3.return_subsessionid = v2.reached_sub
+    WHERE   v1.source_id IS NULL AND v2.source_id IS NULL
+)
+,t_c3 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_3
+    FROM    t_frontier_3 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c3_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_3_mids
+    FROM    t_frontier_3 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+--========================================
+-- 4b. 多跳计算 48h(BFS frontier + subsession 去环)
+--========================================
+
+,t_frontier_1_48h AS (
+    SELECT DISTINCT exposure_id AS source_id, return_subsessionid AS reached_sub
+    FROM   t_share_return_48h
+)
+,t_c1_48h AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_1
+    FROM    t_frontier_1_48h f
+    JOIN    t_exposure_bn_48h eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c1_mids_48h AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_1_mids
+    FROM    t_frontier_1_48h f
+    JOIN    t_exposure_bn_48h eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return_48h sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+,t_frontier_2_48h AS (
+    SELECT DISTINCT f1.source_id, sr2.return_subsessionid AS reached_sub
+    FROM    t_frontier_1_48h f1
+    JOIN    t_exposure_bn_48h eb1 ON f1.reached_sub = eb1.subsessionid
+    JOIN    t_share_return_48h sr2 ON eb1.exposure_id = sr2.exposure_id
+    LEFT JOIN t_frontier_1_48h v1
+        ON  f1.source_id = v1.source_id
+        AND sr2.return_subsessionid = v1.reached_sub
+    WHERE   v1.source_id IS NULL
+)
+,t_c2_48h AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_2
+    FROM    t_frontier_2_48h f
+    JOIN    t_exposure_bn_48h eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c2_mids_48h AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_2_mids
+    FROM    t_frontier_2_48h f
+    JOIN    t_exposure_bn_48h eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return_48h sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+,t_frontier_3_48h AS (
+    SELECT DISTINCT f2.source_id, sr3.return_subsessionid AS reached_sub
+    FROM    t_frontier_2_48h f2
+    JOIN    t_exposure_bn_48h eb2 ON f2.reached_sub = eb2.subsessionid
+    JOIN    t_share_return_48h sr3 ON eb2.exposure_id = sr3.exposure_id
+    LEFT JOIN t_frontier_1_48h v1
+        ON  f2.source_id = v1.source_id
+        AND sr3.return_subsessionid = v1.reached_sub
+    LEFT JOIN t_frontier_2_48h v2
+        ON  f2.source_id = v2.source_id
+        AND sr3.return_subsessionid = v2.reached_sub
+    WHERE   v1.source_id IS NULL AND v2.source_id IS NULL
+)
+,t_c3_48h AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_3
+    FROM    t_frontier_3_48h f
+    JOIN    t_exposure_bn_48h eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c3_mids_48h AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_3_mids
+    FROM    t_frontier_3_48h f
+    JOIN    t_exposure_bn_48h eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return_48h sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+--========================================
+-- 5. 最终输出
+--========================================
+SELECT  e.id AS exposure_id
+        ,e.vid
+        ,v.title AS video_title
+        ,e.uid
+        ,e.mid
+        ,e.ts
+        -- 24h 非去重
+        ,CASE WHEN se.exposure_id IS NOT NULL THEN 1 ELSE 0 END AS is_share
+        ,COALESCE(bn.B, 0) AS B
+        ,CONCAT_WS(',', bn.B_mids) AS B_mids
+        ,COALESCE(c1.C_1, 0) AS C_1
+        ,CONCAT_WS(',', c1m.C_1_mids) AS C_1_mids
+        ,COALESCE(c2.C_2, 0) AS C_2
+        ,CONCAT_WS(',', c2m.C_2_mids) AS C_2_mids
+        ,COALESCE(c3.C_3, 0) AS C_3
+        ,CONCAT_WS(',', c3m.C_3_mids) AS C_3_mids
+        ,COALESCE(bn.B, 0) + COALESCE(c1.C_1, 0) + COALESCE(c2.C_2, 0) + COALESCE(c3.C_3, 0) AS V_total
+        -- 24h 去重(ARRAY_EXCEPT 跨层排除已计入的 MID)
+        ,SIZE(c1m.C_1_mids) AS C_1_distinct
+        ,IF(c1m.C_1_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(c1m.C_1_mids, COALESCE(bn.B_mids, ARRAY('')))), 0) AS C_1_dedup
+        ,IF(c2m.C_2_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(c2m.C_2_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(c1m.C_1_mids, ARRAY('')))), 0) AS C_2_dedup
+        ,IF(c3m.C_3_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(ARRAY_EXCEPT(c3m.C_3_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(c1m.C_1_mids, ARRAY(''))), COALESCE(c2m.C_2_mids, ARRAY('')))), 0) AS C_3_dedup
+        ,COALESCE(bn.B, 0)
+            + IF(c1m.C_1_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(c1m.C_1_mids, COALESCE(bn.B_mids, ARRAY('')))), 0)
+            + IF(c2m.C_2_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(c2m.C_2_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(c1m.C_1_mids, ARRAY('')))), 0)
+            + IF(c3m.C_3_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(ARRAY_EXCEPT(c3m.C_3_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(c1m.C_1_mids, ARRAY(''))), COALESCE(c2m.C_2_mids, ARRAY('')))), 0)
+            AS V_total_dedup
+        -- 48h 非去重
+        ,CASE WHEN se48.exposure_id IS NOT NULL THEN 1 ELSE 0 END AS is_share_48h
+        ,COALESCE(bn48.B, 0) AS B_48h
+        ,CONCAT_WS(',', bn48.B_mids) AS B_mids_48h
+        ,COALESCE(c1_48.C_1, 0) AS C_1_48h
+        ,CONCAT_WS(',', c1m48.C_1_mids) AS C_1_mids_48h
+        ,COALESCE(c2_48.C_2, 0) AS C_2_48h
+        ,CONCAT_WS(',', c2m48.C_2_mids) AS C_2_mids_48h
+        ,COALESCE(c3_48.C_3, 0) AS C_3_48h
+        ,CONCAT_WS(',', c3m48.C_3_mids) AS C_3_mids_48h
+        ,COALESCE(bn48.B, 0) + COALESCE(c1_48.C_1, 0) + COALESCE(c2_48.C_2, 0) + COALESCE(c3_48.C_3, 0) AS V_total_48h
+        -- 48h 去重
+        ,IF(c1m48.C_1_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(c1m48.C_1_mids, COALESCE(bn48.B_mids, ARRAY('')))), 0) AS C_1_dedup_48h
+        ,IF(c2m48.C_2_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(c2m48.C_2_mids, COALESCE(bn48.B_mids, ARRAY(''))), COALESCE(c1m48.C_1_mids, ARRAY('')))), 0) AS C_2_dedup_48h
+        ,IF(c3m48.C_3_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(ARRAY_EXCEPT(c3m48.C_3_mids, COALESCE(bn48.B_mids, ARRAY(''))), COALESCE(c1m48.C_1_mids, ARRAY(''))), COALESCE(c2m48.C_2_mids, ARRAY('')))), 0) AS C_3_dedup_48h
+        ,COALESCE(bn48.B, 0)
+            + IF(c1m48.C_1_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(c1m48.C_1_mids, COALESCE(bn48.B_mids, ARRAY('')))), 0)
+            + IF(c2m48.C_2_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(c2m48.C_2_mids, COALESCE(bn48.B_mids, ARRAY(''))), COALESCE(c1m48.C_1_mids, ARRAY('')))), 0)
+            + IF(c3m48.C_3_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(ARRAY_EXCEPT(c3m48.C_3_mids, COALESCE(bn48.B_mids, ARRAY(''))), COALESCE(c1m48.C_1_mids, ARRAY(''))), COALESCE(c2m48.C_2_mids, ARRAY('')))), 0)
+            AS V_total_dedup_48h
+FROM    t_exposure e
+-- 24h joins
+LEFT JOIN (SELECT DISTINCT exposure_id FROM t_share_exposure) se
+ON      e.id = se.exposure_id
+LEFT JOIN t_exposure_bn bn
+ON      e.id = bn.exposure_id
+LEFT JOIN t_c1 c1
+ON      e.id = c1.exposure_id
+LEFT JOIN t_c1_mids c1m
+ON      e.id = c1m.exposure_id
+LEFT JOIN t_c2 c2
+ON      e.id = c2.exposure_id
+LEFT JOIN t_c2_mids c2m
+ON      e.id = c2m.exposure_id
+LEFT JOIN t_c3 c3
+ON      e.id = c3.exposure_id
+LEFT JOIN t_c3_mids c3m
+ON      e.id = c3m.exposure_id
+-- 48h joins
+LEFT JOIN (SELECT DISTINCT exposure_id FROM t_share_exposure_48h) se48
+ON      e.id = se48.exposure_id
+LEFT JOIN t_exposure_bn_48h bn48
+ON      e.id = bn48.exposure_id
+LEFT JOIN t_c1_48h c1_48
+ON      e.id = c1_48.exposure_id
+LEFT JOIN t_c1_mids_48h c1m48
+ON      e.id = c1m48.exposure_id
+LEFT JOIN t_c2_48h c2_48
+ON      e.id = c2_48.exposure_id
+LEFT JOIN t_c2_mids_48h c2m48
+ON      e.id = c2m48.exposure_id
+LEFT JOIN t_c3_48h c3_48
+ON      e.id = c3_48.exposure_id
+LEFT JOIN t_c3_mids_48h c3m48
+ON      e.id = c3m48.exposure_id
+-- video info
+LEFT JOIN videoods.wx_video v
+ON      e.vid = CAST(v.id AS STRING)
+;

+ 460 - 0
table_gen/exposure_return_Bn_v4.sql

@@ -0,0 +1,460 @@
+--*********************
+-- 曝光回流收益计算 (B + C 多跳 + D 链, BFS 去环, 24h)
+-- D 链: session 内后续曝光的传播收益
+--*********************
+
+WITH
+--========================================
+-- 1. 基础数据准备
+--========================================
+
+-- 1.1 回流数据 24h
+t_return AS (
+    SELECT  *
+            ,CONCAT(dthh,":",shareid,":",vid,":",dthh_id) AS id
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,clickobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,shareid
+                        ,rootshareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,clickobjectid,sessionid,subsessionid,shareid,rootshareid ORDER BY clienttimestamp DESC ) AS rn
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),shareid,clickobjectid ORDER BY clienttimestamp ) AS dthh_id
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 24),'YYYYMMDDHH')
+                AND     __topic__ = 'click'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     clickobjectid IS NOT NULL
+                AND     pagesource REGEXP "-pages/user-videos-share$"
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.2 分享数据 24h
+,t_share_from_sharelog AS (
+    SELECT  *
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,shareobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,pagesource
+                        ,shareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,shareobjectid,sessionid,subsessionid,pagesource,shareid ORDER BY clienttimestamp DESC ) AS rn
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN '${dt}${hh}' AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) + 3600 * 24),'YYYYMMDDHH')
+                AND     __topic__ = 'share'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     shareobjectid IS NOT NULL
+            ) t
+    WHERE   rn = 1
+)
+
+-- 1.3 曝光数据(共用)
+,t_exposure AS (
+    SELECT  dthh_id
+            ,dthh
+            ,apptype
+            ,uid
+            ,mid
+            ,vid
+            ,sessionid
+            ,subsessionid
+            ,pagesource
+            ,ts
+            ,id
+            ,dt
+            ,hh
+    FROM    loghubods.dwd_recsys_alg_exposure_base_view_20250402
+    WHERE   CONCAT(dt,hh) = '${dt}${hh}'
+)
+
+-- 1.4 详情页曝光(共用)
+,t_exposure_detail AS (
+    SELECT  *
+    FROM    t_exposure
+    WHERE   pagesource REGEXP "-pages/user-videos-detail$|pages/detail-recommend$"
+)
+
+--========================================
+-- 2. 曝光关联分享 24h
+--========================================
+,t_normal_share_exposure AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                    WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                    WHEN s.subsessionid = e.subsessionid THEN 5
+                    WHEN s.sessionid = e.sessionid THEN 6
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid AND s.pagesource = e.pagesource THEN 3
+                            WHEN s.sessionid = e.sessionid AND s.pagesource = e.pagesource THEN 4
+                            WHEN s.subsessionid = e.subsessionid THEN 5
+                            WHEN s.sessionid = e.sessionid THEN 6
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog s
+        LEFT JOIN t_exposure e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource NOT REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+,t_no_normal_share_exposure AS (
+    SELECT  *
+    FROM    (
+        SELECT  s.dthh
+                ,s.apptype
+                ,s.mid
+                ,s.vid
+                ,s.sessionid
+                ,s.subsessionid
+                ,s.pagesource
+                ,s.shareid
+                ,s.ts
+                ,e.id AS exposure_id
+                ,e.ts AS exposure_ts
+                ,CASE
+                    WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                    WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                    WHEN s.subsessionid = e.subsessionid THEN 3
+                    WHEN s.sessionid = e.sessionid THEN 4
+                END AS match_priority
+                ,ROW_NUMBER() OVER (
+                    PARTITION BY s.dthh,s.apptype,s.mid,s.vid,s.sessionid,s.subsessionid,s.pagesource,s.shareid
+                    ORDER BY
+                        CASE
+                            WHEN s.subsessionid = e.subsessionid AND s.ts >= e.ts THEN 1
+                            WHEN s.sessionid = e.sessionid AND s.ts >= e.ts THEN 2
+                            WHEN s.subsessionid = e.subsessionid THEN 3
+                            WHEN s.sessionid = e.sessionid THEN 4
+                        END
+                        ,e.ts DESC
+                ) AS rn
+        FROM    t_share_from_sharelog s
+        LEFT JOIN t_exposure_detail e
+        ON      s.apptype = e.apptype
+        AND     s.mid = e.mid
+        AND     s.vid = e.vid
+        AND     (s.subsessionid = e.subsessionid OR s.sessionid = e.sessionid)
+        WHERE   s.pagesource REGEXP "pages/detail-user-videos-share-recommend$"
+    ) t
+    WHERE   rn = 1
+)
+
+,t_share_exposure AS (
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_normal_share_exposure
+    UNION ALL
+    SELECT  dthh, apptype, mid, vid, sessionid, subsessionid, pagesource, shareid, ts, exposure_id, exposure_ts
+    FROM    t_no_normal_share_exposure
+)
+
+--========================================
+-- 3. 分享关联回流 + B 值计算 (24h)
+--========================================
+,t_share_return AS (
+    SELECT  se.exposure_id
+            ,se.shareid
+            ,se.vid
+            ,se.apptype
+            ,se.subsessionid
+            ,r.subsessionid AS return_subsessionid
+            ,r.mid AS return_mid
+    FROM    t_share_exposure se
+    JOIN    t_return r
+    ON      se.shareid = r.rootshareid
+    AND     se.vid = r.vid
+    AND     se.apptype = r.apptype
+)
+
+,t_exposure_bn AS (
+    SELECT  e.id AS exposure_id
+            ,e.subsessionid
+            ,e.ts
+            ,e.vid
+            ,e.uid
+            ,e.mid
+            ,COALESCE(bn.B, 0) AS B
+            ,bn.B_mids
+    FROM    t_exposure e
+    LEFT JOIN (
+        SELECT  exposure_id
+                ,COUNT(DISTINCT return_mid) AS B
+                ,COLLECT_SET(return_mid) AS B_mids
+        FROM    t_share_return
+        GROUP BY exposure_id
+    ) bn
+    ON      e.id = bn.exposure_id
+)
+
+--========================================
+-- 4. C 链多跳计算 24h(BFS frontier + subsession 去环)
+--   MID 跨层去重在最终输出用 ARRAY_EXCEPT 计算
+--========================================
+
+,t_frontier_1 AS (
+    SELECT DISTINCT exposure_id AS source_id, return_subsessionid AS reached_sub
+    FROM   t_share_return
+)
+,t_c1 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_1
+    FROM    t_frontier_1 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c1_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_1_mids
+    FROM    t_frontier_1 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+,t_frontier_2 AS (
+    SELECT DISTINCT f1.source_id, sr2.return_subsessionid AS reached_sub
+    FROM    t_frontier_1 f1
+    JOIN    t_exposure_bn eb1 ON f1.reached_sub = eb1.subsessionid
+    JOIN    t_share_return sr2 ON eb1.exposure_id = sr2.exposure_id
+    LEFT JOIN t_frontier_1 v1
+        ON  f1.source_id = v1.source_id
+        AND sr2.return_subsessionid = v1.reached_sub
+    WHERE   v1.source_id IS NULL
+)
+,t_c2 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_2
+    FROM    t_frontier_2 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c2_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_2_mids
+    FROM    t_frontier_2 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+,t_frontier_3 AS (
+    SELECT DISTINCT f2.source_id, sr3.return_subsessionid AS reached_sub
+    FROM    t_frontier_2 f2
+    JOIN    t_exposure_bn eb2 ON f2.reached_sub = eb2.subsessionid
+    JOIN    t_share_return sr3 ON eb2.exposure_id = sr3.exposure_id
+    LEFT JOIN t_frontier_1 v1
+        ON  f2.source_id = v1.source_id
+        AND sr3.return_subsessionid = v1.reached_sub
+    LEFT JOIN t_frontier_2 v2
+        ON  f2.source_id = v2.source_id
+        AND sr3.return_subsessionid = v2.reached_sub
+    WHERE   v1.source_id IS NULL AND v2.source_id IS NULL
+)
+,t_c3 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS C_3
+    FROM    t_frontier_3 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_c3_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_3_mids
+    FROM    t_frontier_3 f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+--========================================
+-- 5. D 链(session 内后续曝光传播)
+--========================================
+
+-- 5a. t_d1 — 同 subsession 后续曝光的 B 之和
+,t_d1 AS (
+    SELECT  e1.exposure_id
+            ,SUM(e2.B) AS D_1
+    FROM    t_exposure_bn e1
+    JOIN    t_exposure_bn e2
+    ON      e1.subsessionid = e2.subsessionid
+    AND     e2.ts > e1.ts
+    GROUP BY e1.exposure_id
+)
+
+-- 5b. t_d1_mids — 后续曝光的 return mids
+,t_d1_mids AS (
+    SELECT  e1.exposure_id
+            ,COLLECT_SET(sr.return_mid) AS D_1_mids
+    FROM    t_exposure_bn e1
+    JOIN    t_exposure_bn e2
+    ON      e1.subsessionid = e2.subsessionid
+    AND     e2.ts > e1.ts
+    JOIN    t_share_return sr
+    ON      e2.exposure_id = sr.exposure_id
+    GROUP BY e1.exposure_id
+)
+
+-- 5c. t_d1_frontier — d1 后续曝光的 return users 落入的 subsessions
+,t_d1_frontier AS (
+    SELECT DISTINCT e1.exposure_id AS source_id
+           ,sr.return_subsessionid AS reached_sub
+    FROM    t_exposure_bn e1
+    JOIN    t_exposure_bn e2
+    ON      e1.subsessionid = e2.subsessionid
+    AND     e2.ts > e1.ts
+    JOIN    t_share_return sr
+    ON      e2.exposure_id = sr.exposure_id
+)
+
+-- 5d. t_d2 / t_d2_mids — BFS 第二跳
+,t_d2 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS D_2
+    FROM    t_d1_frontier f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_d2_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS D_2_mids
+    FROM    t_d1_frontier f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+-- 5e. t_d2_frontier / t_d3 / t_d3_mids — BFS 第三跳(含去环)
+,t_d2_frontier AS (
+    SELECT DISTINCT f1.source_id, sr2.return_subsessionid AS reached_sub
+    FROM    t_d1_frontier f1
+    JOIN    t_exposure_bn eb1 ON f1.reached_sub = eb1.subsessionid
+    JOIN    t_share_return sr2 ON eb1.exposure_id = sr2.exposure_id
+    LEFT JOIN t_d1_frontier v1
+        ON  f1.source_id = v1.source_id
+        AND sr2.return_subsessionid = v1.reached_sub
+    WHERE   v1.source_id IS NULL
+)
+,t_d3 AS (
+    SELECT  f.source_id AS exposure_id, SUM(eb.B) AS D_3
+    FROM    t_d2_frontier f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    GROUP BY f.source_id
+)
+,t_d3_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS D_3_mids
+    FROM    t_d2_frontier f
+    JOIN    t_exposure_bn eb ON f.reached_sub = eb.subsessionid
+    JOIN    t_share_return sr ON eb.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+
+--========================================
+-- 6. 最终输出
+--========================================
+SELECT  e.id AS exposure_id
+        ,e.vid
+        ,v.title AS video_title
+        ,e.uid
+        ,e.mid
+        ,e.ts
+        -- 24h 非去重
+        ,CASE WHEN se.exposure_id IS NOT NULL THEN 1 ELSE 0 END AS is_share
+        ,COALESCE(bn.B, 0) AS B
+        ,CONCAT_WS(',', bn.B_mids) AS B_mids
+        ,COALESCE(c1.C_1, 0) AS C_1
+        ,CONCAT_WS(',', c1m.C_1_mids) AS C_1_mids
+        ,COALESCE(c2.C_2, 0) AS C_2
+        ,CONCAT_WS(',', c2m.C_2_mids) AS C_2_mids
+        ,COALESCE(c3.C_3, 0) AS C_3
+        ,CONCAT_WS(',', c3m.C_3_mids) AS C_3_mids
+        ,COALESCE(bn.B, 0) + COALESCE(c1.C_1, 0) + COALESCE(c2.C_2, 0) + COALESCE(c3.C_3, 0) AS V_total
+        -- 24h 去重(ARRAY_EXCEPT 跨层排除已计入的 MID)
+        ,SIZE(c1m.C_1_mids) AS C_1_distinct
+        ,IF(c1m.C_1_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(c1m.C_1_mids, COALESCE(bn.B_mids, ARRAY('')))), 0) AS C_1_dedup
+        ,IF(c2m.C_2_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(c2m.C_2_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(c1m.C_1_mids, ARRAY('')))), 0) AS C_2_dedup
+        ,IF(c3m.C_3_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(ARRAY_EXCEPT(c3m.C_3_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(c1m.C_1_mids, ARRAY(''))), COALESCE(c2m.C_2_mids, ARRAY('')))), 0) AS C_3_dedup
+        ,COALESCE(bn.B, 0)
+            + IF(c1m.C_1_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(c1m.C_1_mids, COALESCE(bn.B_mids, ARRAY('')))), 0)
+            + IF(c2m.C_2_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(c2m.C_2_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(c1m.C_1_mids, ARRAY('')))), 0)
+            + IF(c3m.C_3_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(ARRAY_EXCEPT(c3m.C_3_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(c1m.C_1_mids, ARRAY(''))), COALESCE(c2m.C_2_mids, ARRAY('')))), 0)
+            AS V_total_dedup
+        -- D 链(session 内后续曝光传播)非去重
+        ,COALESCE(d1.D_1, 0) AS D_1
+        ,CONCAT_WS(',', d1m.D_1_mids) AS D_1_mids
+        ,COALESCE(d2.D_2, 0) AS D_2
+        ,CONCAT_WS(',', d2m.D_2_mids) AS D_2_mids
+        ,COALESCE(d3.D_3, 0) AS D_3
+        ,CONCAT_WS(',', d3m.D_3_mids) AS D_3_mids
+        ,COALESCE(d1.D_1, 0) + COALESCE(d2.D_2, 0) + COALESCE(d3.D_3, 0) AS D_total
+        -- D 链去重(ARRAY_EXCEPT 跨层排除)
+        ,IF(d1m.D_1_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(d1m.D_1_mids, COALESCE(bn.B_mids, ARRAY('')))), 0) AS D_1_dedup
+        ,IF(d2m.D_2_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(d2m.D_2_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(d1m.D_1_mids, ARRAY('')))), 0) AS D_2_dedup
+        ,IF(d3m.D_3_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(ARRAY_EXCEPT(d3m.D_3_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(d1m.D_1_mids, ARRAY(''))), COALESCE(d2m.D_2_mids, ARRAY('')))), 0) AS D_3_dedup
+        ,IF(d1m.D_1_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(d1m.D_1_mids, COALESCE(bn.B_mids, ARRAY('')))), 0)
+            + IF(d2m.D_2_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(d2m.D_2_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(d1m.D_1_mids, ARRAY('')))), 0)
+            + IF(d3m.D_3_mids IS NOT NULL, SIZE(ARRAY_EXCEPT(ARRAY_EXCEPT(ARRAY_EXCEPT(d3m.D_3_mids, COALESCE(bn.B_mids, ARRAY(''))), COALESCE(d1m.D_1_mids, ARRAY(''))), COALESCE(d2m.D_2_mids, ARRAY('')))), 0)
+            AS D_total_dedup
+FROM    t_exposure e
+-- 24h joins
+LEFT JOIN (SELECT DISTINCT exposure_id FROM t_share_exposure) se
+ON      e.id = se.exposure_id
+LEFT JOIN t_exposure_bn bn
+ON      e.id = bn.exposure_id
+LEFT JOIN t_c1 c1
+ON      e.id = c1.exposure_id
+LEFT JOIN t_c1_mids c1m
+ON      e.id = c1m.exposure_id
+LEFT JOIN t_c2 c2
+ON      e.id = c2.exposure_id
+LEFT JOIN t_c2_mids c2m
+ON      e.id = c2m.exposure_id
+LEFT JOIN t_c3 c3
+ON      e.id = c3.exposure_id
+LEFT JOIN t_c3_mids c3m
+ON      e.id = c3m.exposure_id
+-- D chain joins
+LEFT JOIN t_d1 d1 ON e.id = d1.exposure_id
+LEFT JOIN t_d1_mids d1m ON e.id = d1m.exposure_id
+LEFT JOIN t_d2 d2 ON e.id = d2.exposure_id
+LEFT JOIN t_d2_mids d2m ON e.id = d2m.exposure_id
+LEFT JOIN t_d3 d3 ON e.id = d3.exposure_id
+LEFT JOIN t_d3_mids d3m ON e.id = d3m.exposure_id
+-- video info
+LEFT JOIN videoods.wx_video v
+ON      e.vid = CAST(v.id AS STRING)
+;

+ 912 - 0
table_gen/loghubods.dwd_recsys_alg_exposure_base_20260206.sql

@@ -0,0 +1,912 @@
+--@exclude_input=loghubods.video_action_log_flow_new
+--@exclude_input=loghubods.user_share_log_flow
+--*********************
+-- alg_recsys_rank_labelmatch_20260206
+-- 在 20250108 基础上新增 B/C 多跳回流列
+--*********************
+--drop table loghubods.dwd_recsys_alg_exposure_base_20260206;
+CREATE TABLE IF NOT EXISTS loghubods.dwd_recsys_alg_exposure_base_20260206
+(
+    apptype                    STRING
+    ,uid                       STRING
+    ,mid                       STRING
+    ,vid                       STRING
+    ,sessionid                 STRING
+    ,subsessionid              STRING
+    ,pagesource                STRING
+    ,page                      STRING
+    ,recommendlogvo            STRING COMMENT '推荐算法的返回结果日志存在这个字段中'
+    ,abcode                    STRING COMMENT '推荐算法的ab分组:ab0'
+    ,recommendpagetype         STRING COMMENT '用于区分pagesource相同时某些场景的。三种回流头部;两种下滑-沉浸页下滑和feed下滑。 -pages/user-videos-share-recommend-detail 是沉浸页。'
+    ,recomtraceid              STRING COMMENT '在后端调取推荐服务之前生成。前端降级会空;后端也可能为空。'
+    ,headvideoid               STRING
+    ,rootsourceid              STRING COMMENT '区分touliu等流量,咨询产品。'
+    ,hotsencetype              STRING
+    ,flowpool                  STRING COMMENT '非流量池,是空字符串。没有null值。'
+    ,level                     STRING COMMENT '非流量池,是null。'
+    ,clientip                  STRING
+    ,machineinfo_brand         STRING
+    ,machineinfo_model         STRING
+    ,machineinfo_system        STRING
+    ,machineinfo_wechatversion STRING
+    ,machineinfo_sdkversion    STRING
+    ,province                  STRING
+    ,city                      STRING
+    ,ts                        STRING
+    ,is_share                  STRING
+    ,share_cnt                 STRING
+    ,is_return_1               STRING
+    ,return_1_pv               STRING
+    ,return_1_uv               STRING
+    ,return_1_mids             STRING
+    ,is_return_n               STRING
+    ,return_n_pv               STRING
+    ,return_n_uv               STRING
+    ,return_n_mids             STRING
+    ,is_return_noself          STRING
+    ,return_1_uv_noself        STRING
+    ,return_1_mids_noself      STRING
+    ,is_return_n_noself        STRING
+    ,return_n_uv_noself        STRING
+    ,return_n_mids_noself      STRING
+    ,new_exposure_cnt          STRING
+    ,b                         STRING COMMENT '直接回流去重人数(B)'
+    ,c_1                       STRING COMMENT '1跳回流SUM(B)'
+    ,c_2                       STRING COMMENT '2跳回流SUM(B)'
+    ,c_3                       STRING COMMENT '3跳回流SUM(B)'
+    ,b_mids                    STRING COMMENT 'B对应的回流mid列表'
+    ,c_1_mids                  STRING COMMENT 'C_1对应的回流mid列表'
+    ,c_2_mids                  STRING COMMENT 'C_2对应的回流mid列表'
+    ,c_3_mids                  STRING COMMENT 'C_3对应的回流mid列表'
+    ,extend                    STRING
+)
+PARTITIONED BY
+(
+    dt                         STRING COMMENT '日期:20240105'
+    ,hh                        STRING COMMENT '小时:04'
+)
+STORED AS ALIORC
+TBLPROPERTIES ('comment' = '推荐算法-labelmatch表-20260206更新-含多跳B/C')
+LIFECYCLE 3650
+;
+
+SET hive.exec.dynamic.partition = true
+;
+
+SET hive.exec.dynamic.partition.mode = nonstrict
+;
+
+SET odps.stage.mapper.split.size = 1024
+;
+
+INSERT OVERWRITE TABLE loghubods.dwd_recsys_alg_exposure_base_20260206 PARTITION (dt,hh)
+WITH t_return AS
+(
+    SELECT  *
+            ,CONCAT(dthh,":",shareid,":",vid,":",dthh_id) AS id
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,clickobjectid AS vid
+                        ,sessionid
+                        ,subsessionid -- 注意这是回流对应的subsessionid,每次回流点击会重置,可以通过这个字段找到回流的曝光。
+                        ,shareid
+                        ,rootshareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,clickobjectid,sessionid,subsessionid,shareid,rootshareid ORDER BY clienttimestamp DESC ) AS rn
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),shareid,clickobjectid ORDER BY clienttimestamp ) AS dthh_id
+                FROM    loghubods.user_share_log_flow -- 回流行为,理应subsessionid只有一条,但有脏数据,去重。
+                WHERE   CONCAT(year,month,day,hour) BETWEEN TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) - 3600 * 25),'YYYYMMDDHH') AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) - 3600 * 1),'YYYYMMDDHH') --WHERE   CONCAT(year,month,day,hour) = TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) - 3600 * 25),'YYYYMMDDHH')
+                AND     __topic__ = 'click'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12') -- 12的pagesoucre是h5-share和h5-detail 暂时过滤掉 不做处理
+                AND     machinecode IS NOT NULL
+                AND     clickobjectid IS NOT NULL
+                AND     pagesource REGEXP "-pages/user-videos-share$" -- 存在脏数据 vlog-gzh /mine/mine-info$ 结尾的,都过滤掉。
+            )
+    WHERE   rn = 1
+)
+,t_share_from_sharelog AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  CONCAT(year,month,day,hour) AS dthh
+                        ,apptype
+                        ,machinecode AS mid
+                        ,shareobjectid AS vid
+                        ,sessionid
+                        ,subsessionid
+                        ,pagesource
+                        ,shareid
+                        ,CAST(clienttimestamp / 1000 AS BIGINT) AS ts
+                        ,ROW_NUMBER() OVER (PARTITION BY CONCAT(year,month,day,hour),apptype,machinecode,shareobjectid,sessionid,subsessionid,pagesource,shareid ORDER BY clienttimestamp DESC ) AS rn
+                FROM    loghubods.user_share_log_flow
+                WHERE   CONCAT(year,month,day,hour) BETWEEN TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) - 3600 * 25),'YYYYMMDDHH') AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) - 3600 * 1),'YYYYMMDDHH') --WHERE   CONCAT(year,month,day,hour) = TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) - 3600 * 25),'YYYYMMDDHH')
+                AND     __topic__ = 'share'
+                AND     apptype IS NOT NULL
+                AND     apptype NOT IN ('12')
+                AND     machinecode IS NOT NULL
+                AND     shareobjectid IS NOT NULL
+            )
+    WHERE   rn = 1
+)
+,t_exposure AS
+(
+    SELECT  dthh_id
+            ,dthh
+            ,apptype
+            ,uid
+            ,mid
+            ,vid
+            ,sessionid
+            ,subsessionid
+            ,rootsessionid_new
+            ,pagesource
+            ,recommendlogvo
+            ,abcode
+            ,recommendpagetype
+            ,recomtraceid
+            ,headvideoid
+            ,rootsourceid
+            ,hotsencetype
+            ,animationscenetype
+            ,JSON_PARSE(IF(JSON_VALID(extparams),extparams,"{}")) AS extParams
+            ,flowpool
+            ,level
+            ,clientip
+            ,machineinfo_brand
+            ,machineinfo_model
+            ,machineinfo_system
+            ,machineinfo_wechatversion
+            ,machineinfo_sdkversion
+            ,province
+            ,city
+            ,versioncode
+            ,ts
+            ,rn
+            ,id
+            ,dt
+            ,hh
+    FROM    loghubods.dwd_recsys_alg_exposure_base_view_20250402
+    WHERE   CONCAT(dt,hh) BETWEEN TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) - 3600 * 25),'YYYYMMDDHH') AND TO_CHAR(FROM_UNIXTIME(UNIX_TIMESTAMP(TO_DATE('${dt}${hh}','YYYYMMDDHH')) - 3600 * 1),'YYYYMMDDHH')
+)
+,t_exposure_recommend AS
+(
+    SELECT  *
+    FROM    t_exposure
+    WHERE   pagesource REGEXP 'category$|recommend$|-pages/user-videos-detail$'
+)
+,t_return_exposure_1 AS -- 曝光关联回流,用于计算viewh24
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.id AS exposure_id
+                        ,t1.mid AS mid
+                        ,t1.vid AS vid
+                        ,t1.subsessionid AS subsessionid
+                        ,t1.sessionid AS sessionid
+                        ,t1.headvideoid AS headvideoid
+                        ,t1.dthh
+                        ,t2.id AS return_id
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY t2.ts DESC ) AS rn
+                FROM    t_exposure_recommend t1
+                LEFT JOIN t_return t2
+                ON      t1.mid = t2.mid
+                AND     t1.headvideoid = t2.vid
+                AND     t1.subsessionid = t2.subsessionid
+            )
+    WHERE   rn = 1
+)
+,t_return_exposure_2 AS -- 曝光关联回流,用于计算viewh24
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.exposure_id AS exposure_id
+                        ,t1.mid AS mid
+                        ,t1.vid AS vid
+                        ,t1.subsessionid AS subsessionid
+                        ,t1.sessionid AS sessionid
+                        ,t1.headvideoid AS headvideoid
+                        ,t1.dthh
+                        ,t2.id AS return_id
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.exposure_id ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_return_exposure_1
+                            WHERE   return_id IS NULL
+                        ) t1
+                LEFT JOIN t_return t2
+                ON      t1.mid = t2.mid
+                AND     t1.headvideoid = t2.vid
+                AND     t1.sessionid = t2.sessionid
+            )
+    WHERE   rn = 1
+)
+,t_return_exposure_3 AS -- 曝光关联回流,用于计算viewh24
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.exposure_id AS exposure_id
+                        ,t1.mid AS mid
+                        ,t1.vid AS vid
+                        ,t1.subsessionid AS subsessionid
+                        ,t1.sessionid AS sessionid
+                        ,t1.headvideoid AS headvideoid
+                        ,t1.dthh
+                        ,t2.id AS return_id
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.exposure_id ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_return_exposure_2
+                            WHERE   return_id IS NULL
+                        ) t1
+                LEFT JOIN t_return t2
+                ON      t1.mid = t2.mid
+                AND     t1.subsessionid = t2.subsessionid
+            )
+    WHERE   rn = 1
+)
+,t_return_exposure_4 AS -- 曝光关联回流,用于计算viewh24
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.exposure_id AS exposure_id
+                        ,t1.mid AS mid
+                        ,t1.vid AS vid
+                        ,t1.subsessionid AS subsessionid
+                        ,t1.sessionid AS sessionid
+                        ,t1.headvideoid AS headvideoid
+                        ,t1.dthh
+                        ,t2.id AS return_id
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.exposure_id ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_return_exposure_3
+                            WHERE   return_id IS NULL
+                        ) t1
+                LEFT JOIN t_return t2
+                ON      t1.mid = t2.mid
+                AND     t1.sessionid = t2.sessionid
+            )
+    WHERE   rn = 1
+)
+,t_return_exposure AS
+(
+    SELECT  a.*
+            ,b.exposure_cnt AS new_exposure_cnt
+    FROM    t_return a
+    LEFT JOIN   (
+                    SELECT  return_id
+                            ,COUNT(1) AS exposure_cnt
+                    FROM    (
+                                SELECT  *
+                                FROM    t_return_exposure_1
+                                WHERE   return_id IS NOT NULL
+                                UNION ALL
+                                SELECT  *
+                                FROM    t_return_exposure_2
+                                WHERE   return_id IS NOT NULL
+                                UNION ALL
+                                SELECT  *
+                                FROM    t_return_exposure_3
+                                WHERE   return_id IS NOT NULL
+                                UNION ALL
+                                SELECT  *
+                                FROM    t_return_exposure_4
+                                WHERE   return_id IS NOT NULL
+                            )
+                    GROUP BY return_id
+                ) b
+    ON      a.id = b.return_id
+)
+,t_normal_share_exposure_1 AS -- 开始处理常规的分享与曝光关联
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    t_share_from_sharelog t1
+                LEFT JOIN t_exposure t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.subsessionid = t2.subsessionid
+                AND     t1.pagesource = t2.pagesource
+                AND     t1.ts >= t2.ts
+                WHERE   t1.pagesource NOT REGEXP "pages/detail-user-videos-share-recommend$"
+            )
+    WHERE   rn = 1
+)
+,t_normal_share_exposure_2 AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_normal_share_exposure_1
+                            WHERE   exposure_id IS NULL
+                        ) t1
+                LEFT JOIN t_exposure t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.sessionid = t2.sessionid
+                AND     t1.pagesource = t2.pagesource
+                AND     t1.ts >= t2.ts
+            )
+    WHERE   rn = 1
+)
+,t_normal_share_exposure_3 AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_normal_share_exposure_2
+                            WHERE   exposure_id IS NULL
+                        ) t1
+                LEFT JOIN t_exposure t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.subsessionid = t2.subsessionid
+                AND     t1.pagesource = t2.pagesource
+            )
+    WHERE   rn = 1
+)
+,t_normal_share_exposure_4 AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_normal_share_exposure_3
+                            WHERE   exposure_id IS NULL
+                        ) t1
+                LEFT JOIN t_exposure t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.sessionid = t2.sessionid
+                AND     t1.pagesource = t2.pagesource
+            )
+    WHERE   rn = 1
+)
+,t_normal_share_exposure_5 AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_normal_share_exposure_4
+                            WHERE   exposure_id IS NULL
+                        ) t1
+                LEFT JOIN t_exposure t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.subsessionid = t2.subsessionid
+            )
+    WHERE   rn = 1
+)
+,t_normal_share_exposure_6 AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_normal_share_exposure_5
+                            WHERE   exposure_id IS NULL
+                        ) t1
+                LEFT JOIN t_exposure t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.sessionid = t2.sessionid
+            )
+    WHERE   rn = 1
+)
+,t_exposure_detail AS
+(
+    SELECT  *
+    FROM    t_exposure
+    WHERE   pagesource REGEXP "-pages/user-videos-detail$|pages/detail-recommend$"
+)
+,t_no_normal_share_exposure_1 AS -- 开始处理非常规的分享与曝光关联
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    t_share_from_sharelog t1
+                LEFT JOIN t_exposure_detail t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.subsessionid = t2.subsessionid
+                AND     t1.ts >= t2.ts
+                WHERE   t1.pagesource REGEXP "pages/detail-user-videos-share-recommend$"
+            )
+    WHERE   rn = 1
+)
+,t_no_normal_share_exposure_2 AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_no_normal_share_exposure_1
+                            WHERE   exposure_id IS NULL
+                        ) t1
+                LEFT JOIN t_exposure_detail t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.sessionid = t2.sessionid
+                AND     t1.ts >= t2.ts
+            )
+    WHERE   rn = 1
+)
+,t_no_normal_share_exposure_3 AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_no_normal_share_exposure_2
+                            WHERE   exposure_id IS NULL
+                        ) t1
+                LEFT JOIN t_exposure_detail t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.subsessionid = t2.subsessionid
+            )
+    WHERE   rn = 1
+)
+,t_no_normal_share_exposure_4 AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  t1.dthh
+                        ,t1.apptype
+                        ,t1.mid
+                        ,t1.vid
+                        ,t1.sessionid
+                        ,t1.subsessionid
+                        ,t1.pagesource
+                        ,t1.shareid
+                        ,t1.ts
+                        ,t2.id AS exposure_id
+                        ,t2.ts AS exposure_ts
+                        ,ROW_NUMBER() OVER (PARTITION BY t1.dthh,t1.apptype,t1.mid,t1.vid,t1.sessionid,t1.subsessionid,t1.pagesource,t1.shareid ORDER BY t2.ts DESC ) AS rn
+                FROM    (
+                            SELECT  *
+                            FROM    t_no_normal_share_exposure_3
+                            WHERE   exposure_id IS NULL
+                        ) t1
+                LEFT JOIN t_exposure_detail t2
+                ON      t1.apptype = t2.apptype
+                AND     t1.mid = t2.mid
+                AND     t1.vid = t2.vid
+                AND     t1.sessionid = t2.sessionid
+            )
+    WHERE   rn = 1
+)
+,t_share_exposure AS
+(
+    SELECT  *
+    FROM    t_normal_share_exposure_1
+    WHERE   exposure_id IS NOT NULL
+    UNION ALL
+    SELECT  *
+    FROM    t_normal_share_exposure_2
+    WHERE   exposure_id IS NOT NULL
+    UNION ALL
+    SELECT  *
+    FROM    t_normal_share_exposure_3
+    WHERE   exposure_id IS NOT NULL
+    UNION ALL
+    SELECT  *
+    FROM    t_normal_share_exposure_4
+    WHERE   exposure_id IS NOT NULL
+    UNION ALL
+    SELECT  *
+    FROM    t_normal_share_exposure_5
+    WHERE   exposure_id IS NOT NULL
+    UNION ALL
+    SELECT  *
+    FROM    t_normal_share_exposure_6
+    UNION ALL
+    SELECT  *
+    FROM    t_no_normal_share_exposure_1
+    WHERE   exposure_id IS NOT NULL
+    UNION ALL
+    SELECT  *
+    FROM    t_no_normal_share_exposure_2
+    WHERE   exposure_id IS NOT NULL
+    UNION ALL
+    SELECT  *
+    FROM    t_no_normal_share_exposure_3
+    WHERE   exposure_id IS NOT NULL
+    UNION ALL
+    SELECT  *
+    FROM    t_no_normal_share_exposure_4
+)
+--========================================
+-- 多跳 B/C 计算 (BFS frontier + anti-join 去环, 仅 24h)
+--========================================
+,t_share_return AS (
+    SELECT  se.exposure_id
+            ,se.shareid
+            ,se.vid
+            ,se.apptype
+            ,se.subsessionid
+            ,r.subsessionid AS return_subsessionid
+            ,r.mid AS return_mid
+    FROM    t_share_exposure se
+    JOIN    t_return r
+    ON      se.shareid = r.rootshareid
+    AND     se.vid = r.vid
+    AND     se.apptype = r.apptype
+)
+,t_exposure_bn AS (
+    SELECT  exposure_id
+            ,COUNT(DISTINCT return_mid) AS B
+            ,COLLECT_SET(return_mid) AS B_mids
+    FROM    t_share_return
+    GROUP BY exposure_id
+)
+-- BFS frontier 1: 直达回流的 subsessionid 集合
+,t_frontier_1 AS (
+    SELECT DISTINCT exposure_id AS source_id, return_subsessionid AS reached_sub
+    FROM   t_share_return
+)
+-- C_1: frontier_1 中曝光的 B 之和
+,t_c1 AS (
+    SELECT  f.source_id AS exposure_id, SUM(bn.B) AS C_1
+    FROM    t_frontier_1 f
+    JOIN    t_exposure e ON f.reached_sub = e.subsessionid
+    JOIN    t_exposure_bn bn ON e.id = bn.exposure_id
+    GROUP BY f.source_id
+)
+,t_c1_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_1_mids
+    FROM    t_frontier_1 f
+    JOIN    t_exposure e ON f.reached_sub = e.subsessionid
+    JOIN    t_exposure_bn bn ON e.id = bn.exposure_id
+    JOIN    t_share_return sr ON bn.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+-- BFS frontier 2: frontier_1 延伸, anti-join 排除 frontier_1
+,t_frontier_2 AS (
+    SELECT DISTINCT f1.source_id, sr2.return_subsessionid AS reached_sub
+    FROM    t_frontier_1 f1
+    JOIN    t_exposure e1 ON f1.reached_sub = e1.subsessionid
+    JOIN    t_exposure_bn bn1 ON e1.id = bn1.exposure_id
+    JOIN    t_share_return sr2 ON bn1.exposure_id = sr2.exposure_id
+    LEFT JOIN t_frontier_1 v1
+        ON  f1.source_id = v1.source_id
+        AND sr2.return_subsessionid = v1.reached_sub
+    WHERE   v1.source_id IS NULL
+)
+,t_c2 AS (
+    SELECT  f.source_id AS exposure_id, SUM(bn.B) AS C_2
+    FROM    t_frontier_2 f
+    JOIN    t_exposure e ON f.reached_sub = e.subsessionid
+    JOIN    t_exposure_bn bn ON e.id = bn.exposure_id
+    GROUP BY f.source_id
+)
+,t_c2_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_2_mids
+    FROM    t_frontier_2 f
+    JOIN    t_exposure e ON f.reached_sub = e.subsessionid
+    JOIN    t_exposure_bn bn ON e.id = bn.exposure_id
+    JOIN    t_share_return sr ON bn.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+-- BFS frontier 3: frontier_2 延伸, anti-join 排除 frontier_1 + frontier_2
+,t_frontier_3 AS (
+    SELECT DISTINCT f2.source_id, sr3.return_subsessionid AS reached_sub
+    FROM    t_frontier_2 f2
+    JOIN    t_exposure e2 ON f2.reached_sub = e2.subsessionid
+    JOIN    t_exposure_bn bn2 ON e2.id = bn2.exposure_id
+    JOIN    t_share_return sr3 ON bn2.exposure_id = sr3.exposure_id
+    LEFT JOIN t_frontier_1 v1
+        ON  f2.source_id = v1.source_id
+        AND sr3.return_subsessionid = v1.reached_sub
+    LEFT JOIN t_frontier_2 v2
+        ON  f2.source_id = v2.source_id
+        AND sr3.return_subsessionid = v2.reached_sub
+    WHERE   v1.source_id IS NULL AND v2.source_id IS NULL
+)
+,t_c3 AS (
+    SELECT  f.source_id AS exposure_id, SUM(bn.B) AS C_3
+    FROM    t_frontier_3 f
+    JOIN    t_exposure e ON f.reached_sub = e.subsessionid
+    JOIN    t_exposure_bn bn ON e.id = bn.exposure_id
+    GROUP BY f.source_id
+)
+,t_c3_mids AS (
+    SELECT  f.source_id AS exposure_id
+            ,COLLECT_SET(sr.return_mid) AS C_3_mids
+    FROM    t_frontier_3 f
+    JOIN    t_exposure e ON f.reached_sub = e.subsessionid
+    JOIN    t_exposure_bn bn ON e.id = bn.exposure_id
+    JOIN    t_share_return sr ON bn.exposure_id = sr.exposure_id
+    GROUP BY f.source_id
+)
+--========================================
+-- 以下为原有 CTE 继续
+--========================================
+,t_share_with_label AS
+(
+    SELECT  a.dthh
+            ,a.apptype -- join 条件
+            ,a.mid
+            ,a.vid -- join 条件
+            ,a.sessionid
+            ,a.subsessionid
+            ,a.pagesource
+            ,a.shareid -- join 条件
+            ,a.ts
+            ,a.exposure_id
+            ,COALESCE(b.return_1_pv,0) AS return_1_pv
+            ,COALESCE(b.return_1_uv,0) AS return_1_uv
+            ,b.return_1_mids AS return_1_mids -- 可能为null,再决策是否提前处理。
+            ,COALESCE(c.return_n_pv,0) AS return_n_pv
+            ,COALESCE(c.return_n_uv,0) AS return_n_uv
+            ,c.return_n_mids AS return_n_mids -- 可能为null,再决策是否提前处理。
+            ,COALESCE(c.new_exposure_cnt,0) AS new_exposure_cnt
+    FROM    t_share_exposure a
+    LEFT JOIN   (
+                    SELECT  shareid
+                            ,vid
+                            ,apptype
+                            ,COUNT(1) AS return_1_pv
+                            ,COUNT(DISTINCT mid) AS return_1_uv
+                            ,CONCAT_WS(',',COLLECT_SET(mid)) AS return_1_mids
+                    FROM    t_return
+                    GROUP BY shareid
+                             ,vid
+                             ,apptype
+                ) b
+    ON      a.shareid = b.shareid
+    AND     a.vid = b.vid
+    AND     a.apptype = b.apptype
+    LEFT JOIN   (
+                    SELECT  rootshareid
+                            ,vid
+                            ,apptype
+                            ,COUNT(1) AS return_n_pv
+                            ,COUNT(DISTINCT mid) AS return_n_uv
+                            ,CONCAT_WS(',',COLLECT_SET(mid)) AS return_n_mids
+                            ,SUM(new_exposure_cnt) AS new_exposure_cnt
+                    FROM    t_return_exposure
+                    GROUP BY rootshareid
+                             ,vid
+                             ,apptype
+                ) c
+    ON      a.shareid = c.rootshareid
+    AND     a.vid = c.vid
+    AND     a.apptype = c.apptype
+)
+,t_share_with_label_group AS
+(
+    SELECT  exposure_id
+            ,COUNT(1) AS share_cnt
+            ,SUM(return_1_pv) AS return_1_pv
+            ,COALESCE(SIZE(SPLIT(DEDUPLICATION4LIST(CONCAT_WS(',',COLLECT_LIST(return_1_mids))),",")),0) AS return_1_uv
+            ,DEDUPLICATION4LIST(CONCAT_WS(',',COLLECT_LIST(return_1_mids))) AS return_1_mids -- 可能是null
+            ,SUM(return_n_pv) AS return_n_pv
+            ,COALESCE(SIZE(SPLIT(DEDUPLICATION4LIST(CONCAT_WS(',',COLLECT_LIST(return_n_mids))),",")),0) AS return_n_uv
+            ,DEDUPLICATION4LIST(CONCAT_WS(',',COLLECT_LIST(return_n_mids))) AS return_n_mids -- 可能是null
+            ,SUM(new_exposure_cnt) AS new_exposure_cnt
+    FROM    t_share_with_label
+    GROUP BY exposure_id
+)
+,t_root_source_id_group_name AS
+(
+    SELECT  *
+    FROM    (
+                SELECT  root_source_id
+                        ,group_name
+                        ,ROW_NUMBER() OVER (PARTITION BY root_source_id ) AS rn
+                FROM    loghubods.changwen_rootsourceid_group_hour
+                WHERE   dt = MAX_PT('loghubods.changwen_rootsourceid_group_hour')
+            )
+    WHERE   rn = 1
+)
+,t_exposure_share_return AS
+(
+    SELECT  apptype
+            ,uid
+            ,mid
+            ,vid
+            ,sessionid
+            ,subsessionid
+            ,pagesource
+            ,CASE   WHEN pagesource REGEXP 'pages/user-videos-share-recommend$' THEN '回流后沉浸页&内页feed'
+                    WHEN pagesource REGEXP 'pages/detail-recommend$' THEN '详情后沉浸页'
+                    WHEN pagesource REGEXP 'pages/user-videos-share$' THEN '回流页'
+                    WHEN pagesource REGEXP 'pages/user-videos-detail$' THEN '详情页'
+                    WHEN pagesource REGEXP 'pages/category$' THEN '首页feed'
+                    ELSE '其他'
+            END AS pagesource_new
+            ,recommendlogvo -- 推荐算法的返回结果日志存在这个字段中
+            ,abcode -- 推荐算法的ab分组
+            ,recommendpagetype -- 三种回流头部;两种下滑-沉浸页下滑和feed下滑
+            ,recomtraceid
+            ,headvideoid
+            ,rootsourceid
+            ,hotsencetype
+            ,flowpool -- 14#68#3#1735262438476#2
+            ,level
+            ,clientip
+            ,machineinfo_brand
+            ,machineinfo_model
+            ,machineinfo_system
+            ,machineinfo_wechatversion
+            ,machineinfo_sdkversion
+            ,province
+            ,city
+            ,ts
+            ,IF(COALESCE(share_cnt,0) > 0,1,0) AS is_share
+            ,COALESCE(share_cnt,0) AS share_cnt
+            ,IF(COALESCE(return_1_uv,0) > 0,1,0) AS is_return_1
+            ,COALESCE(return_1_pv,0) AS return_1_pv
+            ,COALESCE(return_1_uv,0) AS return_1_uv
+            ,return_1_mids -- 可能是null
+            ,IF(COALESCE(return_n_pv,0) > 0,1,0) AS is_return_n
+            ,COALESCE(return_n_pv,0) AS return_n_pv
+            ,COALESCE(return_n_uv,0) AS return_n_uv
+            ,return_n_mids -- 可能是null
+            ,IF(COALESCE(COALESCE(SIZE(ARRAY_REMOVE(SPLIT(return_1_mids,","),mid)),0),0) > 0,1,0) AS is_return_noself
+            ,COALESCE(SIZE(ARRAY_REMOVE(SPLIT(return_1_mids,","),mid)),0) AS return_1_uv_noself
+            ,ARRAY_JOIN(ARRAY_REMOVE(SPLIT(return_1_mids,","),mid),",") AS return_1_mids_noself
+            ,IF(COALESCE(COALESCE(SIZE(ARRAY_REMOVE(SPLIT(return_n_mids,","),mid)),0),0) > 0,1,0) AS is_return_n_noself
+            ,COALESCE(SIZE(ARRAY_REMOVE(SPLIT(return_n_mids,","),mid)),0) AS return_n_uv_noself
+            ,ARRAY_JOIN(ARRAY_REMOVE(SPLIT(return_n_mids,","),mid),",") AS return_n_mids_noself
+            ,COALESCE(new_exposure_cnt) AS new_exposure_cnt
+            ,COALESCE(bn_hop.B, 0) AS b
+            ,COALESCE(c1_hop.C_1, 0) AS c_1
+            ,COALESCE(c2_hop.C_2, 0) AS c_2
+            ,COALESCE(c3_hop.C_3, 0) AS c_3
+            ,CONCAT_WS(',', bn_hop.B_mids) AS b_mids
+            ,CONCAT_WS(',', c1m_hop.C_1_mids) AS c_1_mids
+            ,CONCAT_WS(',', c2m_hop.C_2_mids) AS c_2_mids
+            ,CONCAT_WS(',', c3m_hop.C_3_mids) AS c_3_mids
+            ,JSON_FORMAT(
+                        JSON_OBJECT("animationSceneType",animationSceneType,"extParams",extParams,"rootsessionid",rootsessionid_new,"versioncode",versioncode,"group_name",tc.group_name)
+            ) AS extend
+            ,SUBSTR(dthh,1,8) AS dt
+            ,SUBSTR(dthh,9,2) AS hh
+    FROM    t_exposure ta
+    LEFT JOIN t_share_with_label_group tb
+    ON      ta.id = tb.exposure_id
+    LEFT JOIN t_root_source_id_group_name tc
+    ON      ta.rootsourceid = tc.root_source_id
+    LEFT JOIN t_exposure_bn bn_hop
+    ON      ta.id = bn_hop.exposure_id
+    LEFT JOIN t_c1 c1_hop
+    ON      ta.id = c1_hop.exposure_id
+    LEFT JOIN t_c1_mids c1m_hop
+    ON      ta.id = c1m_hop.exposure_id
+    LEFT JOIN t_c2 c2_hop
+    ON      ta.id = c2_hop.exposure_id
+    LEFT JOIN t_c2_mids c2m_hop
+    ON      ta.id = c2m_hop.exposure_id
+    LEFT JOIN t_c3 c3_hop
+    ON      ta.id = c3_hop.exposure_id
+    LEFT JOIN t_c3_mids c3m_hop
+    ON      ta.id = c3m_hop.exposure_id
+)SELECT  *
+FROM    t_exposure_share_return
+;

+ 6 - 0
tasks/00_AB效果/01_推荐AB天级效果.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "L9pxuw",
+  "sort": "dt:desc",
+  "cols": null
+}

+ 85 - 0
tasks/00_AB效果/01_推荐AB天级效果.sql

@@ -0,0 +1,85 @@
+WITH t_base AS 
+(
+    SELECT  dt
+            ,apptype 
+            -- ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
+            --         WHEN apptype IN ("4") AND abcode IN ("ab4","ab5","ab6","ab7","ab8","ab9") THEN "实验组-str+校准"
+            --         WHEN apptype IN ("4") AND abcode IN ("ab2","ab3") THEN "对照组"
+            --         WHEN apptype IN ("0") AND abcode IN ("ab0","ab1","ab4","ab5","ab6","ab7","ab8","ab9") THEN "实验组-str+校准"
+            --         WHEN apptype IN ("0") AND abcode IN ("ab2","ab3") THEN "对照组"
+            --         ELSE "其他"
+            -- END AS abcode
+            ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
+                    WHEN apptype IN ("4") AND abcode IN ("ab6","ab7") THEN "实验组-str+校准&ros-统计量"
+                    WHEN apptype IN ("4") AND abcode IN ("ab8","ab9") THEN "实验组-str+校准&ros损失函数优化"
+                    WHEN apptype IN ("4") AND abcode IN ("ab4","ab5") THEN "实验组-str+校准&ros天级更新"
+                    WHEN apptype IN ("4") AND abcode IN ("ab2","ab3") THEN "对照组"
+                    ELSE "其他"
+            END AS abcode
+            -- ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
+            --         WHEN apptype IN ("4") AND abcode IN ("ab8","ab9") THEN "实验组-str+校准"
+            --         WHEN apptype IN ("4") AND abcode IN ("ab2","ab3","ab4","ab5","ab6","ab7") THEN "对照组"
+            --         ELSE "其他"
+            -- END AS abcode
+            ,CASE   WHEN page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页") THEN "推荐"
+                    WHEN page IN ("回流页","其他") THEN "非推荐"
+                    ELSE "其他"
+            END AS page
+            ,mid
+            ,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
+    FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
+    WHERE   dt = '${dt}'
+    AND     apptype IN ("4")
+    AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页","回流页","其他")
+    AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
+    AND     abcode NOT IN ("ab100")
+)
+SELECT  dt
+        ,COALESCE(apptype,"sum") AS apptype
+        ,COALESCE(abcode,"sum") AS abcode
+        ,COALESCE(page,"sum") AS page
+        ,round(COALESCE(COUNT(1) / COUNT(DISTINCT mid),0),2) AS exp_per_dau
+        ,round(COALESCE(SUM(is_share) / COUNT(1),0),6) AS str_one
+        ,round(COALESCE(SUM(return_n_uv) / SUM(is_share),0),6) AS ros_one
+        ,round(COALESCE(SUM(share_cnt) / COUNT(1),0),6) AS str
+        ,round(COALESCE(SUM(return_n_uv) / SUM(share_cnt),0),6) AS ros
+        ,round(COALESCE(SUM(is_return_1) / COUNT(1),0),6) AS str_plus
+        ,round(COALESCE(SUM(return_n_uv) / SUM(is_return_1),0),6) AS ros_minus
+        ,round(COALESCE(SUM(return_n_uv) / COUNT(1),0),6) AS rovn
+        ,round(COALESCE(SUM(new_exposure_cnt) / COUNT(1),0),6) AS vovh24
+        ,COUNT(DISTINCT mid) AS dau
+        ,COUNT(1) AS exp
+        ,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 -- ,MAX(CAST(COALESCE(share_cnt,'0') AS BIGINT)) AS max_share_cnt
+        -- ,MAX(CAST(COALESCE(return_1_uv,'0') AS BIGINT)) AS max_return_1_uv
+        -- ,MAX(CAST(COALESCE(return_n_uv,'0') AS BIGINT)) AS max_return_n_uv
+        -- ,MAX(CAST(COALESCE(return_n_uv_noself,'0') AS BIGINT)) AS max_return_n_uv_noself
+        -- ,COALESCE(SUM(is_return_noself),0) AS is_return_noself
+        -- ,COALESCE(SUM(return_1_uv),0) AS return_1_uv
+        -- ,COUNT(DISTINCT vid) AS exp_vid_cnt
+        -- ,COUNT(DISTINCT CASE    WHEN is_share = '1' THEN vid ELSE NULL END) AS share_vid_cnt
+        -- ,COUNT(DISTINCT CASE    WHEN is_return_n = '1' THEN vid ELSE NULL END) AS return_vid_cnt
+FROM    t_base
+where page in ("推荐")
+GROUP BY dt
+         ,apptype
+         ,abcode
+         ,page
+-- GROUPING SETS ((dt,apptype,abcode)
+--               ,(dt,apptype,abcode,page))
+ORDER BY dt DESC,apptype,page,abcode
+;

+ 4 - 1
tasks/00_AB效果/01_推荐AB实时效果.sql

@@ -1,6 +1,7 @@
 WITH t_base AS 
 (
     SELECT  dt
+            ,hh
             ,apptype 
             -- ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
             --         WHEN apptype IN ("4") AND abcode IN ("ab4","ab5","ab6","ab7","ab8","ab9") THEN "实验组-str+校准"
@@ -39,7 +40,7 @@ WITH t_base AS
             ,flowpool
     FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
     WHERE   dt = '${dt}'
-    AND     hh BETWEEN "16" AND "24"
+--     AND     hh BETWEEN "16" AND "24"
     AND     apptype IN ("4")
     AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页","回流页","其他")
     AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
@@ -74,6 +75,8 @@ SELECT  dt
         -- ,COUNT(DISTINCT vid) AS exp_vid_cnt
         -- ,COUNT(DISTINCT CASE    WHEN is_share = '1' THEN vid ELSE NULL END) AS share_vid_cnt
         -- ,COUNT(DISTINCT CASE    WHEN is_return_n = '1' THEN vid ELSE NULL END) AS return_vid_cnt
+        ,min(hh) as start_hh
+        ,max(hh) as end_hh
 FROM    t_base
 where page in ("推荐")
 GROUP BY dt

+ 6 - 0
tasks/00_AB效果/01_推荐AB实时效果_分小时.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "JWT28U",
+  "sort": "dt:desc,hh:asc",
+  "cols": null
+}

+ 145 - 0
tasks/00_AB效果/01_推荐AB实时效果_分小时.sql

@@ -0,0 +1,145 @@
+-- 推荐AB实时效果 - 分小时对比对照组
+-- 新增维度:hh(小时),各指标相对对照组的变化率(lift)
+WITH t_base AS
+(
+    SELECT  dt
+            ,hh
+            ,apptype
+            ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
+                    WHEN apptype IN ("4") AND abcode IN ("ab6","ab7") THEN "实验组-str+校准&ros-统计量"
+                    WHEN apptype IN ("4") AND abcode IN ("ab8","ab9") THEN "实验组-str+校准&ros损失函数优化"
+                    WHEN apptype IN ("4") AND abcode IN ("ab4","ab5") THEN "实验组-str+校准&ros天级更新"
+                    WHEN apptype IN ("4") AND abcode IN ("ab2","ab3") THEN "对照组"
+                    ELSE "其他"
+            END AS abcode
+            ,CASE   WHEN page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页") THEN "推荐"
+                    WHEN page IN ("回流页","其他") THEN "非推荐"
+                    ELSE "其他"
+            END AS page
+            ,mid
+            ,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
+    FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
+    WHERE   dt = '${dt}'
+    AND     apptype IN ("4")
+    AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页","回流页","其他")
+    AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
+    AND     abcode NOT IN ("ab100")
+),
+-- 计算各组基础指标(按小时)
+t_metrics AS (
+    SELECT  dt
+            ,hh
+            ,apptype
+            ,abcode
+            ,page
+            ,COUNT(1) / COUNT(DISTINCT mid) AS exp_per_dau
+            ,SUM(is_share) / COUNT(1) AS str_one
+            ,SUM(return_n_uv) / SUM(is_share) AS ros_one
+            ,SUM(share_cnt) / COUNT(1) AS str
+            ,SUM(return_n_uv) / SUM(share_cnt) AS ros
+            ,SUM(is_return_1) / COUNT(1) AS str_plus
+            ,SUM(return_n_uv) / SUM(is_return_1) AS ros_minus
+            ,SUM(return_n_uv) / COUNT(1) AS rovn
+            ,SUM(new_exposure_cnt) / COUNT(1) AS vovh24
+            ,COUNT(DISTINCT mid) AS dau
+            ,COUNT(1) AS exp
+            ,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
+    FROM    t_base
+    WHERE   page IN ("推荐")
+    GROUP BY dt
+             ,hh
+             ,apptype
+             ,abcode
+             ,page
+),
+-- 获取对照组数据(按小时)
+t_control AS (
+    SELECT  dt
+            ,hh
+            ,apptype
+            ,page
+            ,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
+            ,str_plus AS ctrl_str_plus
+            ,ros_minus AS ctrl_ros_minus
+            ,rovn AS ctrl_rovn
+            ,vovh24 AS ctrl_vovh24
+            ,dau AS ctrl_dau
+            ,exp AS ctrl_exp
+            ,is_share AS ctrl_is_share
+            ,share_cnt AS ctrl_share_cnt
+            ,is_return_1 AS ctrl_is_return_1
+            ,return_n_uv AS ctrl_return_n_uv
+            ,viewh24 AS ctrl_viewh24
+            ,return_n_uv_noself AS ctrl_return_n_uv_noself
+    FROM    t_metrics
+    WHERE   abcode = "对照组"
+)
+-- 关联对照组,计算变化率
+SELECT  m.dt
+        ,m.hh
+        ,m.apptype
+        ,m.abcode
+        ,m.page
+        -- 原始指标
+        ,m.exp_per_dau
+        ,m.str_one
+        ,m.ros_one
+        ,m.str
+        ,m.ros
+        ,m.str_plus
+        ,m.ros_minus
+        ,m.rovn
+        ,m.vovh24
+        ,m.dau
+        ,m.exp
+        ,m.is_share
+        ,m.share_cnt
+        ,m.is_return_1
+        ,m.return_n_uv
+        ,m.viewh24
+        ,m.return_n_uv_noself
+        -- 相对对照组变化率
+        ,(m.exp_per_dau - c.ctrl_exp_per_dau) / c.ctrl_exp_per_dau AS exp_per_dau_lift
+        ,(m.str_one - c.ctrl_str_one) / c.ctrl_str_one AS str_one_lift
+        ,(m.ros_one - c.ctrl_ros_one) / c.ctrl_ros_one AS ros_one_lift
+        ,(m.str - c.ctrl_str) / c.ctrl_str AS str_lift
+        ,(m.ros - c.ctrl_ros) / c.ctrl_ros AS ros_lift
+        ,(m.str_plus - c.ctrl_str_plus) / c.ctrl_str_plus AS str_plus_lift
+        ,(m.ros_minus - c.ctrl_ros_minus) / c.ctrl_ros_minus AS ros_minus_lift
+        ,(m.rovn - c.ctrl_rovn) / c.ctrl_rovn AS rovn_lift
+        ,(m.vovh24 - c.ctrl_vovh24) / c.ctrl_vovh24 AS vovh24_lift
+        ,(m.dau - c.ctrl_dau) / c.ctrl_dau AS dau_lift
+        ,(m.exp - c.ctrl_exp) / c.ctrl_exp AS exp_lift
+        ,(m.is_share - c.ctrl_is_share) / c.ctrl_is_share AS is_share_lift
+        ,(m.share_cnt - c.ctrl_share_cnt) / c.ctrl_share_cnt AS share_cnt_lift
+        ,(m.is_return_1 - c.ctrl_is_return_1) / c.ctrl_is_return_1 AS is_return_1_lift
+        ,(m.return_n_uv - c.ctrl_return_n_uv) / c.ctrl_return_n_uv AS return_n_uv_lift
+        ,(m.viewh24 - c.ctrl_viewh24) / c.ctrl_viewh24 AS viewh24_lift
+        ,(m.return_n_uv_noself - c.ctrl_return_n_uv_noself) / c.ctrl_return_n_uv_noself AS return_n_uv_noself_lift
+FROM    t_metrics m
+LEFT JOIN t_control c
+ON      m.dt = c.dt
+AND     m.hh = c.hh
+AND     m.apptype = c.apptype
+AND     m.page = c.page
+ORDER BY m.dt DESC, m.hh, m.apptype, m.page, m.abcode
+;

+ 6 - 0
tasks/00_AB效果/02_推荐AB天级效果_对比对照组.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "JWT28U",
+  "sort": "dt:desc",
+  "cols": null
+}

+ 139 - 0
tasks/00_AB效果/02_推荐AB天级效果_对比对照组.sql

@@ -0,0 +1,139 @@
+-- 推荐AB天级效果 - 含对照组对比
+-- 新增列:各指标相对对照组的变化率(lift)
+WITH t_base AS
+(
+    SELECT  dt
+            ,apptype
+            ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
+                    WHEN apptype IN ("4") AND abcode IN ("ab6","ab7") THEN "实验组-str+校准&ros-统计量"
+                    WHEN apptype IN ("4") AND abcode IN ("ab8","ab9") THEN "实验组-str+校准&ros损失函数优化"
+                    WHEN apptype IN ("4") AND abcode IN ("ab4","ab5") THEN "实验组-str+校准&ros天级更新"
+                    WHEN apptype IN ("4") AND abcode IN ("ab2","ab3") THEN "对照组"
+                    ELSE "其他"
+            END AS abcode
+            ,CASE   WHEN page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页") THEN "推荐"
+                    WHEN page IN ("回流页","其他") THEN "非推荐"
+                    ELSE "其他"
+            END AS page
+            ,mid
+            ,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
+    FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
+    WHERE   dt = '${dt}'
+    AND     apptype IN ("4")
+    AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页","回流页","其他")
+    AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
+    AND     abcode NOT IN ("ab100")
+),
+-- 计算各组基础指标
+t_metrics AS (
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,page
+            ,COUNT(1) / COUNT(DISTINCT mid) AS exp_per_dau
+            ,SUM(is_share) / COUNT(1) AS str_one
+            ,SUM(return_n_uv) / SUM(is_share) AS ros_one
+            ,SUM(share_cnt) / COUNT(1) AS str
+            ,SUM(return_n_uv) / SUM(share_cnt) AS ros
+            ,SUM(is_return_1) / COUNT(1) AS str_plus
+            ,SUM(return_n_uv) / SUM(is_return_1) AS ros_minus
+            ,SUM(return_n_uv) / COUNT(1) AS rovn
+            ,SUM(new_exposure_cnt) / COUNT(1) AS vovh24
+            ,COUNT(DISTINCT mid) AS dau
+            ,COUNT(1) AS exp
+            ,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
+    FROM    t_base
+    WHERE   page IN ("推荐")
+    GROUP BY dt
+             ,apptype
+             ,abcode
+             ,page
+),
+-- 获取对照组数据
+t_control AS (
+    SELECT  dt
+            ,apptype
+            ,page
+            ,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
+            ,str_plus AS ctrl_str_plus
+            ,ros_minus AS ctrl_ros_minus
+            ,rovn AS ctrl_rovn
+            ,vovh24 AS ctrl_vovh24
+            ,dau AS ctrl_dau
+            ,exp AS ctrl_exp
+            ,is_share AS ctrl_is_share
+            ,share_cnt AS ctrl_share_cnt
+            ,is_return_1 AS ctrl_is_return_1
+            ,return_n_uv AS ctrl_return_n_uv
+            ,viewh24 AS ctrl_viewh24
+            ,return_n_uv_noself AS ctrl_return_n_uv_noself
+    FROM    t_metrics
+    WHERE   abcode = "对照组"
+)
+-- 关联对照组,计算变化率
+SELECT  m.dt
+        ,m.apptype
+        ,m.abcode
+        ,m.page
+        -- 原始指标
+        ,m.exp_per_dau
+        ,m.str_one
+        ,m.ros_one
+        ,m.str
+        ,m.ros
+        ,m.str_plus
+        ,m.ros_minus
+        ,m.rovn
+        ,m.vovh24
+        ,m.dau
+        ,m.exp
+        ,m.is_share
+        ,m.share_cnt
+        ,m.is_return_1
+        ,m.return_n_uv
+        ,m.viewh24
+        ,m.return_n_uv_noself
+        -- 相对对照组变化率
+        ,(m.exp_per_dau - c.ctrl_exp_per_dau) / c.ctrl_exp_per_dau AS exp_per_dau_lift
+        ,(m.str_one - c.ctrl_str_one) / c.ctrl_str_one AS str_one_lift
+        ,(m.ros_one - c.ctrl_ros_one) / c.ctrl_ros_one AS ros_one_lift
+        ,(m.str - c.ctrl_str) / c.ctrl_str AS str_lift
+        ,(m.ros - c.ctrl_ros) / c.ctrl_ros AS ros_lift
+        ,(m.str_plus - c.ctrl_str_plus) / c.ctrl_str_plus AS str_plus_lift
+        ,(m.ros_minus - c.ctrl_ros_minus) / c.ctrl_ros_minus AS ros_minus_lift
+        ,(m.rovn - c.ctrl_rovn) / c.ctrl_rovn AS rovn_lift
+        ,(m.vovh24 - c.ctrl_vovh24) / c.ctrl_vovh24 AS vovh24_lift
+        ,(m.dau - c.ctrl_dau) / c.ctrl_dau AS dau_lift
+        ,(m.exp - c.ctrl_exp) / c.ctrl_exp AS exp_lift
+        ,(m.is_share - c.ctrl_is_share) / c.ctrl_is_share AS is_share_lift
+        ,(m.share_cnt - c.ctrl_share_cnt) / c.ctrl_share_cnt AS share_cnt_lift
+        ,(m.is_return_1 - c.ctrl_is_return_1) / c.ctrl_is_return_1 AS is_return_1_lift
+        ,(m.return_n_uv - c.ctrl_return_n_uv) / c.ctrl_return_n_uv AS return_n_uv_lift
+        ,(m.viewh24 - c.ctrl_viewh24) / c.ctrl_viewh24 AS viewh24_lift
+        ,(m.return_n_uv_noself - c.ctrl_return_n_uv_noself) / c.ctrl_return_n_uv_noself AS return_n_uv_noself_lift
+FROM    t_metrics m
+LEFT JOIN t_control c
+ON      m.dt = c.dt
+AND     m.apptype = c.apptype
+AND     m.page = c.page
+ORDER BY m.dt DESC, m.apptype, m.page, m.abcode
+;

+ 6 - 0
tasks/00_AB效果/02_推荐AB天级效果_对比对照组_分小时.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "fiw6Fz",
+  "sort": "dt:desc",
+  "cols": null
+}

+ 6 - 0
tasks/00_AB效果/03_推荐AB天级效果_对比对照组_分小时.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "fiw6Fz",
+  "sort": "dt:desc,hh:desc",
+  "cols": null
+}

+ 145 - 0
tasks/00_AB效果/03_推荐AB天级效果_对比对照组_分小时.sql

@@ -0,0 +1,145 @@
+-- 推荐AB天级效果 - 含对照组对比(分小时)
+-- 新增维度:hh(小时),各指标相对对照组的变化率(lift)
+WITH t_base AS
+(
+    SELECT  dt
+            ,hh
+            ,apptype
+            ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
+                    WHEN apptype IN ("4") AND abcode IN ("ab6","ab7") THEN "实验组-str+校准&ros-统计量"
+                    WHEN apptype IN ("4") AND abcode IN ("ab8","ab9") THEN "实验组-str+校准&ros损失函数优化"
+                    WHEN apptype IN ("4") AND abcode IN ("ab4","ab5") THEN "实验组-str+校准&ros天级更新"
+                    WHEN apptype IN ("4") AND abcode IN ("ab2","ab3") THEN "对照组"
+                    ELSE "其他"
+            END AS abcode
+            ,CASE   WHEN page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页") THEN "推荐"
+                    WHEN page IN ("回流页","其他") THEN "非推荐"
+                    ELSE "其他"
+            END AS page
+            ,mid
+            ,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
+    FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
+    WHERE   dt = '${dt}'
+    AND     apptype IN ("4")
+    AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页","回流页","其他")
+    AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
+    AND     abcode NOT IN ("ab100")
+),
+-- 计算各组基础指标(按小时)
+t_metrics AS (
+    SELECT  dt
+            ,hh
+            ,apptype
+            ,abcode
+            ,page
+            ,COUNT(1) / COUNT(DISTINCT mid) AS exp_per_dau
+            ,SUM(is_share) / COUNT(1) AS str_one
+            ,SUM(return_n_uv) / SUM(is_share) AS ros_one
+            ,SUM(share_cnt) / COUNT(1) AS str
+            ,SUM(return_n_uv) / SUM(share_cnt) AS ros
+            ,SUM(is_return_1) / COUNT(1) AS str_plus
+            ,SUM(return_n_uv) / SUM(is_return_1) AS ros_minus
+            ,SUM(return_n_uv) / COUNT(1) AS rovn
+            ,SUM(new_exposure_cnt) / COUNT(1) AS vovh24
+            ,COUNT(DISTINCT mid) AS dau
+            ,COUNT(1) AS exp
+            ,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
+    FROM    t_base
+    WHERE   page IN ("推荐")
+    GROUP BY dt
+             ,hh
+             ,apptype
+             ,abcode
+             ,page
+),
+-- 获取对照组数据(按小时)
+t_control AS (
+    SELECT  dt
+            ,hh
+            ,apptype
+            ,page
+            ,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
+            ,str_plus AS ctrl_str_plus
+            ,ros_minus AS ctrl_ros_minus
+            ,rovn AS ctrl_rovn
+            ,vovh24 AS ctrl_vovh24
+            ,dau AS ctrl_dau
+            ,exp AS ctrl_exp
+            ,is_share AS ctrl_is_share
+            ,share_cnt AS ctrl_share_cnt
+            ,is_return_1 AS ctrl_is_return_1
+            ,return_n_uv AS ctrl_return_n_uv
+            ,viewh24 AS ctrl_viewh24
+            ,return_n_uv_noself AS ctrl_return_n_uv_noself
+    FROM    t_metrics
+    WHERE   abcode = "对照组"
+)
+-- 关联对照组,计算变化率
+SELECT  m.dt
+        ,m.hh
+        ,m.apptype
+        ,m.abcode
+        ,m.page
+        -- 原始指标
+        ,m.exp_per_dau
+        ,m.str_one
+        ,m.ros_one
+        ,m.str
+        ,m.ros
+        ,m.str_plus
+        ,m.ros_minus
+        ,m.rovn
+        ,m.vovh24
+        ,m.dau
+        ,m.exp
+        ,m.is_share
+        ,m.share_cnt
+        ,m.is_return_1
+        ,m.return_n_uv
+        ,m.viewh24
+        ,m.return_n_uv_noself
+        -- 相对对照组变化率
+        ,(m.exp_per_dau - c.ctrl_exp_per_dau) / c.ctrl_exp_per_dau AS exp_per_dau_lift
+        ,(m.str_one - c.ctrl_str_one) / c.ctrl_str_one AS str_one_lift
+        ,(m.ros_one - c.ctrl_ros_one) / c.ctrl_ros_one AS ros_one_lift
+        ,(m.str - c.ctrl_str) / c.ctrl_str AS str_lift
+        ,(m.ros - c.ctrl_ros) / c.ctrl_ros AS ros_lift
+        ,(m.str_plus - c.ctrl_str_plus) / c.ctrl_str_plus AS str_plus_lift
+        ,(m.ros_minus - c.ctrl_ros_minus) / c.ctrl_ros_minus AS ros_minus_lift
+        ,(m.rovn - c.ctrl_rovn) / c.ctrl_rovn AS rovn_lift
+        ,(m.vovh24 - c.ctrl_vovh24) / c.ctrl_vovh24 AS vovh24_lift
+        ,(m.dau - c.ctrl_dau) / c.ctrl_dau AS dau_lift
+        ,(m.exp - c.ctrl_exp) / c.ctrl_exp AS exp_lift
+        ,(m.is_share - c.ctrl_is_share) / c.ctrl_is_share AS is_share_lift
+        ,(m.share_cnt - c.ctrl_share_cnt) / c.ctrl_share_cnt AS share_cnt_lift
+        ,(m.is_return_1 - c.ctrl_is_return_1) / c.ctrl_is_return_1 AS is_return_1_lift
+        ,(m.return_n_uv - c.ctrl_return_n_uv) / c.ctrl_return_n_uv AS return_n_uv_lift
+        ,(m.viewh24 - c.ctrl_viewh24) / c.ctrl_viewh24 AS viewh24_lift
+        ,(m.return_n_uv_noself - c.ctrl_return_n_uv_noself) / c.ctrl_return_n_uv_noself AS return_n_uv_noself_lift
+FROM    t_metrics m
+LEFT JOIN t_control c
+ON      m.dt = c.dt
+AND     m.hh = c.hh
+AND     m.apptype = c.apptype
+AND     m.page = c.page
+ORDER BY m.dt DESC, m.hh, m.apptype, m.page, m.abcode
+;

+ 6 - 0
tasks/00_AB效果/04_推荐AB天级效果_对比对照组_分seq.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "IXIx4D",
+  "sort": "dt:desc,exp:desc",
+  "cols": null
+}

+ 145 - 0
tasks/00_AB效果/04_推荐AB天级效果_对比对照组_分seq.sql

@@ -0,0 +1,145 @@
+-- 推荐AB天级效果 - 含对照组对比(分sequence)
+-- 新增维度:seq(曝光序号),各指标相对对照组的变化率(lift)
+WITH t_base AS
+(
+    SELECT  dt
+            ,COALESCE(CAST(LEAST(CAST(GET_JSON_OBJECT(extend, '$.extParams.sequence') AS BIGINT), 20) AS STRING), "unknown") AS seq
+            ,apptype
+            ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
+                    WHEN apptype IN ("4") AND abcode IN ("ab6","ab7") THEN "实验组-str+校准&ros-统计量"
+                    WHEN apptype IN ("4") AND abcode IN ("ab8","ab9") THEN "实验组-str+校准&ros损失函数优化"
+                    WHEN apptype IN ("4") AND abcode IN ("ab4","ab5") THEN "实验组-str+校准&ros天级更新"
+                    WHEN apptype IN ("4") AND abcode IN ("ab2","ab3") THEN "对照组"
+                    ELSE "其他"
+            END AS abcode
+            ,CASE   WHEN page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页") THEN "推荐"
+                    WHEN page IN ("回流页","其他") THEN "非推荐"
+                    ELSE "其他"
+            END AS page
+            ,mid
+            ,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
+    FROM    loghubods.dwd_recsys_alg_exposure_base_20250108
+    WHERE   dt = '${dt}'
+    AND     apptype IN ("4")
+    AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页","回流页","其他")
+    AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
+    AND     abcode NOT IN ("ab100")
+),
+-- 计算各组基础指标(按sequence)
+t_metrics AS (
+    SELECT  dt
+            ,seq
+            ,apptype
+            ,abcode
+            ,page
+            ,COUNT(1) / COUNT(DISTINCT mid) AS exp_per_dau
+            ,SUM(is_share) / COUNT(1) AS str_one
+            ,SUM(return_n_uv) / SUM(is_share) AS ros_one
+            ,SUM(share_cnt) / COUNT(1) AS str
+            ,SUM(return_n_uv) / SUM(share_cnt) AS ros
+            ,SUM(is_return_1) / COUNT(1) AS str_plus
+            ,SUM(return_n_uv) / SUM(is_return_1) AS ros_minus
+            ,SUM(return_n_uv) / COUNT(1) AS rovn
+            ,SUM(new_exposure_cnt) / COUNT(1) AS vovh24
+            ,COUNT(DISTINCT mid) AS dau
+            ,COUNT(1) AS exp
+            ,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
+    FROM    t_base
+    WHERE   page IN ("推荐")
+    GROUP BY dt
+             ,seq
+             ,apptype
+             ,abcode
+             ,page
+),
+-- 获取对照组数据(按sequence)
+t_control AS (
+    SELECT  dt
+            ,seq
+            ,apptype
+            ,page
+            ,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
+            ,str_plus AS ctrl_str_plus
+            ,ros_minus AS ctrl_ros_minus
+            ,rovn AS ctrl_rovn
+            ,vovh24 AS ctrl_vovh24
+            ,dau AS ctrl_dau
+            ,exp AS ctrl_exp
+            ,is_share AS ctrl_is_share
+            ,share_cnt AS ctrl_share_cnt
+            ,is_return_1 AS ctrl_is_return_1
+            ,return_n_uv AS ctrl_return_n_uv
+            ,viewh24 AS ctrl_viewh24
+            ,return_n_uv_noself AS ctrl_return_n_uv_noself
+    FROM    t_metrics
+    WHERE   abcode = "对照组"
+)
+-- 关联对照组,计算变化率
+SELECT  m.dt
+        ,m.seq
+        ,m.apptype
+        ,m.abcode
+        ,m.page
+        -- 原始指标
+        ,m.exp_per_dau
+        ,m.str_one
+        ,m.ros_one
+        ,m.str
+        ,m.ros
+        ,m.str_plus
+        ,m.ros_minus
+        ,m.rovn
+        ,m.vovh24
+        ,m.dau
+        ,m.exp
+        ,m.is_share
+        ,m.share_cnt
+        ,m.is_return_1
+        ,m.return_n_uv
+        ,m.viewh24
+        ,m.return_n_uv_noself
+        -- 相对对照组变化率
+        ,(m.exp_per_dau - c.ctrl_exp_per_dau) / c.ctrl_exp_per_dau AS exp_per_dau_lift
+        ,(m.str_one - c.ctrl_str_one) / c.ctrl_str_one AS str_one_lift
+        ,(m.ros_one - c.ctrl_ros_one) / c.ctrl_ros_one AS ros_one_lift
+        ,(m.str - c.ctrl_str) / c.ctrl_str AS str_lift
+        ,(m.ros - c.ctrl_ros) / c.ctrl_ros AS ros_lift
+        ,(m.str_plus - c.ctrl_str_plus) / c.ctrl_str_plus AS str_plus_lift
+        ,(m.ros_minus - c.ctrl_ros_minus) / c.ctrl_ros_minus AS ros_minus_lift
+        ,(m.rovn - c.ctrl_rovn) / c.ctrl_rovn AS rovn_lift
+        ,(m.vovh24 - c.ctrl_vovh24) / c.ctrl_vovh24 AS vovh24_lift
+        ,(m.dau - c.ctrl_dau) / c.ctrl_dau AS dau_lift
+        ,(m.exp - c.ctrl_exp) / c.ctrl_exp AS exp_lift
+        ,(m.is_share - c.ctrl_is_share) / c.ctrl_is_share AS is_share_lift
+        ,(m.share_cnt - c.ctrl_share_cnt) / c.ctrl_share_cnt AS share_cnt_lift
+        ,(m.is_return_1 - c.ctrl_is_return_1) / c.ctrl_is_return_1 AS is_return_1_lift
+        ,(m.return_n_uv - c.ctrl_return_n_uv) / c.ctrl_return_n_uv AS return_n_uv_lift
+        ,(m.viewh24 - c.ctrl_viewh24) / c.ctrl_viewh24 AS viewh24_lift
+        ,(m.return_n_uv_noself - c.ctrl_return_n_uv_noself) / c.ctrl_return_n_uv_noself AS return_n_uv_noself_lift
+FROM    t_metrics m
+LEFT JOIN t_control c
+ON      m.dt = c.dt
+AND     m.seq = c.seq
+AND     m.apptype = c.apptype
+AND     m.page = c.page
+ORDER BY m.dt DESC, m.seq, m.apptype, m.page, m.abcode
+;

+ 6 - 0
tasks/00_AB效果/05_推荐AB天级效果_对比对照组_含多跳.json

@@ -0,0 +1,6 @@
+{
+  "token": "ONZqsxB9BhGH8tt90EScSJT5nHh",
+  "sheet_id": "6vAr7l",
+  "sort": "dt:desc",
+  "cols": null
+}

+ 163 - 0
tasks/00_AB效果/05_推荐AB天级效果_对比对照组_含多跳.sql

@@ -0,0 +1,163 @@
+-- 推荐AB天级效果 - 含对照组对比 + 多跳B/C指标
+-- 基于新表 dwd_recsys_alg_exposure_base_20260206,新增 b/c_1/c_2/c_3/total_bc per-exposure 率指标
+WITH t_base AS
+(
+    SELECT  dt
+            ,apptype
+            ,CASE   WHEN apptype IN ("4") AND abcode IN ("ab0","ab1") THEN "实验组-先验地域降权"
+                    WHEN apptype IN ("4") AND abcode IN ("ab6","ab7") THEN "实验组-str+校准&ros-统计量"
+                    WHEN apptype IN ("4") AND abcode IN ("ab8","ab9") THEN "实验组-str+校准&ros损失函数优化"
+                    WHEN apptype IN ("4") AND abcode IN ("ab4","ab5") THEN "实验组-str+校准&ros天级更新"
+                    WHEN apptype IN ("4") AND abcode IN ("ab2","ab3") THEN "对照组"
+                    ELSE "其他"
+            END AS abcode
+            ,CASE   WHEN page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页") THEN "推荐"
+                    WHEN page IN ("回流页","其他") THEN "非推荐"
+                    ELSE "其他"
+            END AS page
+            ,mid
+            ,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
+            ,COALESCE(CAST(b AS BIGINT), 0) AS b
+            ,COALESCE(CAST(c_1 AS BIGINT), 0) AS c_1
+            ,COALESCE(CAST(c_2 AS BIGINT), 0) AS c_2
+            ,COALESCE(CAST(c_3 AS BIGINT), 0) AS c_3
+    FROM    loghubods.dwd_recsys_alg_exposure_base_20260206
+    WHERE   dt = '${dt}'
+    AND     apptype IN ("4")
+    AND     page IN ("回流后沉浸页&内页feed","详情后沉浸页","首页feed","详情页","回流页","其他")
+    AND     abcode IN ("ab0","ab1","ab2","ab3","ab4","ab5","ab6","ab7","ab8","ab9")
+    AND     abcode NOT IN ("ab100")
+),
+-- 计算各组基础指标
+t_metrics AS (
+    SELECT  dt
+            ,apptype
+            ,abcode
+            ,page
+            ,COUNT(1) / COUNT(DISTINCT mid) AS exp_per_dau
+            ,SUM(is_share) / COUNT(1) AS str_one
+            ,SUM(return_n_uv) / SUM(is_share) AS ros_one
+            ,SUM(share_cnt) / COUNT(1) AS str
+            ,SUM(return_n_uv) / SUM(share_cnt) AS ros
+            ,SUM(is_return_1) / COUNT(1) AS str_plus
+            ,SUM(return_n_uv) / SUM(is_return_1) AS ros_minus
+            ,SUM(return_n_uv) / COUNT(1) AS rovn
+            ,SUM(new_exposure_cnt) / COUNT(1) AS vovh24
+            ,COUNT(DISTINCT mid) AS dau
+            ,COUNT(1) AS exp
+            ,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
+            ,SUM(b) / COUNT(1) AS b
+            ,SUM(c_1) / COUNT(1) AS c_1
+            ,SUM(c_2) / COUNT(1) AS c_2
+            ,SUM(c_3) / COUNT(1) AS c_3
+            ,SUM(b + c_1 + c_2 + c_3) / COUNT(1) AS total_bc
+    FROM    t_base
+    WHERE   page IN ("推荐")
+    GROUP BY dt
+             ,apptype
+             ,abcode
+             ,page
+),
+-- 获取对照组数据
+t_control AS (
+    SELECT  dt
+            ,apptype
+            ,page
+            ,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
+            ,str_plus AS ctrl_str_plus
+            ,ros_minus AS ctrl_ros_minus
+            ,rovn AS ctrl_rovn
+            ,vovh24 AS ctrl_vovh24
+            ,dau AS ctrl_dau
+            ,exp AS ctrl_exp
+            ,is_share AS ctrl_is_share
+            ,share_cnt AS ctrl_share_cnt
+            ,is_return_1 AS ctrl_is_return_1
+            ,return_n_uv AS ctrl_return_n_uv
+            ,viewh24 AS ctrl_viewh24
+            ,return_n_uv_noself AS ctrl_return_n_uv_noself
+            ,b AS ctrl_b
+            ,c_1 AS ctrl_c_1
+            ,c_2 AS ctrl_c_2
+            ,c_3 AS ctrl_c_3
+            ,total_bc AS ctrl_total_bc
+    FROM    t_metrics
+    WHERE   abcode = "对照组"
+)
+-- 关联对照组,计算变化率
+SELECT  m.dt
+        ,m.apptype
+        ,m.abcode
+        ,m.page
+        -- 原始指标
+        ,m.exp_per_dau
+        ,m.str_one
+        ,m.ros_one
+        ,m.str
+        ,m.ros
+        ,m.str_plus
+        ,m.ros_minus
+        ,m.rovn
+        ,m.vovh24
+        ,m.dau
+        ,m.exp
+        ,m.is_share
+        ,m.share_cnt
+        ,m.is_return_1
+        ,m.return_n_uv
+        ,m.viewh24
+        ,m.return_n_uv_noself
+        ,m.b
+        ,m.c_1
+        ,m.c_2
+        ,m.c_3
+        ,m.total_bc
+        -- 相对对照组变化率
+        ,(m.exp_per_dau - c.ctrl_exp_per_dau) / c.ctrl_exp_per_dau AS exp_per_dau_lift
+        ,(m.str_one - c.ctrl_str_one) / c.ctrl_str_one AS str_one_lift
+        ,(m.ros_one - c.ctrl_ros_one) / c.ctrl_ros_one AS ros_one_lift
+        ,(m.str - c.ctrl_str) / c.ctrl_str AS str_lift
+        ,(m.ros - c.ctrl_ros) / c.ctrl_ros AS ros_lift
+        ,(m.str_plus - c.ctrl_str_plus) / c.ctrl_str_plus AS str_plus_lift
+        ,(m.ros_minus - c.ctrl_ros_minus) / c.ctrl_ros_minus AS ros_minus_lift
+        ,(m.rovn - c.ctrl_rovn) / c.ctrl_rovn AS rovn_lift
+        ,(m.vovh24 - c.ctrl_vovh24) / c.ctrl_vovh24 AS vovh24_lift
+        ,(m.dau - c.ctrl_dau) / c.ctrl_dau AS dau_lift
+        ,(m.exp - c.ctrl_exp) / c.ctrl_exp AS exp_lift
+        ,(m.is_share - c.ctrl_is_share) / c.ctrl_is_share AS is_share_lift
+        ,(m.share_cnt - c.ctrl_share_cnt) / c.ctrl_share_cnt AS share_cnt_lift
+        ,(m.is_return_1 - c.ctrl_is_return_1) / c.ctrl_is_return_1 AS is_return_1_lift
+        ,(m.return_n_uv - c.ctrl_return_n_uv) / c.ctrl_return_n_uv AS return_n_uv_lift
+        ,(m.viewh24 - c.ctrl_viewh24) / c.ctrl_viewh24 AS viewh24_lift
+        ,(m.return_n_uv_noself - c.ctrl_return_n_uv_noself) / c.ctrl_return_n_uv_noself AS return_n_uv_noself_lift
+        ,(m.b - c.ctrl_b) / c.ctrl_b AS b_lift
+        ,(m.c_1 - c.ctrl_c_1) / c.ctrl_c_1 AS c_1_lift
+        ,(m.c_2 - c.ctrl_c_2) / c.ctrl_c_2 AS c_2_lift
+        ,(m.c_3 - c.ctrl_c_3) / c.ctrl_c_3 AS c_3_lift
+        ,(m.total_bc - c.ctrl_total_bc) / c.ctrl_total_bc AS total_bc_lift
+FROM    t_metrics m
+LEFT JOIN t_control c
+ON      m.dt = c.dt
+AND     m.apptype = c.apptype
+AND     m.page = c.page
+ORDER BY m.dt DESC, m.apptype, m.page, m.abcode
+;