lucene 的评分公式
|
这个公式是由基本的空间向量公式经过化简后再加入各种boost变形而来
首先来解释文章相关度和空间向量之间的概念转换
1 每篇文章都由多种不同的term组成,如果说每种term都表示一个独立的内容含义,那么以多维空间表示的话,每种term都是该空间的一个方向向量。
2 文章内容要表达的总的含义也是一个方向向量,这个方向向量的方向和模受这篇文章内所有term向量的影响(也可以说文章总的意思的方向向量是由所有term向量共同组合而成)。
3 如果某个term向量的模要明显长于其他term向量,就更能引导总向量的方向偏向于它(比如V1+V2=V3,那么如果V1的模比V2要大很多很多,其实V3无限逼近V1的方向)。所以说每个term向量的模都在影响着总向量的方向(其实就是文章表达的总含义)。那么如果term向量的模大小是由对应term的tf和idf来表示,那么就可以建立tf,idf和文章总向量方向之间的数学关系——即tf和idf能左右文章的总含义,这样就把各term的tf,idf和文章总含义用数学关系串起来了。
4 从上面得到的数学模型就是文章中各种term的tf和idf共同影响着文章总的意思,
doc的向量可表示为
Vd=(d_t1_tf * d_t1_idf, d_t2_tf * d_t2_idf, d_t3_tf * d_t3_idf, ...d_tN_tf * d_tN_idf)
d_tN_tf表示doc里第N个term的tf
d_tN_idf表示doc里第N个term的idf
而查询语句也可以看成是一篇简短的doc 所以query的向量可以表示为
Vq=(q_t1_tf * q_t1_idf, q_t2_tf * q_t2_idf, q_t3_tf * q_t3_idf, ...q_tN_tf * q_tN_idf)
q_tN_tf表示query里第N个term的tf
q_tN_idf表示query里第N个term的idf
即:
∑ | ( d_tN_tf · tN_idf2 ) |
1->N
然后是分母
|V(q)| =((q_t1_tf * q_t1_idf)2 + ...+(q_tN_tf * q_tN_idf)2)½
因为q_tN_tf上面说过可看成1,所以
|V(q)| =(q_t1_idf2 + ...+ q_tN_idf2)½
即
(∑ | ( q_tN_idf2 ))½ |
1->N
|V(d)|是doc的总长度
由于Vq*Vd=d_t1_tf * t1_idf * t1_idf + ... + d_tN_tf * tN_idf * tN_idf,
所以如果先不看|V(q)|
V(q) · V(d) 1 |
––––––––– = (d_t1_tf * t1_idf2 + ... + d_tN_tf * tN_idf2) * –––– |
|V(d)| |V(d)| |
d_t1_tf * t1_idf2 d_tN_tf * t1_idf2
= –––––––––––– +...+ ––––––––––––
|V(d)| |V(d)|
在这个算式中每个分项式分子的逻辑含义是表示每个term在对应field内的相关度分值(结合它在其对应field里的频率(tf)和该term本身在全文档中的重要程度(idf)算得),而相除的分母一律是|V(d)| (doc的总长度),这样相除会导致相关度值不够准确
因为在索引中,不同的文档长度不一样,很显然,对于任意一个term,在长的文档中的tf要大的多,因而分数也越高,这样对小的文档不公平,举一个极端的例子,在一篇1000万个词的鸿篇巨著中,"lucene"这个词出现了11次,而在一篇12个词的短小文档中,"lucene"这个词出现了10次,如果不考虑长度在内,当然鸿篇巨著应该分数更高,然而显然这篇小文档才是真正关注"lucene"的。
所以分母不应该是|V(d)| (doc的总长度),而应该分别是分子上每个term对应的域上的term总个数,即“num of term in field f”
就是lucene里面的lengthNorm 这个值等于 (1.0 / Math.sqrt(“num of term in field f”)
所以上面那个连加算式可转化为
即
∑ | ( (d_tN_tf · tN_idf2 )/(“num of term in field f”)½) |
1->N
再加上分母的|V(q)|:
这个就是通过纯粹向量公式再加上lucene对里面一些指标的修改转化而成的原型公式,如果在乘上各种boost就和文档上写的总公式一样了。
上面说了lucene采用向量公式时对公式里的几个因子进行了简化和修改,总结一下
1 q_tN_tf(query中term的频率)简化成了1
2 d_t1_idf 和 q_t1_idf,都代表term在全文档中的重要程度,所以2个值没啥区别 可看成一样
3 |V(d)|(doc长度),按照向量公式转化后每个term在对应field里相关度分数要和 |V(d)|做除,这样不符合实际相关度的情况(理由上面说明),所以去除了|V(d)|,用lengthNorm(代表分子上每个term所在域的term总个数)代替。
公式中关于各类因素的具体实现
public float coord(int overlap, int maxOverlap) {
return overlap / (float)maxOverlap;
}
public float lengthNorm(FieldInvertState state) {
final int numTerms;
if (discountOverlaps)
numTerms = state.getLength() - state.getNumOverlap();
else
numTerms = state.getLength();
return state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)));
}
public float tf(float freq) {
return (float)Math.sqrt(freq);
}
/** The default implementation returns <code>1</code> */
@Override
public float scorePayload(int doc, int start, int end, BytesRef payload) {
return 1;
}