一个游戏广告主早上打开投放后台:昨天那条下载广告花了 11,520 元,带来 150 个激活,一个激活 76.8 元。可昨晚 12 点看的时候,还是 12,000 元、120 个激活、一个 100 元;等到一周后再看,激活又变成了 180 个。

这里有两个问题:这一万多块钱,每一分是怎么扣下来的?同一天的数,为什么会一直变?这篇跟着这条广告走一遍:先看广告主怎么出价,再看平台怎么在一百多毫秒里选出它、给它定价,然后看展示之后钱怎么扣、激活怎么算,最后回到报表。

平台夹在中间:广告主要效果,媒体要收入,用户要体验

广告是广告主借媒体的流量,以较低的成本接触到用户。今天它几乎都发生在互联网上:2025 年全国广告业务收入首次突破 2 万亿元,其中互联网广告发布收入 12518.4 亿元,占各类媒介广告发布收入的 89.1%。

角色

例子

想要什么

广告主

我们的游戏公司,还有电商、品牌、App

同样的钱,换到更多激活

媒体

短视频、资讯、社交 App

流量卖出好价钱,又不伤用户体验

广告平台

负责投放、竞价、计费

撮合得准,平台收入高

用户

刷到广告的人

广告别太烦,最好有点用

三方的诉求并不一致,平台每一次选广告、定价格,都是在三者之间找平衡。大型互联网公司往往自己既有媒体流量、又有投放系统,一家就能完成撮合;在开放市场里,代表广告主的需求方平台(DSP)和代表媒体的供给方平台(SSP)通过广告交易平台(ADX)实时竞价。

交易方式是怎么一步步变成实时竞价的
  1. 按位置的合约:某个广告位在某段时间归某个广告主,按时间付费(CPT),和报纸、电视广告一样;

  2. 按受众的合约:承诺把广告给某类人群看若干次,按展示量结算;

  3. 竞价:广告主不再买固定的量,而是对每一次展示机会出价,价高者得;

  4. 实时竞价(RTB):每次展示时,交易平台向多个需求方实时询价,当场拍卖。

展现形式也在变:从内容旁边的广告位,到和内容融为一体的原生广告,比如信息流里的这一条。

合约广告(灰)按位置、按展示量卖,后来都汇进竞价(蓝):一头走向程序化交易,一头走向和内容融为一体的原生广告(据《计算广告》)
开放市场里,一次展示从媒体到广告主可能要经过好几手,每一手都是一个平台(据《计算广告》简化)

出价从哪来:结算方式决定谁来承担不确定性

一次展示能带来多少价值,可以拆成两个不确定的数:用户会不会点(点击率),点了之后值多少钱(点击价值)。按什么结算,其实是在约定这两个数由谁来估、估错了谁吃亏:

结算方式

按什么付费

点击率谁来估

点击价值谁来估

CPT

时间

广告主

广告主

CPM

千次展示

广告主

广告主

CPC

点击

平台

广告主

CPA / CPS

转化 / 销售额

平台

平台

越往下,广告主的风险越小,平台要估的东西越多。

我们的游戏广告主真正想买的是激活,可平台又不愿意承担「点了不激活」的全部风险。折中是 oCPC 这类优化出价:广告主报一个目标激活成本,平台用模型把它换算成每次点击的出价去竞价,扣费仍按点击。比如目标激活成本 100 元,模型预估点击后的激活率是 2%:

每次点击的出价=100 元×2%=2 元\text{每次点击的出价} = 100 \text{ 元} \times 2\% = 2 \text{ 元}

所以这条广告进场时,手里拿的是「一次点击最多 2 元」。

选谁:按期望收益排,不按出价排

一个用户刷到信息流里的广告位,App 向平台发起请求。平台要在这次请求里走完下面这条路,返回一条广告:

在线这一段只选出一条广告、定好一个价格,还没有扣一分钱

召回先按地域、人群、兴趣筛掉大部分广告;粗排用轻量模型快速初筛,精排再用复杂模型估每条广告的点击率和转化率。到竞价这一步,比的不是谁出价高,而是这次展示期望能收多少钱,用千次展示的期望收入 eCPM 衡量:

eCPM=预估点击率×每次点击的出价×1000\text{eCPM} = \text{预估点击率} \times \text{每次点击的出价} \times 1000

假设这次请求最后剩下三条候选:

广告

计费

出价

预估点击率

eCPM

A:我们的游戏

CPC

2 元 / 点击

1.5%

2 × 1.5% × 1000 = 30 元

B:一家电商

CPC

1 元 / 点击

2.4%

1 × 2.4% × 1000 = 24 元

C:一个品牌

CPM

20 元 / 千次

—

20 元

A 赢了。但它赢在点击率估得高:如果模型把 A 的点击率估成 1%,它的 eCPM 只有 20 元,就会输给出价只有它一半的 B。点击率预估是平台最核心的能力:估高了,平台把展示给了不会被点的广告,白白浪费流量;估低了,好广告排不上来。

在线部分要在很短的时间内完成。程序化交易里,交易平台会在请求里写明最多等多少毫秒(OpenRTB 协议的 tmax 字段,协议示例里是 120 毫秒),超时的出价直接作废。

付多少:赢家只付保住名次的价钱

A 出价 2 元,但它不按 2 元付。常见的广义第二价格(GSP)规则下,赢家只付刚好能保住第一名的价格:要让自己的 eCPM 不低于第二名 B 的 24 元,每次点击只需要

241.5%×1000=1.6 元\frac{24}{1.5\% \times 1000} = 1.6 \text{ 元}

