揭秘我烧网热文排序算法—SmartHot
就像Google不会公布其搜索排名算法一样,大多数公司都不会对外公布涉及排名的算法。因为这个算法一旦公布,总会有人去做SPAM。同理,我烧网的热文排序算法也不会对外公布,我们只是向用户提供一些基本的原则。这一算法被我们命名为SmartHot,是在2009年底我烧网改版时设计的,到现在已有一年多时间。这期间我们对算法进行了数次改进和调整,也正因如此,才使得我有机会可以将当时的一些设计思路拿出来与大家分享。希望通过对这一算法的产生过程的介绍,给更多的网站、程序设计人员一些启发,同样也希望大家踊跃拍砖,共同学习、共同进步。
我烧网是一个以博客内容聚合为基础的阅读社区,像其他内容聚合网站一样,由于存在海量的内容,因此对内容的提炼尤为重要。在改版之前,我们一直通过人工方式推荐内容,但人工方式有两个缺陷:一个是人力成本过高,另一个是推荐出的内容往往是编辑喜欢而用户不一定喜欢的。这次改版,我们希望采用众包的方式,让用户为用户推荐内容,从而节约团队的人力成本,同时也能够真正把用户喜欢的内容推荐出来,使用户的互动更加活跃。这个推荐列表就是后来的我烧网热文。从访问统计来看,热文页的PV也远远高于其他页面。而热文的幕后,就是靠这套SmartHot算法支撑的。
在提出要研制一套文章排序算法之前,我们先是对这次改版进行了一个规划,整个规划有一个中心思想,那就是让更多的用户参与到网站中来,通过用户的参与提高网站内容的质量,然后再把高质量的内容反馈给用户。SmartHot要为这一中心思想服务。后来的实践证明,在这套算法的支撑下,我烧网实现了飞速的发展,最终带来的主要影响有三:一是更多用户参与到社区的活动中来,二是内容质量大幅提升,三是节约了大量的人力成本而且带来了比人工更好的效果。在这一中心思想的指导下整个团队开始了对热文排序算法的思考。
提出问题
首先,以用户行为为推荐的基础并不是说让用户去推荐,因为用户做太多贡献会使网站失去活力。更加明智的做法应该是基于用户的各种单一操作,通过数据挖掘找出最值得推荐的文章。这样就细化成了一个数据挖掘的问题—通过对用户行为数据的挖掘找到好的文章再推荐给全部的用户。面对这样的问题,团队提出了很多种解决思路。最简单、最常规的当然就是按照文章的浏览量来排序。然而无数经历都证明了这不是一个合理的算法,浏览量的高低只能代表访问者被标题、图片等吸引的程度。如果想要了解用户对文章的真实感受,就得用添柴数(我烧网中用户通过为文章添柴来表达对其的喜爱)来排序。但是,无论是浏览数还是添柴数,都是累计的数字,最终必然会因马太效应产生严重问题,使排在前面的文章永远排在前面,新文章无法进入前列。这时,将二者结合的思路出现了。
我们把添柴数作为正向的参数,把浏览量作为反向的参数。如果一篇文章被用户浏览了100次、添柴10次,那么就计为0.1分(10/100=0.1)。这就意味着,浏览量越大,最终的排序分值越小!这是一个很具突破性的想法,因为我们知道很多同行都把浏览量作为正向参数给文章排序。问题貌似解决了,但是新的问题也随之产生:大多数用户只看不操作,换句话说很多用户即便觉得文章很不错,也懒得去添柴,这样势必导致很多好的文章因为浏览量大反而失去排在前面的机会。几番斟酌,我们最终决定放弃浏览量这个依据—文章得分以添柴数为基础。
在我烧网中,对文章的其他操作如评论、分享等也类似于添柴,被赋予一定的分数计入文章的得分。当然,单纯按得分来排序也是不合理的,这与直接用添柴数排序的结果是一样的。为了保证用户喜欢的新文章能够永远排在用户同样喜欢的旧文章之前,我们必须要引入时间参数,由用户操作的得分和文章的发布时间共同决定文章的排序值。添柴数(包括其他用户操作)作为正向的参数,文章发布时间作为反向的参数,最终得到的排序用的排序值与文章得分成正比、与发布时间成反比。于是又一重要原则产生了—文章排序值随时间的前进而衰减。
分析到这里,团队里的每一个人都欣喜若狂:我们知道算法即将完成了。但是一个尖锐的矛盾又把我们拉回现实:文章得分是非常容易作弊的。一个人如果对一篇文章连续添柴,包括换用很多马甲连续添柴,都可以直接获得很多得分。我们可以限制一名用户连续添柴的次数,可是我们无法限制一个用户注册马甲的数量。于是,一个关于用户权重的参数—用户系数,出现了。用户系数与等级相关,等级越高的用户权
重越大,刚注册的用户权重极低。基本思路产生后,问题也就很明确了,接下来就是根据这些问题确定各个目标,然后解决问题。
确定目标
根据前面的分析,可以确定如下目标。
1.为每种用户操作设定其固有的分值。
2.设定一个时间衰减的速率。
3.确立一个用户系数模型,使用户的权重随等级变化而变化。
4.设计一个用户等级体系。