一、最外层:最终聚合

SELECT
    t1.event_day, t1.cmatch, t1.trans_type, t1.exp_id,
    sum(eshow),          -- 曝光
    sum(click),          -- 点击
    sum(charge),         -- 实际消费
    sum(convert_num),    -- 转化数
    sum(target_charge)   -- 目标消费(即"该花多少钱")
FROM t1 LEFT JOIN t2
    ON (searchid_decimal = search_id AND ideaid = idea_id)
GROUP BY event_day, cmatch, trans_type, exp_id

核心思路: t1 提供每次曝光的展/点/消,t2 补充对应的转化数和目标消费,按searchid + ideaid一对一关联。

一条请求就是一个searchid(检索 id),一个请求可能带下来很多广告;一个 ideaid(创意 id)就是一个广告。所以searchid + ideaid才能唯一确定一个请求里的唯一广告。

二、t1 展点消主体(每条曝光记录)

SELECT
    event_day, searchid_decimal, ideaid, cmatch,
    -- 实验分组
    CASE WHEN ovl_exp LIKE '%153613-0%' THEN 'exp'
         WHEN ovl_exp LIKE '%153613-dz%' THEN 'dz' END AS exp_id,
    trans_type,
    eshow,               -- 曝光(表里自带字段)
    clk AS click,        -- 点击
    -- 消费计算:区分计价方式
    CASE
        WHEN (bid_type='3' AND pricing_type='1') OR bid_type='2'
            THEN price / 1000 / 100    -- oCPM: price 单位是厘/千次
        ELSE clk * price / 100          -- CPC: 点击 × 单价
    END AS charge
FROM fc_nad.nativeads_feed_asp_view
WHERE event_day BETWEEN '20251114' AND '20251119'
    AND event_type = 'browser'
    AND cmatch = '719'
    AND (ovl_exp LIKE '%153613-0%' OR ovl_exp LIKE '%153613-dz%')

要点:

  • 一行 = 一次曝光事件
  • eshowclk是表自带的字段
  • charge需要根据出价类型自己算

三、t2 转化汇总(四路 UNION ALL)

t2 的作用是:把所有转化来源合到一起,最终按search_id, idea_id聚合出convert_numtarget_charge

第 1 路:常规 oCPX 转化

来源: nativeads_ocpx_charge_hour
产出: convert_num(转化数)+ target_charge(目标消费)
  • 处理了深度转化逻辑:如果is_ocpc_deep=1deep_trans_type不是 28/29,就用深度出价和深度转化数
  • target_charge=ocpc_bid × convert_num / 100
  • 但对trans_type in (14,80-88,90,118)这些特殊类型,target_charge = 0(因为第 3、4 路单独算)

第 2 路:视频播放转化(补充)

来源: nativeads_video_play_conv (ocpx_join_flag = '0')
产出: 同上,convert_num + target_charge
  • ocpx_join_flag = '0' 表示没被第 1 路 join 上的漏网转化
  • 逻辑和第 1 路基本一致,是补数据用的

第 3 路:特殊 trans_type 的 ROI 目标消费

来源: asp_view LEFT JOIN nativeads_ods_ocpc_all_convert
适用: trans_type in (14,78,80-88,90)
产出: convert_num = 0, target_charge = 按ROI逻辑算

关键:convert_num** 硬编码为 0**,因为转化数已经在第 1、2 路算了,这里只补 target_charge

target_charge 逻辑:

  • 非 ROI 出价: ocpc_bid × convert_num / 100
  • ROI 出价: convert_value / bw_idf_ratio(转化价值 / ROI 系数)

第 4 路:trans_type = 118(明投 ROI)

来源: asp_view LEFT JOIN nativeads_feed_ocpc_all_convert
适用: trans_type = 118
产出: convert_num = 0, target_charge = 按明投ROI逻辑算

