《Real-time Personalization using Embeddings for Search Ranking at Airbnb》论文总结

这次总结的文章是2018 kdd best paper,来自Airbnb的学长们。

由于从去年年底到现在一直在百度feed实习,也接触到了大量的推荐业务,其实生成embedding更是家常便饭,今天这篇文章更是把embedding思想发挥到了极致。

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

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

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

基于这样的场景,利用几种交互方式产生的数据,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分钟没有动作,那么这个序列会断掉,不再是一个序列。

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

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

这里直接列出word2vec的skip-gram model的objective如下:

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

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

在原始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就变成了下面的样子

《Real-time Personalization using Embeddings for Search Ranking at Airbnb》论文总结_第1张图片

其中最后一项的lb就是代表着booked listing,因为booking是一个正样本行为,这一项前也是有负号的。注意,这里的objective应该是一个滑动窗口的objective,原论文这里可能不严谨(欢迎讨论)

下面这一项就比较容易理解了,为了更好的发现同一市场(marketplace)内部listing的差异性,Airbnb加入了另一组negative sample,就是在central listing同一市场的listing集合中进行随机抽样,获得一组新的negative samples。同理,我们可以用跟之前negative sample同样的形式加入到objective中。

《Real-time Personalization using Embeddings for Search Ranking at Airbnb》论文总结_第2张图片

其中Dmn就是新的同一地区的negative samples的集合。

至此,lisitng embedding的objective就定义完成了,embedding的训练过程就是word2vec negative sampling模型的标准训练过程,这里不再详述。

除此之外,文章多介绍了一下cold start的问题。简言之,如果有new listing缺失embedding vector,就找附近的3个同样类型、相似价格的listing embedding进行平均得到,不失为一个实用的工程经验。

总结起来就是,在skip-gram形势采用负采样训练的word2vec中的每一个滑动窗口的损失中添加了正样本信息(book session中添加了book item),是搜索列表和相似列表更加倾向于推荐之前预定过的item,又添加了负样本信息(central item同一市场的集合中随机负采样)这样更能发现同一个市场中item的差异。

我们介绍了Airbnb为了捕捉用户的短期兴趣,使用用户的点击数据构建了listing(也可称为item,即一个短租屋)的embedding,基于该embedding,可以很好的找出相似listing,但有所欠缺的是,该embedding并没有包含用户的长期兴趣信息。

比如用户6个月前订了一个listing,其中包含了该用户对于房屋价格、房屋类型等属性的长期偏好,但由于之前的embedding只使用了session级别的点击数据,从而明显丢失了用户的长期兴趣信息。

为了捕捉用户的长期偏好,airbnb在这里使用了booking session序列。比如用户j在过去1年依次book过5个listing,那么其booking session就是 。既然有了booking session的集合,我们是否可以像之前对待click session一样拿直接应用w2v的方法得到embedding呢?答案是否定的,因为我们会遇到非常棘手的数据稀疏问题。

具体来讲booking session的数据稀疏问题表现在下面三点上:

  1. book行为的总体数量本身就远远小于click的行为,所以booking session集合的大小是远远小于click session的
  2. 单一用户的book行为很少,大量用户在过去一年甚至只book过一个房源,这导致很多booking session sequence的长度为1
  3. 大部分listing被book的次数也少的可怜,大家知道w2v要训练出较稳定有意义的embedding,item最少需要出现5-10次,但大量listing的book次数少于5次,根本无法得到有效的embedding。

Airbnb如何解决如此严重的数据稀疏问题,训练出有意义的user embedding和listing embedding呢?
他们给出的答案是基于某些属性规则做相似user和相似listing的聚合

那么我们就可以用属性名和bucket id组成一个属性标识,比如说某个listing的国家是US,类型(listing type)是Ent(bucket 1),每晚的价格(per night)是56-59美金(bucket3),那么就可以用US_lt1_pn3来表示该listing的listing_type。

user_type的定义同理。

有了user type和listing type之后,一种直观的生成新的booking session sequence的方式是这样,直接把user type当作原来的user id,生成一个由listing type组成的booking session。这种方法能够解决数据稀疏性的问题,却无法直接得到user type embedding。为了让user type embedding和listing type embedding在同一个vector space中生成,airbnb采用了一种比较“反直觉”的方式。

针对某一user id按时间排序的booking session, ,我们用(user_type, listing_type)组成的元组替换掉原来的listing item,因此sequence变成了 ,这里 指的就是listing l1对应的listing type, 指的是该user在book listing l1时的user type,由于某一user的user_type会随着时间变化,所以 不一定相同。

有了该sequence的定义,下面的问题就是如何训练embedding使得user type和listing type在一个空间内了。训练所用的objective完全沿用了上一篇文章的objective的形式,但由于我们用一个(user type,listing type)的元组替换掉了原来的listing,如何确定central item就成为了一个核心问题。看了原文章,也没太讲清楚,我猜测大概率是把元组打平了(欢迎讨论)。

接下来为了引入“房主拒绝”(reject)这个action,airbnb又在objective中加入了reject这样一个negative signal,方法与上一篇文章中加入negative signal的方法相同,在此不再赘述。

介绍完论文之后看看airbnb中用到特征

《Real-time Personalization using Embeddings for Search Ranking at Airbnb》论文总结_第3张图片

清晰明了 除了最后一个特征 其他特征都是第一种embedding的产出,最后一个特征是基于用户长兴趣的特征。

最后回顾一下标题,为什么airbnb在文章题目中强调是real time personalization?原因就是由于在这些embedding相关的feature中,我们加入了“最近点击listing的相似度”,“最后点击listing的相似度”这类特征,由于这类特征的存在,用户在点击浏览的过程中就可以得到实时的反馈,搜索结果也是实时地根据用户的点击行为而改变,所以这无疑是一个real time个性化系统。

 

 

你可能感兴趣的:(推荐系统,论文阅读)