Solr dismax 源码详解以及使用方法

类路径
org.apache.solr.search.DisMaxQParserPlugin
org.apache.solr.search.DisMaxQParser
org.apache.solr.common.params.DisMaxParams
实现逻辑:
第一步 从传递过来的参数中获取QF(query fields),同时解析出查询域的boosts;
参数使用:
QF=name^10 description^2
queryFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams(DisMaxParams.QF));
解析结果:
protected Map<String, Float> queryFields;
Key:name,Value:10;
Key:description,Value:2;
第二步 创建主查询
① 将queryFields封装成DisjunctionMaxQueryParser(SolrQueryParser子类,支持aliasing fields,用来构造DisjunctionMaxQueries),封装时还用到了参数QS(查询间距), 参数TIE(tie break,没有使用过,网上找的一个解释,不对请指正);
参数使用:
QS=3
TIE=0.1
相关代码:
float tiebreaker = solrParams.getFloat(DisMaxParams.TIE, 0.0f);
SolrPluginUtils.DisjunctionMaxQueryParser up = getParser(queryFields, DisMaxParams.QS, solrParams, tiebreaker);
② 获取PF(phrase boost fields)同1,将phraseFields封装成DisjunctionMaxQueryParser,同时解析出查询域的boosts,同上也需要查询间距(参数PS), 参数TIE;
相关代码:
Map<String, Float> phraseFields = SolrPluginUtils.parseFieldBoosts(solrParams.getParams(DisMaxParams.PF));
③ 获取用户查询语句并进行校验,删除“"”,转义字符,过滤连续的和多余的+ and/or -;
相关代码:
userQuery=SolrPluginUtils.partialEscape(SolrPluginUtils.stripUnbalancedQuotes(userQuery)).toString();
userQuery=SolrPluginUtils.stripIllegalOperators(userQuery).toString();
④ 将用户查询语句封装成BooleanQuery,关系为SHOULD,并设置参数MM(最小匹配,默认100%)。包括短语查询,关系为SHOULD。如果userQuery为空,则调用ALTQ(q.alt备用查询)语句;
相关代码:
Query dis = up.parse(userQuery);
/**
* 这是用户查询语转换为扁平化的BooleanQuery。
* 貌似应为DisjunctionMaxQueryParser重写了getFieldQuery,
* 递归的解析封装DisjunctionMaxQuery(BooleanQuery的子类)造成的。
*/
SolrPluginUtils.flattenBooleanQuery(t, (BooleanQuery) dis);
第三步 创建提升查询(boost queries)
dismax的bq参数可以用来指定多个查询,类似于automatic phrase boost。以类似的方式被添加到用户的查询中。记住一点,boosting只是用来影响q参数指定的用户查询所匹配到的那些文档的scoring。如果匹配的结果还匹配bq查询,那么这个文档的得分会更高;
参数使用:
BQ=(*:* -r_type:book)^2 //增强所有文档得分,但是除了book
第四步 创建提升功能(boost functions),同上。
dismax的源代码代码实现逻辑比较简单,看起来比较易理解。edismax是它的加强版,改变了不少,听说已经替代了dismax。
参数TIE使用说明
比如有两个field:A和B,query分别在A和B中都能命中,其得分如下:
A     B  max
doc1  0.5  0.8  0.8
doc2  0.8  0.1  0.8
这时候两个doc在不同field上的max得分相同,但是我们其实更希望doc1得分更高
所以这时候采用DisjunctionMaxQuery和tie break参数=0.1
根据算法(score of matching clause with the highest score) + ( (tie paramenter) * (scores of any other matching clauses) )
新的得分为:finalscore: 0.85(doc1) 0.81(doc2)这样就能区分出