原理 算法
作搜索时,高亮是很常见的需求,那么Solr确定也为高亮提供了支持。先解释下Solr高亮的原理,在咱们设置了须要高亮显示的Field以后,查询获得的返回结果会多出来下面的内容: 数据库
周杰伦
其实就是多了highlighting的字段,并无改变原来返回的字段内容。 apache
Json串是使用 Unique Field :{高亮显示的内容}的形式。 函数
SolrJ有三种高亮类型: url
若是要对某field作高亮显示,必须对该field设置stored=true spa
Standard Highlighter,根据查询的docIdSet,获取Documents,并获取当前document的须要高亮的field的value,根据query的term和该field的value作匹配算法
FastVector Highlighter,效率比普通的高亮显示要高;须要定义termvector(占用空间和IO),包括position和offset,根据query term的termvector到field value中作快速的定位标记,进而实现快速的高亮显示
Postings Highlighter,因为高亮显示须要对field设置为store=true,全部对于单节点数据量比较大而且该字段比较大的话,会消耗大量的IO操做,那么能够把该字段存储在另外的地方,好比Hbase,在外部作高亮显示的匹配。 code
其中推荐使用的是Standard Highlighter,下面也是针对Standard Highlighter, xml
配置 排序
下面介绍两种配置方式:ip
1.SolrJ配置:
songQuery.setHighlight(); songQuery.set("hl.highlightMultiTerm","true");songQuery.setHighlightSimplePre("<font style=\"color:#A7D043;font-weight:bold;\">"); songQuery.setHighlightSimplePost("</font>");
2.solrConfig.xml配置:
explicit 10 text true content 50 font color=red /font
详细的RequestHandler配置请参看博客:五、SolrJ、Request Handler
其实这两种配置并无本质上的区别。我我的习惯使用SolrJ配置。
解析
获取highlighting是很是简单的,一条语句搞定:
Map<String,Map<String,List<String>>> tempMap = response.getHighlighting();
相信你们也注意到了,虽然接受结果简单,可是若是想遍历就比较复杂了,由于接受到的结果是嵌套了不少层的类型Map<String,Map<String,List<String>>>
那么我这边把我解析的方法分享下:
Map<String,Map<String,List<String>>> tempMap =(Map.Entry<String, Map<String,List<String>>>(Integer.parseInt(entry.getKey()) ==(Map.Entry<String, List<String>>( != entryLayer2.getKey() && "Song_Name"( != entryLayer2.getKey() && "Song_SingerName"
这个方法比Iterator和foreach效率稍高。
我设置了两个字段须要高亮,因此在循环中判断了高亮是属于哪一个字段,以后进行相应的操做。
由于我作的时候,一首歌可能有几个Song_SingerName,在数据库中用"/"分隔,因此这种状况更加复杂,我首先是把后缀中的/换成了出现几率很小的@
songQuery.setHighlightSimplePost("<@font>");
而后再用split("@")分隔出不一样的Song_SingerName,可是这样就会有一个问题,就是我不知道高亮的歌手究竟是哪个歌手,因此这个时候,我还须要从分割后的String[]中提取全部的中文字符,比对后,存入另外一个变量,最后再用"/"替换掉"@"。
概念
Solr底层依然用的是Lucene的权重算法,也就是经过一个公式计算每一个Documents的得分,而后按得分高低排序,公式以下:
简单解释下这个公式中包含的一些因子:
Tf:Term frequency,就是条目出现的次数。
Idf: Inverse document frequency,就是用来描述在一个搜索关键字中,不一样字词的稀有程度。好比搜索The Cat in the Hat,那么很明显The和in远没有Cat和Hat重要。
Boosting:这个使咱们设置权重的重点,好比搜索歌手名,那么在一个document中还有歌手的ID、歌曲的清晰度、歌曲上传时间,而boosting是不一样的Filed有不一样权重,以后根据公式计算得分。因此能够看到,咱们并不能直接影响solr搜索结果的排序,须要改变权重,进而改变不一样Document的得分,从而影响排序。
其中还有不少因子和公式的解释,有兴趣的同窗能够参考Solr in action这本书,里面有比较详细的解释。
由于咱们只需简单的根据某一Filed的权重影响结果的排序,因此咱们须要改变Document的Boosting,那么就须要用到Dismax,Dismax是一个查询解析器(Query parser),查询解析器的概念就是提供了一系列查询的参数,一旦咱们在查询url中设置了相应的参数,那么查询解析器将会解析查询信息,从而获得搜索结果,其实彻底也能够把查询解析器理解为一个Api,就是提供了相应的方法,咱们设置,以后Solr根据咱们设置的参数进行查询,只不过不一样的Query Parser提供了不一样的参数而已。
一共提供了三种Query Parser
Standard:最经常使用的,而且是默认
Dismax:
Extended Dismax
功能从上至下是逐渐递增的,在大部分状况下,Standard已经能够彻底知足需求,可是由于要使用权重排序,那么须要用到Dismax,具体提供的参数请查看wiki:
https://cwiki.apache.org/confluence/display/solr/The+Standard+Query+Parser
那么首先须要设置Query Parser为Dismax:
songQuery.set("defType","dismax");
以后设置须要查询的Field:
songQuery.set("qf","Song_Name^2 Song_SingerName^0.2");
好比我这里就须要根据用户输入的关键字查询歌手名和歌曲名,以后返回这两个Field命中的结果、多个Query Filed中能够设置不一样的权重,好比Song_Name的权重就为2,必须注意,在Solr权重的设置中,全部权重标准为1,意思是当权重设置大于1时,表明这个字段的权重变大,若是权重设置小于1而且大于0的时候,表明这个字段权重变小。
以后设置其它Field的权重:
songQuery.set("bf", "sum(div(Song_Quality,0.01),if(exists(Song_FileMV),20000,0),recip(ms(NOW,Song_CreateTimeForNew),1,10000,1))");
这里面用到了不少Function Query,好比div,表明相除、exists表明若是Song_FileMV若是不为空那么设置它的权重为20000,为空则为0。记住最后要sum起来,由于从上面的公式能够看出来,boosting是一个变量,因此最好要有一个和值。相关的函数请参考wiki: