BM25算法的介绍:http://en.wikipedia.org/wiki/Okapi_BM25
BM25算法一直是被用作代替lucene的TFIDF的评分公式的。
- 首先给出BM25的相关度计算公式,该函数可以计算出对于一个document,一个给定的关键字序列i对于该document的score:
- score = ∑( IDF[ i ] * f [ i ] * ( k1 + 1) ) / (f [ i ] + k1 * ( 1 - b + b * k2 ) ) (i = 1 .... KeywordsNum )
- 下面对这个公式中的每一部分进行解释
- f[i] 的原型是(term frequency)是指第i个关键字在该document中的出现次数。
- k2 的值为 该帖的长度 与所有贴的平均长度的比值 。这个量其实是很关键的。它可以在一定程度上消除帖子长度对于它重要性的影响。
- k1 和 b 是 BM25 中的两个系数 通常 k1 = 2.0 , b = 0.75 。
- IDF[i]全称是(inverse document frequency)是根据每个关键在在所有帖中出现次数的多少进行该关键字的重要性调整
- 一个直观的认识是如果一个关键字在大多数帖中都出现,那么它的代表性就很差,所以这个这个关键字的IDF值就一定会小,
- 而反过来如果一个关键字只在这一个帖子里出现过,那么这个关键字的代表性就很强,它的IDF值就会很大,该关键字的重要性就被强调了。
- 有了IDF,大量水贴的重复关键字的权值就会被降的很低,从而达到了我们防水抗洪救灾的目的.(^-^)
- IDF[i]的具体计算公式如下:
- IDF[i] = log( ( repNum + n[ i ] + 0.5 ) / ( n [ i ] + 0.5 ) ) ;
- 公式中的repNum值所有回帖的总数,n[i]指在所有回帖中出现关键字i的帖子总数.
- 有了上面的这些公式,我们就可以实现这个基于Okapi BM25算法的allscore函数了~
- **********************************************************************************************************************/
double fscore ( int n , int f[], double IDF[] , double k2 ) // 这里是根据BM25公式计算具体的score值 { double ans = 0, k1 = 2.0, b = 0.75; int i; for ( i = 0 ; i n ; i ++ ) ans += ( IDF[ i ] * f [ i ] * ( k1 + 1) ) / (f [ i ] + k1 * ( 1 - b + b * k2 ) ) ; return ans ; } struct Srch * allScore(struct Reply * p , struct Link * node) { int i , j ,*f , *n ,linkLen = 0 , totalLen = 0 ; double totScore = 0 , *IDF , k2 , avgL , Dlen ; struct Link * pNode = node; struct Reply * pReply = p ; struct Srch * scorelist = NULL ; while ( pNode != NULL) { linkLen++; pNode = pNode -> next ; }// 统计查询关键字个数 f = (int * ) calloc( linkLen , sizeof(int) ) ;// 每个关键字在该Reply中出现的个数 n = (int * ) calloc( linkLen , sizeof(int) ) ;// 每个关键字在全部Reply中的出现的帖子的个数 IDF = (double * ) calloc( linkLen , sizeof(double) ) ;//计算IDF函数 j = 0 ; pNode = node; while ( pReply != NULL ) {//计算n()函数 pNode = countkey( pReply->comment , pNode ); totalLen += strlen( pReply->comment ); i = 0 ; while ( pNode != NULL ) { if ( pNode -> oTimes ) n[ i ] ++ ; i ++ ; pNode = pNode ->next ; } pReply = pReply -> next ; pNode = node; j ++ ; } int repNum = j ; for ( i = 0 ; i linkLen ; i ++ ) IDF[ i ] = log( ( repNum + n[ i ] + 0.5 ) / ( n [ i ] + 0.5 ) ) ; //计算IDF函数 avgL = ( totalLen + 0.0 ) / repNum ; pReply = p; pNode = node ; while ( pReply != NULL ) {//计算所有score pNode = countkey ( pReply->comment , pNode ) ; i = 0 ; while ( pNode != NULL ) { f [ i ] = pNode -> oTimes ; i ++ ; pNode = pNode ->next; } Dlen = strlen( pReply ->comment ) ; k2 = Dlen / avgL ; double nscore ; nscore = fscore( linkLen , f , IDF , k2 ) ; insertIdx( &scorelist , pReply , nscore ) ; pReply = pReply -> next ; pNode = node ; } free(f) ; free(n) ; free(IDF) ; return scorelist; }
待续。。。