探究 Stack Overflow 网站的热点问题排名算法

简介:

引入:

几乎所有搞开发的人都对Stack Overflow不陌生,它是一个专门的Q&A类型的网站http://dbanotes.net/startup/stack_overflow_success.html (类似这种网站的例子还有很多,比如新浪问问,百度搜搜等)你如果遇到了技术问题,你可以在这里提问,然后就有专家或者路人去回答你的问题,其他人还可以对别人的回答以及这个提的问题本身进行评价,然后这些所有信息,比如问题被点击了多少次,多少人提过问题,对问题的评价是好的还是坏的,有多少人参与了回答,回答的得分是多少,这问题提了多久了,这问题最近一次回答是多久前等信息都会被搜集起来,然后用一个叫做“热点度” 的专业词汇来衡量,如果热点度高,那么说明这个问题是热门问题,那么问题更可能出现在关键字搜索后的问题排名中,我们这文章的目的就是来研究热点问题的排名算法,我还专门用java实现了这个算法,并且和网上的搜索结果相匹配。


实践:

比如我搜索liferay-theme关键字,会得到以下的结论:http://stackoverflow.com/questions/tagged/liferay-theme?sort=newest&pageSize=15 ,我们看到了一组热点问题排名如下:

174627221.png

我们通过研究,发现这个Stack Overflow 创始人之一的Jeff Atwood公布过排名算法如下:

174751158.png


我们现在就用java程序来实现这个算法,然后和真实的搜索结果比较(貌似我干的事情很蛋疼):


首先找到这个算法公式的多个自变量:

我们创建一个VO值对象来包含这些自变量,这些自变量作用参见注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package  com.algoresearch;
import  java.util.Date;
/**
  *
  * Description: the value object for given hot question
  *
  * @author charles.wang
  * @created Oct 15, 2013 3:32:25 PM
  *
  */
public  class  HotQuestionInfoVO {
       
     protected  long  viewTimes;                      //问题的浏览次数
     protected  long  agreeTicketNo;                  //问题的赞成票数
     protected  long  rejectTicketNo;                 //问题的反对票数
     protected  long  answerTimes;                    //问题被回答的次数
     protected  long [] answerScores;                 //每个回答的得分
     protected  long  lastQuestionPostMillis ;        //问题提出至今的时间(单位:秒)
     protected  long  lastAnswerPostMillis;           //问题最近回答至今的时间(单位:秒)
       
       
     /**
      *
      * @param viewTimes
      * @param agreeTicketNo
      * @param rejectTicketNo
      * @param answerTimes
      * @param answerScores
      * @param lastQuestionPostMillis
      * @param lastAnswerPostMillis
      */
     public  HotQuestionInfoVO( final  long  viewTimes,
                              final  long  agreeTicketNo,
                              final  long  rejectTicketNo,
                              final  long  answerTimes,
                              final  long [] answerScores,
                              final  long  lastQuestionPostMillis,
                              final  long  lastAnswerPostMillis){
         this .viewTimes                =viewTimes;
         this .agreeTicketNo            =agreeTicketNo;
         this .rejectTicketNo           =rejectTicketNo;
         this .answerTimes              = answerTimes;
         this .answerScores             = answerScores;
         this .lastQuestionPostMillis   =lastQuestionPostMillis;
         this .lastAnswerPostMillis     = lastAnswerPostMillis;
           
     }
       
     @Override
     public  String toString(){
         StringBuilder sb =  new  StringBuilder();
         sb.append( "该问题被浏览了: " + viewTimes+ " 次" + "\n" );
         sb.append( "该问题被赞成的投票数为: " +agreeTicketNo+ "\n" );
         sb.append( "该问题被反对的投票数为: " +rejectTicketNo+ "\n" );
         sb.append( "该问题被回答的次数为: " +answerTimes+ " 次" + "\n" );
         sb.append( "该问题被提出的时间为: " +( new  Date(lastQuestionPostMillis)).toString()+ "\n" );
         sb.append( "该问题被最后一次解答的时间为: " +( new  Date(lastAnswerPostMillis)).toString()+ "\n" );
           
         return  sb.toString();
     }
       
       
       
}



然后,我们来创建计算类,这个类职责是通过以上一些因素来得到相应的热点问题的评分,注释很详细了,自己看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
  */
package com.algoresearch;
/**
  *
  * Description: utility class that can calculate the "hot" value of given hot question based on factors
  *
  * @author charles.wang
  * @created Oct 15, 2013 3:43:45 PM
  *
  */
