合约广告(一):排期系统

在投放方式上,合约广告与竞价广告相比,一大特点就是合约广告需要排期。竞价广告是不需要排期的,因为同一时间内可以投放任意多个竞价广告, 价高者得,媒体没给广告主任何曝光数量的承诺。 但是合约广告就不同了,媒体和广告主是有曝光时间或者曝光数量的约定的,达不成这个约定,媒体是要进行补偿的。对于合约CPD来说,其实很简单, 因为广告主包的是时间段,排期时只需要考虑这个时间段上有没有其他合约广告即可。如果没有,那就可以投放。合约CPM广告就复杂得多了, 因为这涉及到对某个广告位未来一段时间内的流量预测。下面分别讨论下,CPD和合约CPM如何进行排期。

CPD排期

CPD要占用目标人群在投放时间段内的所有曝光流量,因此投放时,要查询目标人群在投放时间段内,有没有被占用过。CPD排期相对简单的原因就在于, 它只关心库存有没有被占用,而不关心库存到底有多少、要占用多少。下面给出一个CPD排期的方案:

假设要进行投放的目标人群是[geo(北京 || 上海) && sex(男) && position(101 || 102)],即101或102广告位、北京或上海的所有男性流量。
投放日期是2021-01-01 至 2021-01-10,具体的排期流程如下:
1. 将目标人群和投放日期进行笛卡尔积,得到最小粒度的资源,以2021-01-01为例:
    1. geo(北京) && sex(男) && position(101) && 2021-01-01
    2. geo(上海) && sex(男) && position(101) && 2021-01-01
    2. geo(北京) && sex(男) && position(102) && 2021-01-01
    3. geo(上海) && sex(男) && position(102) && 2021-01-01
2. 数据库中查询步骤一中得到的所有最小粒度的资源,判断是否有记录,如果有,则是已经被其他广告占用,否则就是没被占用。
3. 对于可以占用的资源,在数据库中写入对应的资源条件

上面给出了一个CPD排期的最简单方案,基于MySQL就可以实现。但由于该方案排期过程中出现了笛卡尔积,所以要求定向条件的维度数量和值的数量, 必须加以限制,否则会出现维度爆炸。

合约CPM排期

合约CPM排期时,需要指定占用目标人群在投放时间段内的流量数量,因此排期系统要知道,目标人群在投放时间段内的库存总量。库存的查询和占用, 有两种方式:

基于曝光日志

广告检索过程是给定一条流量,查询符合这条流量的广告。而基于曝光日志的库存查询,跟广告检索刚好是反过来的,它是给定一个广告, 查询符合这条广告定向条件的所有流量。查询排期的做法很简单,就是查曝光日志即可。占用排期相对麻烦一点,因为占用排期相当于是占用了一条日志。 曝光日志一般都是存在OLAP数据库中的,对update、delete这种操作支持的不是很好。所以一般的做法时,新建一张排期表,存储占用的曝光日志的request id, 这样查询排期的时候,过滤掉已被占用的曝光日志即可;占用排期时,也只需要往排期表中插入数据,不再需要update或delete操作了。

基于流量正交

对曝光日志提前按维度进行聚合。算出每个维度的每个值的曝光量占总曝光量的比值。如,对于地区维度,北京的曝光量占总曝光量的比值5%、上海占7%; 对于性别维度,男性占53%、女性占47%。那么当需要预估北京男性的曝光数量时,我们就可以推算出具体的数量: 总曝光量 * 北京占比 * 男性占比 = 总曝光量 * 5% * 53% = 总曝光量 * 2.65%。这种方式的问题在于,实际上流量不是完全正交的,即男性 在总占比上可能是53%,但在北京人中,男性流量可能不是53%,这会造成流量偏差,并且定向维度越多,偏差越大。这种方式的优点就在于,库存 查询非常简单,并且库存预定时,不需要针对每条流量进行操作,而是直接在某个维度值的流量占比上进行扣除就行了。

上面介绍了库存的查询和占用,但是还有一个问题,不管是上面哪种方法,查询的库存都是历史数据,而我们合约CPM广告投放占用的是未来的库存, 历史库存显然是不能直接当做未来库存的,因此一般的做法是,查询完成历史库存后,再乘以一个系数,得到未来的库存。这个系数一般是算法提供的, 在这里我就不展开讨论了。