solr使用自定义排序函数
(2015-08-27 17:53:33)
标签:
股票 |
我们在查询的时候,通过设置q:_val_来实现自定义排序,_val_后面跟自定义的排序函数。
首先来看一下_val_,
举个查询例子为q=title:hadoop _val_:count 这里顺便说下hadoop和_val_中间的空格,由于solr默认是OR,所以这里是一个or组合的booleanQuery,如果是q=title:hadoop
title和count都是solr配置文件schema.xml里面的一个field,title:hadoop很明细,搜索文档的field值包含hadoop的文档。假如
索引库里总共有5个document 1,2,3,4,5,其中doucument 2,5的field包含hadoop值,那title:hadoop搜索到2,5两个document,
_val_:count
由于_val_代表的是functionQuery,由于我们索引库里的每个document都包含count域。所以solr会把所有库里的5个document
ID取到,其实solr是直接读reader.maxDoc(),这里值为5,
由于是OR,solr底层luence会对两者坐并集,然后对并集的doc ID
打分。关键就在这个打分,也是_val_:count的体现。
由于文档2,5在两个集合里都出现,所以,document 2和5的得分也是两个得分之和。title:hadoop返回的文档2和5的得分就是luence的评分公式计算出来的,而_val_:count是有FunctionQuery的内部类FunctionWeight来计算的,不过FunctionWeight计算权重时,idf的值为1,由FunctionWeight计算的值再乘以该document域count的值,所以整个的查询结果是5个document,但是2,5这个两个文档的得分会很高。但跟这个两个文档的count域的值有关。
同样如果是q=title:hadoop
顺便再说下,如果_val_:3这也,后面直接跟数据,solr就不要到索引库里去取指定域如上面count域的值了,而是直接为3,如果是跟field,solr会用到fieldCache,把该域的值取出来放到fieldCache中,下次取就不要再读索引库了。
以上一段来源 http://ronxin999.blog.163.com/blog/static/4221792020111013131992/
接下来我们自己定义一个函数distfunc(sortType,latitude,longitude)来实现根据排序类型,和距离综合排序的算法。
我们使用的solr lucene版本如下:
<</span>dependency> |
自定义函数需要自己实现两个方法分别继承ValueSourceParser和ValueSource,其中ValueSourceParser可以对自定义函数的入参进行解析,ValueSource里面可以自定义打分规则。
我们定义的distfunc(sortType,latitude,longitude)的功能是,根据位置信息和得分信息来进行综合排序。
我们建立索引的时候,自定义了一个存储位置信息的类型TeacherLocation,locations字段存储的是list< TeacherLocation >转化成jackson后的字符串,TeacherLocation如下:
package com.renren.teach.search; public class TeacherLocation { } |
Popularity字段存储的是排序需要考虑的另一个因素,得分信息。
自定义排序规则代码如下:
首先是自定义的TeachValueSourceParser
package com.renren.teach.search; import org.apache.commons.lang.StringUtils; import org.apache.lucene.queries.function.ValueSource; import org.apache.solr.schema.SchemaField; import org.apache.solr.search.FunctionQParser; import org.apache.solr.search.SyntaxError; import org.apache.solr.search.ValueSourceParser; public class TeachValueSourceParser extends ValueSourceParser {//需要继承ValueSourceParser,重写parse方法 //将参数及需要的文档的值传给自定义的ValueSource方法,打分规则在自定义的ValueSource中定制 //该方法是根据字段名,从FunctionQParser得到文档该字段的相关信息 public ValueSource getValueSource(FunctionQParser fp, String arg) { } |
接下来是自定义的DistanceFieldSource
package com.renren.teach.search; import java.io.IOException; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.queries.function.FunctionValues; import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.queries.function.docvalues.FloatDocValues; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; public class DistanceFieldSource extends ValueSource {//需要继承ValueSource ,重写getValues方法 //通过构造方法取得经纬度信息排序类型以及文档的经纬度得分等 //重写floatVal方法,此处为打分排序规则 //与当前位置计算,取最小距离 } |
以上就定义好了distfunc(sortType,latitude,longitude)函数。
将代码打包放到webapp/WEB-INF/lib下,
在solrconfig.xml中加入声明
重启,就可以使用该函数了。
//searchDO为各种查询条件,queryStr为之前构件好的查询条件字符串 SolrQuery query = new SolrQuery(); String distParams = sortType + ","; QueryResponse response = server.query(query); |
妥妥哒~
还有一种使用方式,是在solrconfig.xml里自定义一个requestHandler,在里面使用distfunc方法,然后搜索时Request-Handler设置成自己定义的这个,不过这个最终没搞定怎么使,requestHandler里头好些参数还不清楚怎么配置。