public  class  HotQuestionScoreCalculator {
                                                                                                                                                                                                              
                                                                                                                                                                                                              
     public  static  double  calculateHotQuestionScoreValue (HotQuestionInfoVO  vo){
                                                                                                                                                                                                                  
         //Step1: 计算问题浏览次数对于热点的影响:
         //       浏览次数(viewTimes)越多,说明越是热点,而对于10取对数的作用则是弱化频繁被浏览造成的指数虚高因素
         double  factor1 = Math.log10(vo.viewTimes) * 4 ;
                                                                                                                                                                                                                  
         //Step2: 计算问题的参与度以及好评/差评对于热点的影响:
         //       如果一个问题,被好评的多,被差评的少,那么问题越"热" (agreeTicketNo-rejectTicketNo),
         //       此外,回答次数也很重要,因为被回答次数越多,说明有更多的人参与了这个问题的思考,从而使该问题变"热"
         double  factor2 = (vo.agreeTicketNo-vo.rejectTicketNo)*vo.answerTimes/ 5 ;
                                                                                                                                                                                                                  
         //Step3:计算回答的质量对于热点的影响:
         //      每个问题的回答都有一个得分,所有问题的总分越高,说明问题越有价值,也就越"热"
         long  sum=0L;
         for long  i : vo.answerScores)
             sum+=i;
         double  factor3=( double )sum;
                                                                                                                                                                                                                  
         //以上几个是放在分子上的正相关因素,下面几个是放在分母上的反相关因素
                                                                                                                                                                                                                  
         //Step4:计算距今发表问题时间和距今最近回答问题时间对于热点的影响:
         //      显然,发表问题越久远,其热点度越低,上次回答问题越久远,其热点度越低。
         //      距今发表问题时间-最近回答问题时间表示了问题的闲置度,显然这个值越小,说明很少有人继续光顾,热点越低。
         long  questionExistingTime=(System.currentTimeMillis()-vo.lastQuestionPostMillis)/ 1000 ;
         long  answerUpdatedTime=(System.currentTimeMillis()-vo.lastAnswerPostMillis)/ 1000 ;
         double  factor4 = Math.pow((questionExistingTime+ 1 ) - ( (questionExistingTime-answerUpdatedTime)/ 2 ), 1.5 );
                                                                                                                                                                                                                  
         return  (factor1+factor2+factor3)/factor4;
     }
}



最后,我们按照上文截图的例子进行验证,我们就取这3个来比较,所以在Main类中,我们创建了3个VO,然后调用计算方法得出3个热点度,最后比较这些热点度是否是和图示一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*
  */
package com.algoresearch;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
/**
  *
  * Description:
  *
  * @author charles.wang
  * @created Oct 15, 2013 4:24:47 PM
  *
  */
public  class  MainClass {
                                                                                                                                                                   
     public  static  void  main(String [] args){
                                                                                                                                                                       
         //模拟search liferay-theme的结果:
         //搜索地址为  http://stackoverflow.com/questions/tagged/liferay-theme?sort=newest&pageSize=15
                                                                                                                                                                       
                                                                                                                                                                       
         //第一条热门问题
         long  answerScores1[]= {-2L,1L,4L,1L};
         Calendar questionAskTime1 = Calendar.getInstance();
         questionAskTime1.set( 2012 10 , 17 , 13 , 59 , 27 );
         Calendar questionLastAnswerTime1 = Calendar.getInstance();
         questionLastAnswerTime1.set( 2013 , 7 , 3 , 18 , 55 , 37 );
         HotQuestionInfoVO hotQuestion1 =  new  HotQuestionInfoVO (2000L,4L,1L,4L,answerScores1,questionAskTime1.getTimeInMillis(),questionLastAnswerTime1.getTimeInMillis());
         System.out.println(hotQuestion1);
         double  hotQuestionValue1 = HotQuestionScoreCalculator.calculateHotQuestionScoreValue(hotQuestion1);
                                                                                                                                                                       
         //第二条热门问题
         long  answerScores2[]= {3L,4L};
         Calendar questionAskTime2 = Calendar.getInstance();
         questionAskTime2.set( 2012 4 , 4 , 8 , 33 , 4 );
         Calendar questionLastAnswerTime2 = Calendar.getInstance();
         questionLastAnswerTime2.set( 2012 , 4 , 4 , 11 , 53 , 17 );
         HotQuestionInfoVO hotQuestion2 =  new  HotQuestionInfoVO (1000L,3L,0L,2L,answerScores2,questionAskTime2.getTimeInMillis(),questionLastAnswerTime2.getTimeInMillis());
         System.out.println(hotQuestion2);
         double  hotQuestionValue2 = HotQuestionScoreCalculator.calculateHotQuestionScoreValue(hotQuestion2);
                                                                                                                                                                       
                                                                                                                                                                       
         //第三条热门问题
         long  answerScores3[]= {7L};
         Calendar questionAskTime3 = Calendar.getInstance();
         questionAskTime3.set( 2012 2 , 19 , 16 , 23 , 38 );
         Calendar questionLastAnswerTime3 = Calendar.getInstance();
         questionLastAnswerTime3.set( 2012 , 02 , 20 , 14 , 18 , 57 );
         HotQuestionInfoVO hotQuestion3 =  new  HotQuestionInfoVO (496L,3L,0L,1L,answerScores3,questionAskTime3.getTimeInMillis(),questionLastAnswerTime3.getTimeInMillis());
         System.out.println(hotQuestion3);
         double  hotQuestionValue3 = HotQuestionScoreCalculator.calculateHotQuestionScoreValue(hotQuestion3);
                                                                                                                                                                       
         if ( (hotQuestionValue1>hotQuestionValue2 ) && (hotQuestionValue2>hotQuestionValue3) ){
             System.out.println( "热点问题排名和期望一样" );
         } else {
             System.out.println( "热点问题排名不和期望一样" );
         }
                                                                                                                                                                       
                                                                                                                                                                      
                                                                                                                                                                       
     }
}



