ElasticSearch[八]:自定義評分
一、適用的場景
- 基本介紹
ES 的使用中,ES 會對我們匹配文檔進行相關(guān)度評分。但對于一些定制化的場景,默認評分規(guī)則滿足不了我們的要求。這些定制化場景,ES 也是推出了自定義評分方式來進行支持??梢允褂?ES 提供的一些函數(shù),什么可以使用較分來讓我們的評分規(guī)則多樣化。我舉個大家都很熟悉的場景,在點外賣時候,大家是不是有一個綜合排序,比如用戶希望通過距離和價格來進行綜合排序,這在 mysql 中是不是比較難以實現(xiàn),接下來我將由簡到繁的來教你如何在 ES 中實現(xiàn)這種綜合評分排序的功能
1.1 使用場景
1.1.1 根據(jù)價格評分排序
在 mysql 中我們可以通過價格從高到低,從低到高排序,但是像訂酒店那樣,用戶有期望價格的,酒店越符合用戶的期望價格,評分越高。mysql 的排序這時候是不是有點捉襟見肘了。廢話不多說了,直接來 ES 實現(xiàn)。
{
"from": 0,
"size": 12,
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"term": {
"price": {
"value": 50,
"boost": 1.0
}
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
},
"functions": [
{
"filter": {
"match_all": {
"boost": 1.0
}
},
"gauss": {
"price": {
"origin": 50,
"offset": 0,
"scale": "25",
"decay": 0.5
}
}
}
]
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
]
}
1.1.2 根據(jù)距離評分排序
在我們?nèi)粘J褂玫膱鼍?,我們?jīng)常有需要根據(jù)距離來進行排序評分,常見的 App 中都是有一個距離更近,來篩選商戶。接下來就來看看 ES 的實現(xiàn)。
{
"from": 0,
"size": 12,
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"term": {
"price": {
"value": 50,
"boost": 1.0
}
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
},
"functions": [
{
"filter": {
"match_all": {
"boost": 1.0
}
},
"gauss": {
"location": {
"origin": {
"lon": 130.380857,
"lat": 31.112834
},
"offset": 0,
"scale": "150km",
"decay": 0.5
}
}
}
]
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
]
}
1.1.3 根據(jù)距離價格綜合評分排序
上面舉例了兩個單一的場景,要么是價格,要么是距離,那如果想實現(xiàn)復(fù)雜點的場景呢,希望通過距離和價格綜合排序。比如用戶希望訂一個距離虹橋火車站近的,價格 200 左右的酒店。廢話不多說,直接看實現(xiàn)。
{
"from": 0,
"size": 12,
"query": {
"function_score": {
"query": {
"match_all": {
"boost": 1.0
}
},
"functions": [
{
"filter": {
"match_all": {
"boost": 1.0
}
},
"gauss": {
"location": {
"origin": {
"lon": 130.380857,
"lat": 31.112834
},
"scale": "150km",
"decay": 0.5
},
"multi_value_mode": "MIN"
},
"weight": 1
},
{
"filter": {
"match_all": {
"boost": 1.0
}
},
"gauss": {
"price": {
"origin": 200,
"offset": 0,
"scale": "25",
"decay": 0.5
}
},
"weight": 2
}
],
"score_mode": "sum",
"boost_mode": "replace",
"max_boost": 3.4028235E38,
"boost": 1.0
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
]
}
1.1.4 自定義編寫腳本
像上面都是 ES 提供給我們現(xiàn)成的功能函數(shù),但是,用戶的場景千千萬,總有一個場景這些函數(shù)會不適合。比如,用戶希望酒店的價格的結(jié)尾含 8 的評分更高呢。ES 提供的這些函數(shù)就不起作用了,但 ES 還提供了終極密法。你可以自定義腳本來決定每個文檔的分數(shù)。
{
"from": 0,
"size": 12,
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"term": {
"price": {
"value": 50,
"boost": 1.0
}
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
},
"functions": [
{
"filter": {
"match_all": {
"boost": 1.0
}
},
"script_score": {
"script": {
"source": "doc['price'].size()==0?0:5",
"lang": "painless"
}
}
}
],
"score_mode": "sum",
"boost_mode": "replace",
"max_boost": 3.4028235E38,
"boost": 1.0
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
]
}
二、常用的字段解釋
- 整體結(jié)構(gòu)
如果需要使用自定義評分,評分查詢結(jié)構(gòu)和正常的查詢結(jié)構(gòu)還是有些區(qū)別的, 分頁和排序和正常的都是一樣的,主要還是 query 內(nèi)的成員,使用的是 function_score。我們來看看圖上圖框住的就是自定義評分需要使用的特定的查詢結(jié)構(gòu)??纯蠢锩媸遣皇沁€有很多成員,接下來我一一為大家介紹這些成員的含義。
2.1 function_score
2.1.1 query
function_score 第一個成員 query,這個就和大家平時用的一樣,篩選符合條件的結(jié)果,并把這個結(jié)果用作后面的評分函數(shù)的數(shù)據(jù)來源,我們來看看它內(nèi)部的結(jié)構(gòu)。下圖框中,目的是為了查詢 price 為 50 的結(jié)果
2.1.2 functions
functions,也是我們使用評分函數(shù)和編寫腳本的地方,他的值是一個數(shù)組,也就是我們使用多個函數(shù)來進行綜合評分,還可以對每個評分進行權(quán)重控制,主要有以下幾個值
-
filter
filter 主要通過條件匹配結(jié)果作用在當(dāng)前函數(shù)上
-
weight
weight 當(dāng)前函數(shù)的權(quán)重,函數(shù)的分值會乘上 weight
-
ES 提供的幾種評分模式,是腳本還是隨機等
1. 衰減函數(shù):
先看看官方的圖,衰減函數(shù)的作用機制, 我們可以設(shè)定一個期望值,越接近期望值的分越高,分值在 0-1 之間,分別有三條對應(yīng)的函數(shù)曲線 linear 、 exp 和 gauss (線性、指數(shù)和高斯函數(shù))原點(origin):期望值,這個值可以得到滿分(1.0)
偏移量(offset):與原點相差在偏移量之內(nèi)的值也可以得到滿分
衰減規(guī)模(scale):當(dāng)值超出了原點到偏移量這段范圍,它所得的分數(shù)就開始進行衰減了,衰減規(guī)模需配合衰減值一起使用。比如衰減規(guī)模是 500 米,衰減值是 0.5,那么在 500 米的時候分值就是 0.5,具體衰減速率由函數(shù)曲線決定
衰減值(decay):該字段可以被接受的值(默認為 0.5),相當(dāng)于一個分界點,具體的效果與衰減的模式有關(guān)2. script_score:自定義腳本評分, 主要就是我們編寫腳本的地方
值 | 描述 |
---|---|
source | 就是我們需要填寫腳本的地方 |
lang | 使用的腳本語言,幾個可選值對應(yīng)相應(yīng)的開發(fā)語言 |
3. random_score:隨機得到 0 到 1 分數(shù)
4. field_value_factor:將某個字段的值進行計算得出分數(shù)。
2.1.3 score_mode
score_mode,主要是控制我們多個評分函數(shù)之間如何運算的,比如 function_score 第一個元素會對結(jié)果進行評分,第二元素也會對結(jié)果進行評分,我們通過參數(shù)來控制這兩個的評分是相加還是別的操作,這最終得出來的分值也稱為功能分值。有以下幾個可選值
函數(shù)名 | 描述 |
---|---|
max | 使用最高分 |
first | 使用第一個評分函數(shù)的分值 |
multiply | 多個評分函數(shù)分值相乘(默認) |
avg | 多個評分函數(shù)分值的平均值 |
sum | 多個評分函數(shù)分值的分數(shù)和 |
min | 使用最小分 |
2.1.4 boost_mode
boost_mode,控制的是查詢分值(下圖框起來的 1 的部分)和功能分值(下圖框起來的 2 的部分)是如何運算的。有以下幾個可選值
函數(shù)名 | 描述 |
---|---|
max | 使用查詢分數(shù)和功能分數(shù)里最大值 |
replace | 使用功能分數(shù),查詢分數(shù)將被忽略 |
multiply | 使用查詢分數(shù)和功能分數(shù)相乘(默認) |
avg | 使用查詢分數(shù)和功能分數(shù)平均值 |
sum | 使用查詢分數(shù)和功能分數(shù)和 |
min | 使用查詢分數(shù)和功能分數(shù)里最小值 |
三、通過 ESJavaApi 實現(xiàn)自定義評分功能
public static void main(String[] args) {
/**構(gòu)建functions**/
FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[2];
//第一個評分函數(shù),gauss
Map<String, Double> locationMap = new HashMap<String, Double>();
locationMap.put("lat", 130.11);
locationMap.put("lon", 12.12);
ScoreFunctionBuilder gaussFunctionByLocation = ScoreFunctionBuilders.gaussDecayFunction("location", locationMap, "150km", 0, 0.5);
filterFunctionBuilders[0] = new FunctionScoreQueryBuilder.FilterFunctionBuilder(gaussFunctionByLocation);
//第二個評分函數(shù),自定義評分
String scriptLang = "painless";
String script = "doc['price'].size()==0?0:5";
ScriptScoreFunctionBuilder scriptFunction = ScoreFunctionBuilders.scriptFunction(new Script(Script.DEFAULT_SCRIPT_TYPE, scriptLang, script, Collections.emptyMap(), Collections.emptyMap()));
filterFunctionBuilders[1] = new FunctionScoreQueryBuilder.FilterFunctionBuilder(scriptFunction);
/**function_score**/
//構(gòu)建query
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//設(shè)置query,functions
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(boolQueryBuilder, filterFunctionBuilders);
//設(shè)置boostMode
functionScoreQueryBuilder.boostMode(CombineFunction.REPLACE);
//設(shè)置scoreMode
functionScoreQueryBuilder.scoreMode(FunctionScoreQuery.ScoreMode.SUM);
//設(shè)置分頁排序
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.from(0);
sourceBuilder.size(12);
sourceBuilder.sort("price", SortOrder.ASC);
//執(zhí)行
SearchRequest searchRequest = new SearchRequest("index_name");
searchRequest.source(sourceBuilder);
}
參考鏈接:
https://blog.csdn.net/qq_51641196/article/details/130074051?spm=1001.2014.3001.5502文章來源:http://www.zghlxwxcb.cn/news/detail-820889.html
https://blog.csdn.net/W2044377578/article/details/128636611文章來源地址http://www.zghlxwxcb.cn/news/detail-820889.html
到了這里,關(guān)于ElasticSearch[八]:自定義評分功能、使用場景講解以及 function_score常用的字段解釋的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!