原理 算法
作搜索時,高亮是很常見的需求,那麼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: