如何控制評分
如果設置了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,...) 返回多個函數的和。
-
Example Syntax: sum(x,1)
-
Example Syntax: sum(x,y)
-
Example Syntax: sum(sqrt(x),log(y),z,0.5)
recip
recip(x,m,a,b)實現a/(m * x + b)的互逆函數。 m,a,b是常數,x是任何數字字段或任意復雜的函數。
當a和b相等,x> = 0時,該函數的最大值為1,隨x增加而下降。 將a和b的值增加在一起導致整個功能的移動到曲線的較平坦部分。 這些屬性可以使這成為在x是rord(datefield)時提升更新文檔的理想功能。
-
Example Syntax: recip(rord(creationDate),1,1000,1000)
max
max(x,c) returns the max of another function and a constant. Useful for "bottoming out" another function at some constant.
-
Example Syntax: max(myfield,0)
log
Solr1.3 log(x) returns log base 10 of the function x. 返回函數x的log10。
-
Example Syntax: log(x)
-
Example Syntax: log(sum(x,100))
sqrt
Solr1.3 sqrt(x) returns the square root of the function x返回函數x的平方根
-
Example Syntax: sqrt(2)
-
Example Syntax: sqrt(sum(x,100))
例子2,來自http://www.xuebuyuan.com/323380.html
舉一個例子,電商類網站(比如淘寶)的商品搜索:
1.在商品名稱上出現搜索關鍵字排序靠前,而內容的次之
2.對多皇冠的買家排序靠前等
3.對近期發布的商品排序靠前
4.對最近銷售多商品靠前
綜上獲得一個綜合排名
在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.
-
Example Syntax: div(1,x)
-
Example Syntax: div(sum(x,100),max(y,1))
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:
-
other functions (e.g. map, sum, etc.)
Arguments may _not_ be "classic" date fields
ms()
-
Equivalent to ms(NOW), number of milliseconds since the epoch.
ms(a)
-
Returns the number of milliseconds since the epoch that the argument represents.
Example: ms(NOW/DAY)
-
Example: ms(2000-01-01T00:00:00Z)
-
Example: ms(mydatefield)
Note that this number can be negative for dates from before the epoch.
ms(a,b)
-
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
pf查詢字段,這樣在schema不用制定默認字段
qf對默認查詢增加權重比值,比如標題是content的1.9倍,值越大權重越大
這樣查詢就會計算如下的一個綜合評分值了