最近做新聞推薦系統,新聞搜索采用的是elasticsearch引擎,為了使推薦更接近用戶偏好,搜索時使用了function_score功能對文檔進行了重新打分,改變排序規則。以下介紹關於function score的一些用法。
The function_score allows you to modify the score of documents that are retrieved by a query. This can be useful if, for example, a score function is computationally expensive and it is sufficient to compute the score on a filtered set of documents.(這個是官方對function_score的解釋)
es內置了幾種預先定義好了的函數:
1、weight:對每份文檔適用一個簡單的提升,且該提升不會被歸約:當weight為2時,結果為2 * _score。
2、field_value_factor:使用文檔中某個字段的值來改變_score,比如將受歡迎程度或者投票數量考慮在內。
3、random_score:使用一致性隨機分值計算來對每個用戶采用不同的結果排序方式,對相同用戶仍然使用相同的排序方式。
4、Decay Functions:衰減函數,衰減函數是利用從給定的原點到某個用戶數字類型字段的值的距離的衰減進行打分的。這類似於一個范圍查詢,而且邊緣是光滑的。
es內部支持的衰減函數有gauss(高斯)、exp(指數)、linear(線性)
5、 script_score:使用自定義的腳本來完全控制分值計算邏輯。
推薦系統中有很多個性化的feature權重,所以我們主要采用script_score來對文檔打分。下面主要說一下script_score的使用。
(1)、在es配置中配置腳本功能,配置后重啟服務
script.inline: on
script.enfine.groovy.inline.aggs: on
script.indexed: on
script.file: on
(2)、測試查詢語句,例:
{
"query": {
"function_score": {
"query": {
"bool": {
"should": [
{
"match": {
"title": "航母"
}
}
]
}
},
"score_mode": "first",
"script_score": {
"lang": "groovy",
"params": {
"timestamp": 1460768418541
},
"script": "(_score+ 1/(timestamp-doc['timestamp'].value.toDouble()+1))/2"
},
"boost_mode": "replace"
}
}
}
查詢結果中可以看到每條文檔數據的分值 例:"_score": 0.5103256,
(3)、java查詢代碼 queryBuilder:
Map<String,Object> params = new HashMap<String,Object>();
params.put("timestamp",1460768428541L);
FunctionScoreQueryBuilder query =
QueryBuilders.functionScoreQuery(QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("title", "航母"))
).add(ScoreFunctionBuilders.scriptFunction(
new Script("(_score + 1/(timestamp-doc['timestamp'].value.toDouble()+1))/2"
,ScriptType.INLINE,"groovy",params))
).scoreMode("first")
.boostMode(CombineFunction.REPLACE);
"script_score": {
"lang": "groovy",
"params": {
"timestamp": 1460768418541
},
"script": "(_score+ 1/(timestamp-doc['timestamp'].value.toDouble()+1))/2"
},
以上這部分就是腳本函數打分的一個實現。lang表示選用的腳本語言,這里我們選用groovy(es配置,默認groovy);params是腳本函數需要的參數;script是函數語句(參照groovy語法)