(实际系统还会再加一个最小加价单位,这里略去。)为什么不让赢家按自己的出价付?如果按出价付,广告主会不停地压低出价、试探刚好能赢的价格,价格来回抖动,系统也不稳定。GSP 让多报的部分不用真的付出去,减少了这种试探。不过它并不保证每个人都如实出价,能做到这一点的是 VCG 机制;GSP 的性质,Edelman、Ostrovsky 和 Schwarz 2007 年的论文分析得很清楚。

还要注意,到这里只是定了价:A 按 CPC 计费,用户不点,一分钱都不扣;用户点了,才扣 1.6 元。

平台背后的几类计算问题

问题

要做什么

点击率 / 转化率预估

用机器学习估每条广告被点击、被转化的概率,上面的 eCPM 全靠它

市场机制设计

多方博弈下怎么排序、怎么定价,GSP 就是一种

在线分配

合约广告承诺了展示量,要在满足各种约束的前提下,对每次展示即时决定给谁

受众定向

把广告主自己的数据、用户画像和历史行为加工成可以投放的标签

投放机在线只做检索、排序和收益管理;它用到的标签、特征和模型,由流计算和离线计算从日志里算好放进键值存储(据《计算广告》简化)

展示之后:一次点击要过几道关才扣钱

广告展示出去以后,曝光、点击、激活这些事件陆续回到平台,要经过下面几道关:

一次点击要先过去重和反作弊才扣钱;激活要等广告主回传、归因到点击上,才进报表
  • 去重:网络重试、客户端重复上报,会让同一次点击出现两遍。不去重,广告主就要为同一次点击付两次钱;

  • 反作弊:机器刷量、误点这类无效流量要剔除,剔除的部分不该由广告主付钱;

  • 扣费:从广告主的预算里扣掉 1.6 元。广告主设了日预算,平台还要控制花钱的速度(预算平滑),避免一早就花光、错过晚上更好的流量;同一个用户看同一条广告的次数也有上限(频控);

  • 归因:游戏 App 在用户激活后把激活回传给平台。一个激活前面可能有好几次曝光和点击,要按规则决定功劳归谁,常见的是归给归因窗口内的最后一次点击。

激活往往比点击晚得多:用户点了广告,可能当天下载、第二天才打开。这就埋下了报表会变的伏笔。

报表上的数为什么会变:公式简单,难的是口径

把这条广告一天的数据汇总起来,就是广告主看到的报表。为了好算,假设每次点击都按 1.6 元计费。指标的公式都很简单:

指标

怎么算

我们这条广告(T+1)

展示

—

480,000

点击

—

7,200

消耗

每次点击的计费之和

7,200 × 1.6 = 11,520 元

CTR 点击率

点击 ÷ 展示

1.5%

CPM 千次展示成本

消耗 ÷ 展示 × 1000

24 元

CPC 点击成本

消耗 ÷ 点击

1.6 元

CVR 转化率

激活 ÷ 点击

150 ÷ 7,200 ≈ 2.1%

CPA 激活成本

消耗 ÷ 激活

11,520 ÷ 150 = 76.8 元

难的是:同一天的同一个数,在不同时候看是不一样的。回到开头的三个时间点:

什么时候看

点击

消耗

激活

CPA

T 日 23:59,实时

7,500

12,000 元

120

100 元

T+1,离线

7,200

11,520 元

150

76.8 元

T+7

7,200

11,520 元

180

64 元

  • 实时到离线:实时数据为了快,先按收到的点击出结果;离线重新算一遍,剔除了 4% 的无效点击(7,500 → 7,200),消耗跟着减少;当天晚些时候回传的激活也补齐了(120 → 150);

  • 归因窗口:T+7 时,7 天窗口内陆续回传的激活都算回 T 日的点击上,激活又多了 30 个。窗口如果是 1 天,这 30 个就不算;

  • 时间口径:激活算在点击那天(上表的算法),还是算在激活发生的那天?两种口径下,同一天的 CPA 不一样,跨天汇总时也不能混用;

  • 去重:同一个用户激活了两次,算一个还是两个。

这些口径没有对错,只有约定。我在字节先当数据 BP,直接对接产品,他们只能从业务视角描述需求。刚开始完全不知道怎么找数、怎么加工、数据对不对,只能全靠老同事带,那时得出的结论是:数据的壁垒不在技术,而在业务。上面这张表就是例子:SQL 谁都会写,可不知道产品问的「激活成本」是哪个窗口、哪种时间口径,算出来的数就是错的。

数据 BP 的核心指标叫「0987」,排在第一位的是数据事故为 0:

数据 BP 的核心指标「0987」:排在第一位的是数据事故为 0(据 DataFun 上的字节数据研发分享)

实时这一侧更难。广告的实时场景需要实时关联,又会碰到 Flink SQL 的回撤问题(见 Flink SQL 回撤机制与问题),所以一直用门槛较高的 DataStream API 开发。我最大的体会是:实时开发的一致性保证非常关键。放到这篇的例子里就很直观:一次点击如果在实时链路里被处理了两遍,广告主就多付了 1.6 元。

怎么读一张广告报表

回到开头的两个问题。每一分钱是这样扣下来的:广告主的目标激活成本,被模型换算成每次点击的出价;平台按 eCPM 选出这条广告,按第二名的 eCPM 定价;用户点了,点击过了去重和反作弊,才从预算里扣钱。数字会变,是因为反作弊、延迟回传和归因窗口都要时间,实时和离线、T+1 和 T+7 看到的是同一件事的不同阶段。

这些数最后会回到广告主那里:游戏公司拿激活成本和玩家的 LTV 比,决定还买不买量,见游戏行业。我后来做的数据产品,就是把这样的报表做成接口给产品用,见 SQL2API。

参考资料


全文评论

0

正在加载评论…