一切依旧 2017-04-11
当用solr或者lucene搜索的时候,如果想对不同类型的文章,或者不同的字段设置不同的权重,又或者对不同的搜索词语设置不同权重,则需要boost功能。
1、boost设置方法
在索引时候设置boost,会消耗额外的内存;在查询的时候设置boost,会消耗cpu。
索引的时候,boost值是写入索引文件的,存储在标准化因子(.nrm)文件中,一旦设定,除非删除此文档,或者重写记录,否则无法改变。所以在查询的时候设置boost会更灵活。
不设置的时候,默认boost为1.0。
solr以lucene为基础的,二者的boost是基本一样的,下面以lucene为例来说。
//lucene索引的时候设置boost
Document doc = new Document();
Field f = new Field("contents", "hello world", Field.Store.NO, Field.Index.ANALYZED);
f.setBoost(100);//对某个字段设置权重
doc.add(f);
doc.setBoost(100);//对文档设置权重
//solrj索引的时候设置boost
doc.addField("title","中华",1.0f);//1.0f即是title域的boost
doc.setDocumentBoost(10.0f);//10.0f就是doc的boost
//查询的时候设置boost
查询的时候,只需在关键词后加上^10,这样就可设置权重,
比如:title:人民^10 表示title中匹配“人民”的记录,需要升高权重
2、boost设置原理
那么boost是如何影响lucene得分的呢?
lucene 得分公式如下:
score(q,d) =coord(q,d) queryNorm(q) ∑( tf(t in d) · idf(t)2 · t.getBoost() · norm(t,d) )t in q
其中:
t:Term,一个查询词,这里的Term是指包含域信息的Term,也即title:hello和content:hello是不同的Term
d:doc,一个文档
f:field
coord(q,d):一次搜索可能包含多个搜索词,而一篇文档中也可能包含多个搜索词,此项表示,当一篇文档中包含的搜索词越多,则此文档则打分越高。
queryNorm(q):计算每个查询条目的方差和,此值并不影响排序,而仅仅使得不同的query之间的分数可以比较。其公式是:
public float queryNorm(float sumOfSquaredWeights) {
return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
},而
public float sumOfSquaredWeights() {
//除了用户指定的boost以外,其他都不计算在打分内
queryWeight = getBoost();
return queryWeight * queryWeight;
}
tf(t in d):Term t在文档d中出现的词频
idf(t):Term t在几篇文档中出现过
norm(t,d) = doc.getBoost() · lengthNorm(field) · ∏field.getBoost()
field f in d
norm(t,d)包括三个参数(都可以在自己的Similarity中影响打分,需要自己实现similarity):
Document boost:此值越大,说明此文档越重要。
Field boost:此域越大,说明此域越重要。
lengthNorm(field) = (1.0 / Math.sqrt(numTerms)):一个域中包含的Term总数越多,也即文档越长,此值越小,文档越短,此值越大。
各类Boost值:
t.getBoost():term的boost,查询语句中每个词的权重,可以在查询中设定某个词更加重要,common^4 hello
d.getBoost():doc的boost,文档权重,在索引阶段写入nrm文件,表明某些文档比其他文档更重要。
f.getBoost():field的boost,域的权重,在索引阶段写入nrm文件,表明某些域比其他的域更重要。
当然,也可以在添加Field的时候,设置Field.Index.ANALYZED_NO_NORMS或Field.Index.NOT_ANALYZED_NO_NORMS,完全不用norm,来节约空间。
没有norms意味着索引阶段禁用了文档boost和域的boost及长度标准化。好处在于节省内存,不用在搜索阶段为索引中的每篇文档的每个域都占用一个字节来保存norms信息了。
但是对norms信息的禁用是必须全部域都禁用的,一旦有一个域不禁用,则其他禁用的域也会存放默认的norms值。因为为了加快norms的搜索速度,Lucene是根据文档号乘以每篇文档的norms信息所占用的大小来计算偏移量的,中间少一篇文档,偏移量将无法计算。也即norms信息要么都保存,要么都不保存。