从黑客到和谐:在推荐中建立产品规则

Building product rules in recommendations From hackers to harmony

不要让启发式算法削弱你的机器学习,学会将它们结合起来

在今天的数据驱动环境中,推荐系统支持从社交媒体信息流到电子商务的各种应用。虽然人们往往认为机器学习算法能够胜任所有任务,但这只是故事的一半。现实世界中的系统通常需要结合机器学习和启发式规则(通常称为产品规则、业务规则或简单的技巧)来生成最相关的推荐。

例如:

  • 不能经常推荐来自同一艺术家的音轨;
  • 应该在信息流中包含订阅内容,但不需过多;
  • 如果用户已经对某个类别或作者表示不喜欢,则相关内容应受到惩罚甚至被过滤掉;
  • 不能推荐不适当的内容,除非有合适的情况。
Photo by Cam Bradford on Unsplash

规则分为两种类型:硬规则和软规则。硬规则作为过滤器,禁止特定上下文中的某些文档被推荐;不遵守规则被视为产品缺陷。这些规则本身并没有问题,但它们的数量应当有限。此外,它们应尽早地应用于排名过程,要么在候选生成阶段,要么甚至在索引构建过程中。另一方面,软规则更像是指导方针:你可以推荐这些项,但最好不要过多(或相反,越多越好)。如果有太多这样的软规则,会使系统的调试和开发变得非常困难。

规则是技术债务。

我发现系统中此类规则的数量通常取决于团队内部的权力动态。产品经理通常喜欢通过规则来表达约束条件,而工程师通常不喜欢这些技巧。在我之前的团队中,我们以将这些规则的数量保持在最低限度为豪。

在我的职业生涯中,我经常遇到一个反复出现的模式。工程团队努力训练系统以产生良好的推荐(无论是整体还是在特定方面)。然后,产品团队采取他们最熟悉的方法——添加新规则。在需要快速修复时,这些补丁是有道理的,但很难在以后删除。该系统通常保持在这种修补状态,直到进行重大重构,就像定期的技术债务一样。

故事的寓意是——不要吝啬雇佣优秀的工程师 🙂

在理想的系统中,不应该存在这样的规则;所有的模糊逻辑应该由足够先进的模型处理。我梦想有一天我们能达到这种技术状态(而且我有一个关于如何实现它的假设)。然而,目前来说,这是不现实的。所以,我会讲述一种方法,可以在一定程度上组织和限制这些混乱。

结构化方法:重新排名框架

这个框架允许将机器学习模型与产品规则执行相结合,帮助在避免完全混乱的同时对这些规则进行结构化。然而,它是灵活的,并不过于限制性,因此无法保证完全有序。从某种意义上说,它只是一种描述规则的语言。在我看来,这非常方便。

在这个讨论中,我们将重点放在排名的最后阶段,此时剩下的文档不多——从几十到几百个左右——我们希望从中编译出最佳列表。有趣的是,这个阶段不仅仅是尽可能准确地评估当前上下文中的每个文档,而且还考虑了这些文档如何相互组合。这就是列表级别的排名(不要与学习排序的列表级学习混淆,后者只有损失函数依赖于查询中的所有文档,而不是排名函数)。这种列表级别的方法的典型应用是增强结果的多样性。

以下是该方法的关键原则。

  1. 结果是通过迭代生成的,从第一个位置开始,直到最后一个位置。在每次迭代中,我们为即将到来的位置选择最合适的文档。这就是大多数重新排名策略(如著名的用于多样化的DPP)的工作方式。对于非线性输出,可以按重要性对位置进行排序。
  2. 在每次迭代中,我们将所有剩余的文档按照一个值函数进行排序。这个值函数可以是从点击概率模型的输出到更复杂的组合模型的各种模型输出(或多个模型)的组合,预测不同的事件、多样性组件(如与前面文档的相似性)和手动提升等。值函数可以在每次迭代中重新计算,因此可以依赖于位置和已经在最终输出中的文档。它必须具有高效的计算性能。设计合适的值函数本身就是一个丰富的主题,该框架既不限制也不简化这个方面。
  3. 产品规则如下表达:在位置子集X内,具有属性f的文档数量应该在某个阈值C以上或以下。通常,X是一系列起始位置,例如1到10(第一页)。属性f最好表示为某个特征的阈值规则,即[feature(doc) > threshold]。如果需要,此格式可以推广为包括非二进制属性。
  4. 规则具有优先级。如果我们不能满足所有规则,我们会放弃最不重要的那些规则。更确切地说:如果给定位置可以实现最高优先级的规则,那么它将被强制执行;否则,它将不会被执行。如果下一个最高优先级的规则在这些条件下可以实现,那么它将被执行;否则,我们跳过它。依此类推。换句话说,我们选择满足规则的词法最高的掩码。

以下是此格式中的一些规则示例:

  • 整个输出中至少一半的文档应该是订阅内容。然而,如果所有的订阅文档已经被阅读过,这个规则就变得不可行,并且会被丢弃。
  • 在前10个位置中,低质量文档的数量不应超过2个。
  • 在第10到第20个位置之间,应该至少有一个来自新类别的文档。

值得注意的是,像“前10个位置中至少有5个具有某个属性的文档”这样的规则可能导致前5个位置填充的是不具备该属性的文档,接下来的5个位置才是具备该属性的文档。为了使分布更加均匀,您可以为中间范围添加规则:前2个位置至少有1个,前4个位置至少有2个,以此类推。

高效实现这个框架是一个很好的挑战,但完全可行。下面是一个Python代码示例,用于演示如何实现所描述的重新排序框架。请注意,这个示例代码并不是为了效率而优化的,但应该可以给出一个很好的起点。

def rerank(documents, count, rules, scorer):    result = []    while len(result) < count and len(documents) > 0:        position = len(result)        candidates = documents        for rule in rules:            filtered = [doc for doc in candidates if rule(position, doc)]            if len(filtered) > 0:                candidates = filtered        next_doc = max(candidates, key=lambda doc: scorer(position, doc))        result.append(next_doc)        documents.remove(next_doc)        scorer.update(position, next_doc)        for rule in rules:            rule.update(position, next_doc)    return result

最后,通过记录所有执行和丢弃的规则,可以极大地提高系统的调试性和可控性。

正如我们所见,一个“无规则”的推荐系统目前仍然更像是一个理想而不是现实。但这并不意味着我们陷入了混乱之中。一个良好结构化的规则管理框架可以为您提供所需的组织,而不会扼杀系统的潜力。