在穿山甲,我们需要在很短(100ms级别)的时间里从千万级的广告中选择出(我们认为)最合适的广告,因此在每个环节都需要对性能进行充分的优化。这篇我们讲讲其中一个环节。
- 定向 -
广告系统的一个关键环节是定向(targeting)。
比如某个广告主可能只想把自己的广告投放给北京的男性用户,在创建广告时需要在广告平台上选择相应的定向条件:
巨量引擎创建广告计划[1]
当广告系统收到一个流量请求时,会根据流量的标签(包括但不限于地域、性别、年龄等),将不符合条件的广告过滤掉。
- 基础版 -
当在投广告的总数较少(几百~几千)时,最简单的做法是 O(n) 遍历一遍,实现简单。
以下是简单的示意代码:
def ad_targeting(request, ads):
candidates = []
for ad in ads:
match = True
for field, value in request.tags:
if !ads.match(field, value):
match = False
break
if match:
candidates.append(ad)
return candidates
注:本文代码只为表意,未经过测试(就是当伪代码看)。
但是如果广告数量达到万级以上的规模,O(n) 的实现的延迟就不太能让人接受了。
- 倒排索引 -
对于这种标签化的过滤,一个很简单的思路就是改成用倒排索引。
先根据广告的标签建立倒排:
field_names = ["city", "gender", "age"]
def build_inverted_index(ads):
index = {} # field -> value -> array_of_ads
for ad in ads:
index["all"][NOT_SPECIFIED].add(ad)
for field in field_names:
value = ad.get_targeting_value(field)
if value is None:
index[field][NOT_SPECIFIED].a