这里是 「王喆的机器学习笔记」 的第八篇文章,今天我们聊一聊KDD 2018的Best Paper,Airbnb的一篇极具工程实践价值的文章 Real-time Personalization using Embeddings for Search Ranking at Airbnb

相信大家已经比较熟悉我选择计算广告和推荐系统相关文章的标准:

  1. 工程导向的;
  2. 阿里、facebook、google等一线互联网公司出品的;
  3. 前沿或者经典的。

Airbnb这篇文章无疑又是一篇兼具实用性和创新性的工程导向的paper。文章的作者Mihajlo发表这篇文章之前在Recsys 2017上做过一个talk,其中涉及了文章中的大部分内容,我也将结合那次talk的slides来讲解这个论文。

废话不多说,我们进入文章的内容。

Airbnb作为全世界最大的短租网站,提供了一个连接房主(host)挂出的短租房( listing)和主要是以旅游为目的的租客(guest/user)的中介平台。这样一个中介平台的交互方式比较简单,guest输入地点,价位,关键词等等,Airbnb会给出listing的搜索推荐列表:

Airbnb的业务场景

容易想见,接下来guest和host之间的交互方式无非有这样几种:

  1. guest点击listing ( click
  2. guest预定lising ( book
  3. host有可能拒绝guest的预定请求 ( reject

Airbnb的交互方式

基于这样的场景,利用几种交互方式产生的数据,Airbnb的search团队要构建一个real time的ranking model。为了捕捉到用户short term以及long term的兴趣,Airbnb并没有把user history的clicked listing ids或者booked listing ids直接输入ranking model,而是先对user和listing进行了embedding,进而利用embedding的结果构建出诸多feature,作为ranking model的输入。这篇文章的核心内容就是介绍 如何生成listing和user的embedding

具体到embedding上,文章通过两种方式生成了两种不同的embedding分别capture用户的short term和long term的兴趣。

  1. 一是通过click session数据生成listing的embedding,生成这个embedding的目的是为了进行listing的相似推荐,以及对用户进行session内的实时个性化推荐。
  2. 二是通过booking session生成user-type和listing-type的embedding,目的是捕捉不同user-type的long term喜好。由于booking signal过于稀疏,Airbnb对同属性的user和listing进行了聚合,形成了user-type和listing-type这两个embedding的对象。

我们先讨论第一个对listing进行embedding的方法:

Airbnb采用了click session数据对listing进行embedding,其中click session指的是一个用户在一次搜索过程中,点击的listing的序列,这个序列需要满足两个条件,一个是只有停留时间超过30s的listing page才被算作序列中的一个数据点,二是如果用户超过30分钟没有动作,那么这个序列会断掉,不再是一个序列。

Click Session的定义和条件

这么做的目的无可厚非,一是清洗噪声点和负反馈信号,二是避免非相关序列的产生。

有了由clicked listings组成的sequence,就像我们在之前专栏文章中讲过的item2vec方法一样,我们可以把这个sequence当作一个“句子”样本,开始embedding的过程。Airbnb不出意外的选择了word2vec的skip-gram model作为embedding方法的框架。通过修改word2vec的objective使其靠近Airbnb的业务目标。

Airbnb的类word2vec embedding方法

我们在之前的专栏文章 万物皆embedding 中详细介绍了word2vec的方法,不清楚的同学还是强烈建议先去弄明白word2vec的基本原理,特别是objective的形式再继续下面的阅读。

我们假设大家已经具备了基本知识,这里直接列出word2vec的skip-gram model的objective如下:

在采用negative sampling的训练方式之后,objective转换成了如下形式:

其中σ函数代表的就是我们经常见到的sigmoid函数,D是正样本集合,D’是负样本集合。我们再详细看一下上面word2vec这个objective function,其中前面的部分是正样本的形式,后面的部分是负样本的形式( 仅仅多了一个负号)。

为什么原始的objective可以转换成上面的形式,其实并不是显然的,感兴趣的同学可以参考这篇文章, Negative-Sampling Word-Embedding Method。这里,我们就以word2vec的objective function为起点,开始下面的内容。

转移到Airbnb这个问题上,正样本很自然的取自click session sliding window里的两个listing,负样本则是在确定central listing后随机从语料库(这里就是listing的集合)中选取一个listing作为负样本。

因此,Airbnb初始的objective function几乎与word2vec的objective一模一样,形式如下:

(给大家出个脑筋急转弯,为啥Airbnb objective的正样本项前面是负号,原始的word2vec objective反而是负样本项前面是负号,是Airbnb搞错了吗?)

在原始word2vec embedding的基础上,针对其业务特点,Airbnb的工程师希望能够把booking的信息引入embedding。这样直观上可以使Airbnb的搜索列表和similar item列表中更倾向于推荐之前booking成功session中的listing。从这个motivation出发,Airbnb把click session分成两类,最终产生booking行为的叫booked session,没有的称做exploratory session。

因为每个booked session只有最后一个listing是booked listing,所以为了把这个booking行为引入objective,我们不管这个booked listing在不在word2vec的滑动窗口中,我们都会假设这个booked listing与滑动窗口的中心listing相关,所以相当于引入了一个global context到objective中,因此,objective就变成了下面的样子

其中最后一项的lb就是代表着booked listing,因为booking是一个正样本行为,这一项前也是有负号的。

需要注意的是最后一项前是没有sigma符号的,前面的sigma符号是因为滑动窗口中的中心listing与所有滑动窗口中的其他listing都相关,最后一项没有sigma符号直观理解是因为booked listing只有一个,所以central listing只与这一个listing有关。

但这里的objective的形式我仍让是有疑问的,因为这个objective写成这种形式应该仅代表了一个滑动窗口中的objective,并不是整体求解的objective。如果是整体的objective,理应是下面的形式:

其中Db代表了所有booked session中所有滑动窗口中central listing和booked listing的pair集合。

**不知道大家有没有疑问,我们可以