26 | 在线测试:如何在推荐服务器内部实现A/B测试?
A/B 测试的“分桶”和“分层”原则
在A/B测试中,分桶和分层是非常重要的原则。分桶是将用户随机分配到不同的实验组中,而分层则是将不同类型的实验分组在不同的层中。层与层之间的流量“正交”,同层之间的流量“互斥”。
为了实现分层,我们需要注意样本的独立性和分桶过程的无偏性。我们需要使用一些复杂的哈希函数来确保用户的 ID 随机地映射到不同的桶中,并且每个用户只能被分配到一个层中。此外,我们还需要保证层与层之间的流量“正交”,同层之间的流量“互斥”,这样才能确保不同类型的实验分组在不同的层中,从而实现分层的效果。
如果同层之间进行多组 A/B 测试,不同测试之间的流量不可以重叠,这是第一个“互斥”;一组 A/B 测试中实验组和对照组的流量是不重叠的,这是第二个“互斥”。在基于用户的 A/B 测试中,“互斥”的含义可以被进一步解读为,不同实验之间以及 A/B 测试的实验组和对照组之间的用户是不重叠的。特别是对推荐系统来说,用户体验的一致性是非常重要的。也就是说我们不可以让同一个用户在不同的实验组之间来回“跳跃”,这样会严重损害用户的实际体验,也会让不同组的实验结果相互影响。因此在 A/B 测试中,保证同一用户始终分配到同一个组是非常有必要的。A/B 测试的“正交”与“互斥”原则共同保证了 A/B 测试指标的客观性,而且由于分层的存在,也让功能无关的 A/B 测试可以在不同的层上执行,充分利用了流量资源。在清楚了 A/B 测试的方法之后,我们要解决的下一个问题就是,怎么选取线上 A/B 测试的指标。
线上 A/B 测试的评估指标
看了这些指标,我想你也发现了,线上 A/B 测试的指标和离线评估的指标(诸如 AUC、F1- score 等),它们之间的差异非常大。这主要是因为,离线评估不具备直接计算业务核心指标的条件,因此退而求其次,选择了偏向于技术评估的模型相关指标,但公司更关心的是能够驱动业务发展的核心指标,这也是 A/B 测试评估指标的选取原则。总的来说,在具备线上环境条件时,利用 A/B 测试验证模型对业务核心指标的提升效果非常有必要。从这个意义上讲,线上 A/B 测试的作用是离线评估永远无法替代的。
SparrowRecSys 中 A/B 测试的实现方法
好的,让我们一起来实现一个 A/B 测试模块吧!首先,我们在 SparrowRecSys 里面建立了一个 ABTest 模块,它负责为每个用户分配实验设置。其中,A 组使用的模型 bucketAModel 是 emb,代表着 Item2vec Embedding 算法,B 组使用的模型 bucketBModel 是 Nerualcf。除此之外,我们还给不在 A/B 测试的用户设置了默认模型 emb,默认模型是不在实验范围内的用户的设置。模型设置完,就到了分配实验组的阶段。这里,我们使用 getConfigByUserId 函数来确定用户所在的实验组。具体怎么做呢?因为这个函数只接收 userId 作为唯一的输入参数,所以我们利用 userId 的 hashCode 把数值型的 ID 打散,然后利用 userId 的 hashCode 和 trafficSplitNumber 这个参数进行取余数的操作,根据余数的值来确定 userId 在哪一个实验组里。你可能对 trafficSplitNumber 这个参数的作用还不熟悉,我来进一步解释一下。这个参数的含义是把我们的全部用户分成几份。这里,我们把所有用户分成了 5 份,让第 1 份用户参与 A 组实验,第 2 份用户参与 B 组实验,其余用户继续使用系统的默认设置。这样的操作就是分流操作,也就是把流量划分之后,选取一部分参与 A/B 测试。
public class ABTest {
final static int trafficSplitNumber = 5;
final static String bucketAModel = "emb";
final static String bucketBModel = "nerualcf";
final static String defaultModel = "emb";
public static String getConfigByUserId(String userId){
if (null == userId || userId.isEmpty()){
return defaultModel;
}
if(userId.hashCode() % trafficSplitNumber == 0){
System.out.println(userId + " is in bucketA.");
return bucketAModel;
}else if(userId.hashCode() % trafficSplitNumber == 1){
System.out.println(userId + " is in bucketB.");
return bucketBModel;
}else{
System.out.println(userId + " isn't in AB test.");
return defaultModel;
}
}
}
if (Config.IS_ENABLE_AB_TEST){
model = ABTest.getConfigByUserId(userId);
}
//a simple method, just fetch all the movie in the genre
List<Movie> movies = RecForYouProcess.getRecList(Integer.parseInt(userId), Integer.parseInt(size), model);
小结
这节课,我们讲解了线上 A/B 测试的基本原理和评估指标,并且在 SparrowRecsys 上实现了 A/B 测试的模块。我带你从 A/B 测试的定义和优势、设计原则以及在线评估指标这三个方面回顾一下。A/B 测试又叫“分流测试”或“分桶测试”,它把被测对象随机分成 A、B 两组,通过对照测试的方法得出实验结论。相比于离线评估,A/B 测试有三个优势:实验环境就是线上的真实生产环境;可以直接得到线上的商业指标;不受离线数据“数据有偏”现象的影响。在 A/B 测试的设计过程中,我们要遵循层与层之间的流量“正交”,同层之间的流量“互斥”这一设计原则,这样才能既正确又高效地同时完成多组 A/B 测试。除此之外,在线上评估指标的制定过程中,我们要尽量保证这些指标与线上业务的核心指标保持一致,这样才能更加准确地衡量模型的改进,有没有帮助到公司的业务发展,是否达成了公司的商业目标。为了方便你复习,我把一些核心的知识点总结在了表格中,你可以看一看。