这次总结的文章是2018 kdd best paper,来自Airbnb的学长们。
由于从去年年底到现在一直在百度feed实习,也接触到了大量的推荐业务,其实生成embedding更是家常便饭,今天这篇文章更是把embedding思想发挥到了极致。
Airbnb作为全世界最大的短租网站,提供了一个连接房主(host)挂出的短租房(listing)和主要是以旅游为目的的租客(guest/user)的中介平台。这样一个中介平台的交互方式比较简单,guest输入地点,价位,关键词等等,Airbnb会给出listing的搜索推荐列表:
容易想见,接下来guest和host之间的交互方式无非有这样几种:
基于这样的场景,利用几种交互方式产生的数据,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的兴趣。
我们先讨论第一个对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就变成了下面的样子
其中最后一项的lb就是代表着booked listing,因为booking是一个正样本行为,这一项前也是有负号的。注意,这里的objective应该是一个滑动窗口的objective,原论文这里可能不严谨(欢迎讨论)
下面这一项就比较容易理解了,为了更好的发现同一市场(marketplace)内部listing的差异性,Airbnb加入了另一组negative sample,就是在central listing同一市场的listing集合中进行随机抽样,获得一组新的negative samples。同理,我们可以用跟之前negative sample同样的形式加入到objective中。
其中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的数据稀疏问题表现在下面三点上:
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中用到特征
清晰明了 除了最后一个特征 其他特征都是第一种embedding的产出,最后一个特征是基于用户长兴趣的特征。
最后回顾一下标题,为什么airbnb在文章题目中强调是real time personalization?原因就是由于在这些embedding相关的feature中,我们加入了“最近点击listing的相似度”,“最后点击listing的相似度”这类特征,由于这类特征的存在,用户在点击浏览的过程中就可以得到实时的反馈,搜索结果也是实时地根据用户的点击行为而改变,所以这无疑是一个real time个性化系统。