和第 3 路类似,但:

  • 用的转化表不同(nativeads_feed_ocpc_all_convert
  • ROI 判断逻辑不同(明投2阶段 / 明投1阶段 / 暗投)
  • 明投2阶段: convert_value / movie_troi

四路关系总结

路径贡献 convert_num贡献 target_charge覆盖的 trans_type
第1路✅(常规类型)常规(排除14,80-88,90,118)
第2路✅(常规类型)同上,补漏
第3路❌ (=0)✅(ROI类型)14,78,80-88,90
第4路❌ (=0)✅(明投ROI)118

设计意图: 转化数只算一次(1、2路),目标消费按不同 trans_type 的计价逻辑分路计算,避免重复。对,t1 是展点消,t2 是转化。t2 最终只产出两个值:convert_num(转化数)和 target_charge(目标消费),按 search_id + idea_id 聚合。

下面逐路拆解:


第 1 路:nativeads_ocpx_charge_hour(常规转化)

这是最核心的转化数据源,有两层嵌套:

内层 — 从原始表取数据,做两个 IF 判断:

-- 出价:是深度转化就用深度出价,否则用普通出价
ocpc_bid_2 = IF(is_ocpc_deep=1 AND deep_trans_type NOT IN ('28','29'),
                deep_ocpc_bid, ocpc_bid)
 
-- 转化数:是深度转化就看深度转化类型是否匹配,否则直接用 convert_num
convert_num = IF(is_ocpc_deep=1 AND deep_trans_type NOT IN ('28','29'),
                 IF(convert_num>0 AND array_contains(..., deep_trans_type), convert_num, 0),
                 convert_num)

简单说:如果广告主开了深度转化,就用深度的出价和转化数;否则用普通的。

外层 — 算 target_charge:

target_charge = CASE
    WHEN trans_type IN (14,80-88,90,118) THEN 0        -- 这些类型留给第3、4路算
    ELSE ocpc_bid_2 * convert_num / 100.0              -- 常规:出价 × 转化数
END

第 2 路:nativeads_video_play_conv(视频转化补漏)

逻辑和第 1 路几乎一样,区别:

  • 数据源不同(视频播放转化表)
  • 多了 ocpx_join_flag = '0' 过滤 — 意思是”没被第 1 路的 ocpx 表 join 上的记录
  • 先做了一次 GROUP BY search_id, idea_id, event_day 去重(用 MAX 取各字段)
  • convert_type_list 的分隔符是 # 而不是第 1 路的 \002

本质:第 1 路漏掉的转化,从这个表补上。


第 3 路:ROI 出价的目标消费(trans_type = 14,78,80-88,90)

结构是 asp_view(t21)LEFT JOIN 转化表(t22)

t21(左表)— 从 asp_view 取曝光记录,并判断是否 ROI 出价:

roi_tag = CASE
    WHEN pla_rank=1 AND bw_idf_ratio>0 THEN 'ROI出价'
    ELSE '非ROI出价'
END

t22(右表)— 从 nativeads_ods_ocpc_all_convert 取转化价值:

-- convert_num: trans_type 和 convert_type 匹配就算 1 次转化
-- convert_value: 从 convert_value_time 数组里炸开,取金额部分

合并后算 target_charge:

target_charge = CASE
    WHEN 非ROI出价 THEN ocpc_bid * convert_num / 100    -- 普通算法
    WHEN ROI出价   THEN convert_value / bw_idf_ratio     -- 转化价值 / ROI系数
END

convert_num** 写死 = 0**,因为转化次数已经在第 1、2 路算过了,这里只补目标消费。


第 4 路:明投 ROI 的目标消费(trans_type = 118)

和第 3 路结构完全一样,区别:

第 3 路第 4 路
trans_type14,78,80-88,90118
转化表nativeads_ods_ocpc_all_convertnativeads_feed_ocpc_all_convert
ROI 判断pla_rank + bw_idf_ratiois_movie_roi_second_stage 等字段
ROI 算法convert_value / bw_idf_ratioconvert_value / movie_troi

四路汇总

最后所有路 UNION ALL 到一起,外面套一层:

SELECT search_id, idea_id,
    SUM(convert_num) AS convert_num,       -- 只有 1、2 路贡献
    SUM(target_charge) AS target_charge    -- 四路都贡献
FROM (第1路 UNION ALL 第2路 UNION ALL 第3路 UNION ALL 第4路)
GROUP BY search_id, idea_id

然后通过 LEFT JOIN 关联回 t1,就把转化数据挂到每条展点消记录上了。

这样清楚了吗?

更新: 2026-03-22 21:00:57
原文: https://www.yuque.com/dongpozhouzi-mshe3/zhm85g/lkqvuy8v1ofzq89w


相关笔记