我们运行结果,果然这个排名和我们图上的一致:

175435288.png



总结:

其实我做的这个无聊的实验只是用于验证这个公式是否真的和创始人说的那样正确的应用到了网站,当然了,这里得到证实。我们反观公式,运用数学公式,可以得到以下结论:


对于Stack Overflow 热点问题的热点度,它:

(1)和浏览次数成正比,浏览次数越多,热点度越高

(2)和问题的参与度成正比,参与问题回答的人越多,热点度越高

(3)和问题本身被评价的好坏正相差成正比,好评越多,差评越少,热点度越高,说明这是个好问题

(4)和提供答案的人给的答案水平成正比,答案正确给分高,错误可能是负分,所以给的正确答案或者参考信息越多,热点越高,而如果一些人恶意给答案或者乱给错误答案导致答案评分低或者负数,则会影响热点度。

(5)和问题提出的距今时间成反比,这个问题被提出的越早,热点度越低。

(6)和问题被最后回答的时间成反比,这个问题如果很久没新的答案了,那么热点度降低。



其他的Q&A类型网站我没研究过,虽然我估计公式不一定一样,但是这些结论我相信还是正确的。





本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1309334,如需转载请自行联系原作者
目录
相关文章
|
6月前
|
算法
|
11月前
|
算法 数据挖掘 索引
白话Elasticsearch48-深入聚合数据分析之 Percentiles Aggregation-percentiles百分比算法以及网站访问时延统计及Percentiles优化
白话Elasticsearch48-深入聚合数据分析之 Percentiles Aggregation-percentiles百分比算法以及网站访问时延统计及Percentiles优化
88 0
|
算法 数据可视化 前端开发
这几个算法可视化网站,太牛了!
很多初学者在学习数据结构与算法的时候,都会觉得很难,很大一部分是因为数据结构与算法本身比较抽象,不好理解。对于这一点,可以通过一些可视化动画来帮助理解。
683 1
|
算法 程序员 测试技术
|
算法 数据可视化 JavaScript
好家伙,被我发现了个数据结构与算法可视化网站!
今天我就把自己在学数据结构与算法时,用到可视化网站分享出来。
好家伙,被我发现了个数据结构与算法可视化网站!
|
算法 数据可视化 JavaScript
轻松学算法的秘密!可视化算法网站汇总!(附动图)
轻松学算法的秘密!可视化算法网站汇总!(附动图)
366 0
轻松学算法的秘密!可视化算法网站汇总!(附动图)
|
XML 搜索推荐 JavaScript
小弟对百度网站排名算法的总结归纳
最近在做深圳人才网的关键字排名,推广写软文的时间很少,所以直接进入主题、
113 0
|
搜索推荐 算法 UED
网站更新频率真的很重要吗?不为人知的算法揭秘
网站更新频率真的很重要吗?不为人知的算法揭秘。很多人认为每天更新文章才能让搜索引擎更加喜欢,但事实上不是这样的,频繁更新更加不利于网站排名
网站更新频率真的很重要吗?不为人知的算法揭秘
|
算法 应用服务中间件 nginx