如何控制评分
如果设置了sort字段,那么将会按照sort字段的顺序返回结果。
如果没有设置sort字段,那么将会根据相关度打分来排序。也就是说,相关度更高的排在前面。
如何来定制适合自身业务的排序打分规则(boost)呢?经过这段时间的思考与实践,想到了如下三个方法:
1、定制Lucene的boost算法,加入自己希望的业务规则;
2、使用Solr的edismax实现的方法,通过bf查询配置来影响boost打分。
3、在建索引的schema时设置一个字段做排序字段,通过它来影响文档的总体boost打分。
上面每一种方法都有其优劣,下面分析一下各自的优劣。
第一种方法技术难度要求较高,需要读懂Lucene的boost打分算法,在代码层做定制.
第二种方式就简单不少,不过因为受限于edismax提供的方法,所以有些局限性。
第三种排序可完全消除文本相关性打分的影响,文本检索匹配逻辑只负责打到匹配的项,排序由自定义字段处理。
下面重点看edismax的使用:
edismax的理念:
edismax中将查询字段和查询词项分开了,如我们在标准用法中使用name:zjf,那么在edismax中,需要在qf中设置查询字段为name,然后在q中输入zjf,注意这里不能加name了,否则没有结果。
这样设计的结果就是,查询词项会去所有的qf列(query field,可以设置多列,也可以配置为每列配置权重)上进行查询,如果要针对每个字段有不同的查询,如name:zjf,age:30,那么需要将其中一个移入到fq中,但是注意,fq中的查询是不影响评分的。这也是edismax的理念。满足常用的搜索场景。
edismax的常用参数:
q和fq来自标准查询,也经常使用。
edismax扩展的有:
qf:query field。q中的词项要在哪些字段上执行查询。可以设置多列以及每一列的权重。如果没有设置,那么将会使用df默认字段(一般在配置文件中配置好)。
pf:parse field。pf和qf的格式一样。区别是pf会更加注重短语匹配,也就是说如果输入zjf xhj作为查询,那么在配置了pf的字段上,zjf随后出现xhj的文档的评分更高。注意这里只是评分更高,如果想获得更加严格的短语匹配,应该在查询中使用"zjf xhj"。
ps:用于配置pf中的词项的短语间隔。可以控制zjf和xhj之间多少个间隔。
bq:接受一个和q一样的查询,它和q的区别是不影响返回的结果集,只会影响排名。
bf:提升函数,通过数学公式来影响评分,而且不局限在qf中的字段。
mm:最小匹配,如果我们不严格要求AND,可以配置mm来定义查询结果集的匹配程度。
注意:想pf 和qf这种需要查询的字段上,一定要是indexed的。
关于mm
mm可以设置为整数,如2,代表至少匹配两个词项,如果输入词项少于两个,那么要全部匹配才行。
mm可以设为百分比,表示必须匹配到多大的百分比才可以。也可以合并在一起匹配。
如设置为mm="2<50%" 那么如下查询的话:
solr: 只有一个词项,必须全部匹配。
solr is:2个词项,也必须全部匹配。
solr is a:超过两个,按照50%来计算,只需要匹配一个词项就可以。(一个词项占33%,四舍五入到50%)
solr is a serch:必须匹配两个,50%。
edismax列子,以下来自网络
例子1,来自网络。
下面结合最近使用Solr的实践,着重介绍一下通过使用Solr的DisMaxQParserPlugin通过配置来制定结果文档打分规则。
DisMaxQParserPlugin提供在针对文本boost打分上,支持搜索多个schema索引字段,并针对每一个字段设置不同的boost权限。
pf查询 与 qf查询
pf: 可提供对一条记录的多个字段做匹配的功能
qf: 针对查询的每个字段设置不同的boost权重打分,其设置的字段必须为在pf中配置的项。
可在solrconfig.xml中的browse中配置做如下配置:
<requestHandler name="/browse" class="solr.SearchHandler">
<lst name="defaults">
<str name="defType">edismax</str>
<str name="pf">
name info title
</str>
<str name="qf">
name^1 info^0.8 title^0.6
</str>
</lst>
</requestHandler>
上面一段的意思是,查询name,info,title三个字段,每个字段的文本相关度打分分别为1,0.8,0.6。计算查询出的每一条结果的权重方法如下:分别计算各字段的文本打分然后乘于配置的系统,最后三者相加即为该结果的boost得分。
bf查询
除去pf查询,qf查询之外,仍然希望索引记录的其它字段能够计入打分中,这时可以使用bf查询。bf查询支持一些数据函数,这些函数可作用在索引记录的字段上,多为时间,数值等字段。同样bf也支持添加权重。下面是一个使用bf查询配置的例子:
<requestHandler name="/browse" class="solr.SearchHandler">
<lst name="defaults">
<str name="defType">edismax</str>
<str name="bf">
sum(recip(ms(NOW,created_time),3.16e-11,1,1),sqrt(log(max(sales,1))),sqrt(log(count)))^10
</str>
<str name="pf">
name info title
</str>
<str name="qf">
name^1 info^0.8 title^0.6
</str>
</lst>
</requestHandler>
其中sum,recip,ms,sqrt,log,max这些都是Solr提供的数学方法,支持的所有数学方法可在这里查找到:http://wiki.apache.org/solr/FunctionQuery
edismax相关资源:http://wiki.apache.org/solr/DisMaxQParserPlugin
sum
Solr1.3 sum(x,y,...) 返回多个函数的和。
recip
recip(x,m,a,b)实现a/(m * x + b)的互逆函数。 m,a,b是常数,x是任何数字字段或任意复杂的函数。
max
log
Solr1.3 log(x) returns log base 10 of the function x.返回函数x的log10。
sqrt
Solr1.3 sqrt(x) returns the square root of the function x返回函数x的平方根
例子2,来自http://www.xuebuyuan.com/323380.html
在solrconfig.xml的SearchHandler中如下配置
- <requestHandler name="standard" class="solr.StandardRequestHandler" default="true" >
- <lst name="defaults">
- <str name="echoParams">explicit</str>
- <str name="rows">10</str>
- <str name="hl">on</str>
- <str name="hl.fl">name,content</str>
- <str name="f.content.hl.fragsize">200</str>
- <str name="defType">edismax</str>
- <str name="bf">
- sum(recip(ms(NOW,pub_date),1,1,100),div(point,5632000),div(sale_count,1000000))
- </str>
- <str name="pf">
- content
- </str>
- <str name="qf">
- name^1.9
- </str>
- </lst>
- </requestHandler>
div
Solr1.3 div(x,y) divides the function x by the function y.
ms
Returns milliseconds of difference between it's arguments.
Dates are relative to the Unix or POSIX time epoch, midnight, January 1, 1970 UTC.
Arguments may be numerically indexed date fields such as TrieDate (recommended field type for dates since Solr 1.4), or date math (examples in SolrQuerySyntax) based on a constant date or NOW.
Things other than these will _not_ work as arguments. For example, you cannot currently use:
- "classic", non-numerically indexed date fields (i.e. fields backed by DateField or LegacyDateField classes)
- other functions (e.g. map, sum, etc.)
Arguments may _not_ be "classic" date fields
- Returns the number of milliseconds since the epoch that the argument represents.
- Example: ms(2000-01-01T00:00:00Z)
- Example: ms(mydatefield)
Note that this number can be negative for dates from before the epoch.
- Returns the number of milliseconds that b occurs before a (i.e. a - b). Note that this offers higher precision than sub(a,b) because the arguments are not converted to floating point numbers before subtraction.
- Example: ms(NOW,mydatefield)
- Example: ms(mydatefield,2000-01-01T00:00:00Z)
- Example: ms(datefield1,datefield2)
bf用函数计算某个字段的权重,如上例子中pub_date发布日期的权重,point比如诚信指数,sale_count销售数量
bf内字段必须是索引的,bf的函数查看solr api文档 http://wiki.apache.org/solr/FunctionQuery