假设你运营了一个电影网站,你有不少用户,而且想知道如何推荐给这些用户他们喜欢的电影。一个办法是,把每一个用户做为一个文档建立索引,以下所示(movies_liked被设置为被分词的字段,而且用于搜索):后端
PUT recs/user/1 { "movies_liked": ["Forrest Gump", "Terminator", "Rambo", "Rocky", "Good Will Hunting"]} PUT recs/user/2 { "movies_liked": ["Forrest Gump", "Terminator", "Rocky IV", "Rocky", "Rocky II", "Predator"]} PUT recs/user/3 { "movies_liked": ["Forrest Gump", "The Thin Red Line", "Good Will Hunting", "Rocky II", "Predator", "Batman"]} PUT recs/user/4 { "movies_liked": ["Forrest Gump", "Something about Mary", "Sixteen Candles"]}
咱们想给喜欢《终结者》的用户进行推荐。也就说,咱们须要知道喜欢《终结者》这部电影的用户还喜欢哪些电影。这是很是常见的“购物篮分析” - 推荐系统的基础组件。“购物篮分析”来源于分析用户的购物篮而且统计出用户感兴趣物品间的关系。研究案例代表,一般在杂货铺购买尿片的人同时会选择购买啤酒。深刻洞察此类行为将有助于提高用户和商家的价值。本文咱们聚焦在《终结者》并找出对这部电影可能感兴趣的潜在用户。缓存
利用那些存储了用户观影历史的ElasticSearch文档,咱们如何找出看过《终结者》的观众喜欢什么呢?马上能想到的办法是进行“项”的聚合。项聚合能够得出当前搜索结果中特定字段所包含的项的数量。在某些应用中项可能会是电影的ID,可是在这个案例中使用“标题”。咱们将搜索“终结者”关键词并聚合结果中的“movies_liked”字段从而得出观看《终结者》的用户同时喜欢其余电影的名称以及数量。最终结果展现以下:微信
"movies_like_terminator": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [{ "key": "Forrest Gump", "doc_count": 2 }, { "key": "Rocky", "doc_count": 2 }, { "key": "Terminator", "doc_count": 2 }, { "key": "Good Will Hunting", "doc_count": 1 } }
经过上述的用户记录,你能够了解到喜欢《终结者》的用户中有两我的同时喜欢《阿甘正传》,两我的同时喜欢《洛奇》。此外,若是咱们对你最喜欢的电影重复这样的操做(搜索《终结者》或者《铁血战士》或者《情到深处》等你喜欢的电影),而后你会获得一些协同过滤:发起一个搜索,找到那些和你喜欢一样电影的用户。而后你能够比较下还未看过的电影和你喜欢的电影同时出现的次数。架构
可是这种简单计数的方法是否足够好呢?咱们在其它文章中进行了讨论,认为用简单统计同时出现的次数的方法实现推荐系统是一种不好的方法。简单计数法优先考虑的是全局的广泛关系,而不是有意义的关系。例如在这个例子中,每一个人都喜欢《阿甘正传》。若是咱们用这种方法作推荐,那么每一个用户都被推荐了《阿甘正传》。咱们把这种问题称为“奥普拉读书俱乐部”问题,这些关系广泛存在但不是特别有用。并发
这里更有趣的是关于电影《终结者》的相关计数结果。以《洛奇》为例。每一个喜欢《洛奇》的用户都喜欢《终结者》,居然有100%的重合率!换句话说,《洛奇》在有条件时(喜欢看《终结者》)出现的的比率为100%,在全局中(无条件时)出现的比率仅为50%(有2人喜欢《洛奇》,共有4人)。从这个结果来看,《洛奇》很是适合推荐给喜欢《终结者》的用户的。分布式
要解决简单计数法带来的问题,利用显著项来聚合是一个更好的方法。这种聚合方法度量了咱们所须要的这种在统计学意义上更重要、更有意义的推荐的关系。它的做用不是计算简单的项的计数,而是计算项在当前结果中相比于在背景语料库中的统计显著性。在《购物篮筐分析》一文中,咱们讨论了正反两种评价显著性的不一样方法。如今,咱们来探讨一下显著项能干什么。
在咱们深刻以前,咱们先把这种方法拿出来看看:微服务
POST recs/user/_search { "query": { "match": { "movies_liked": "Terminator" } }, "aggregations": { "movies_like_terminator": { "significant_terms": { "field": "movies_liked", "min_doc_count": 1 } } } }
上面(与简单计数法)惟一的的不一样是咱们用到了significant_term运算。为了让这个操做在咱们这个极小规模的数据集上能得到较好的结果,咱们将min_doc_count设为1(项关联的文档数大于等于1)。
事实上,这一查询解决了以上的问题,咱们能够发现《阿甘正传》在推荐中没有出现,获得的推荐显得更合适:高并发
"buckets": [{ "key": "Rocky", "doc_count": 2, "score": 1, "bg_count": 2 }, { "key": "Terminator", "doc_count": 2, "score": 1, "bg_count": 2 }, { "key": "Rambo", "doc_count": 1, "score": 0.5, "bg_count": 1 }, { "key": "Rocky IV", "doc_count": 1, "score": 0.5, "bg_count": 1 }]
到此为止了吗?咱们还需继续研究:须要理解评分方法在你的数据上是如何工做的。你须要可以深刻了解所使用的评分方法才能创建起真正优秀的推荐系统。如何根据显著项获得上面的排名?正如咱们在《购物篮分析》一文中所见,不一样形式的计分方法有它们本身的优缺点。选择错误的方法可能在推荐的质量方面形成严重的后果。网站
我不打算剖析文中出现的全部显著项(有不少项),但咱们仍是要深刻了解这种方法来教本身如何思考这些问题。这种方法被称为JLH。评分公式是:spa
(foregroundPercentage / backgroundPercentage) * (foregroundPercentage - backgroundPercentage)
“Foreground”的意思是该项在当前搜索结果中出现的百分比(检索结果中用户喜欢咱们的电影名称百分比)。 例如,《第一滴血》的“Foreground”在《终结者》搜索结果中占比是100%。 “Background” 是整个集合的全局百分比。例如,《第一滴血》的是50%。
你将如何评价某一个评分体系是否适合你的用例?让咱们想象几个场景,考虑不一样场景下的得分。而后,能够批判地思考他们在现实的数据中如何展现。咱们继续使用电影为例,这些数据都是假设的:分析JLH评分所用的并非Netflix或Movielens网站上的真正数据。
第一个场景,咱们已经讨论过的是每一个人都喜欢的电影。在咱们的数据集中,这是《阿甘正传》。99.999%的用户喜欢《阿甘正传》。
事实上,这种很是受欢迎的电影对JLH评分不太好。使用(Foreground / Background),《阿甘正传》的评分是100 / 99.999,几乎为1。一样,(Foreground - Background)=(100 - 99.999),几乎为0。 正如你将看到的,这是一个至关低的JLH评分。
这样公平吗?我认为,在大多数领域里,一个物品被接近100%的用户喜欢是少见的。更有可能的是,不多有人对电影具备可衡量的偏好。 例如,或许每一个人都喜欢《阿甘正传》,但大多数的“喜欢”是评级或点击(并不实际观看),不是100%的用户与《阿甘正传》有交集。 固然,我喜欢《阿甘正传》,但上次我看到它大概是10年前。 这是一个被动的偏好。 当我看到它出如今Netflix上时,我不太可能会兴奋。
现实中更常见,最流行的电影或节目是有20%的用户喜欢的东西。那么JLH的得分如何呢?好比《心灵捕手》,若是这组用户中的100%都喜欢,那么最高得分将是(100/20)(100-20)= 5 80 = 400。比《阿甘正传》要高不少。
大多数影片会显示喜欢此影片用户的百分比。让咱们来看一个平均电影:《洛奇IV》,有4%的用户喜欢。
《洛奇IV》使用JLH评分公平吗?若是“Foreground”的用户中100%喜欢《洛奇IV》,咱们获得(100/4)(100 - 4)或25 96 = 2400。明显超过被推荐的《心灵捕手》!
《心灵捕手》很是受欢迎得分400,《洛奇IV》受欢迎程度通常得分2400。彷佛JLH评分方式对于推荐系统来讲有些糟糕?让咱们考虑这些“最佳状况”场景的可能性。 100%的用户喜欢一个电影的同时又喜欢另外一个电影合理吗?喜欢电影的"Foreground"几率偏离“Background”的可能性有多大?
这很大程度上取决于数据中物品偏好的相对分布。例如,人们能够说,若是你喜欢《洛奇III》,你极可能会喜欢《洛奇IV》,也许接近100%重叠。
若是你的数据集“Background”和“Foreground”的差距不大,也许这不是一个大事。 例如,让咱们考虑“Foreground”的值基于以“Background”百分比为中心的正态分布的状况。让咱们考虑“Background”和“Foreground”之间的恒定变化是大约75%的变化(《洛奇IV》大概是7 +/- 3%; 《心灵捕手》大概20 +/- 15%)。 在这些也许更现实的状况下,咱们将指望得分:
《洛奇IV》最佳得分:(7/4)*(7-4)= 5.25
《心灵捕手》最佳分数:(35/20)*(35 - 20)= 26.25
第一项(除法)中两部电影评分接近。另外一项(减法)拉开了两部电影的差距。
为何会这样?做为JLH的建立者,Mark Harwood指出,这正是JLH设计的目的。JLH反映了许多推荐系统数据集中看到的模式:受欢迎的物品受欢迎程度不会发生太大变化。若是几乎每一个人都买鸡蛋,那么分析煎蛋商品对鸡蛋销量影响就会很是小,即使如此,咱们仍然想要这些煎蛋厨师一些建议:即便只能轻微增长鸡蛋的销量也很重要。
做者信息
本文系LeapCloud团队_云服务研发成员:秦鹏【原创】
现任LeapCloud服务与架构部负责人,负责公司云平台、云应用的后端研发和维护工做。有多年分布式、高并发场景的实战经验;目前在分布式存储、缓存、中间件、容器技术、微服务、公有云等领域均有涉猎。毕业于上海交通大学,曾供职于SAP,后投身MaxLeap致力于为开发者提供快稳定、可靠的云服务。
微信公众号:MaxLeap_yidongyanfa
相关文章
飞驰在Mesos的涡轮引擎上
做者往期佳做
微服务实战:从架构到发布(一)
微服务实战:从架构到发布(二)
从应用到平台 – 云服务架构的演进过程
基于PaaS和SaaS研发的商业云平台实战
想要了解APP制做、开发?欢迎加入技术交流QQ群:480843919