哇,ElasticSearch多欄位權重排序居然可以這麼玩
背景
讀者提問:ES 的權重排序有沒有示列,參考參考?
剛好之前也稍微接觸過,於是寫了這篇文章,可以簡單參考下。
在很多複雜的業務場景下,排序的規則會比較複雜,單一的降序,升序無法滿足日常需求。不過 ES 中提供了給文件加權重的方式來排序,還是挺好用的。
首先初始化三條測試資料,方便檢視效果:
{
id: 1,
title: "Java怎麼學",
type: 3,
userId: 1,
tags: [
"java"
],
textContent: "我要學Java",
status: 1,
heat: 80
}
{
id: 2,
title: "Java怎麼學",
type: 2,
userId: 1,
tags: [
"java"
],
textContent: "我要學Java",
status: 1,
heat: 99
}
{
id: 3,
title: "Java怎麼學",
type: 1,
userId: 1,
tags: [
"java"
],
textContent: "我要學Java",
status: 1,
heat: 100
}
type:1 為翻譯,2 為轉載,3 為原創
需求是查詢 userId=1 的所有文章,按照熱度降序排序,但是原創型別的文章要顯示在前面,優先順序高於熱度。
如果我們簡單的按照熱度排序的話,那麼順序肯定是 id 為 3(熱度:100),2(熱度:99),1(熱度:80)這樣排列的。
但是原創型別的要在前面,那麼結果應該是 1(熱度:80,型別:原創),3(熱度:100,型別:翻譯),2(熱度:99,型別:轉載)。
排序條件肯定是以熱度來進行的,這個是肯定的。唯一需要處理的就是怎麼將原創型別的排在前面,如果只考慮實現,方式還是有很多種的。
比如:原創型別的熱度值可以調的比較高,但是呢,熱度值要重新弄一個欄位,只用於排序,給使用者展示的還是之前的熱度值,這樣排序就簡單了,還是根據熱度排就可以實現效果。
weightFactorFunction
在 ES 搜尋結果中_score 這個欄位相信大家並不陌生,這是 ES 給出的評分,我們可以根據評分來排序,然後將原創型別的評分提高就可以實現想要的效果。
直接看 Java 程式碼吧,透過 FunctionScoreQueryBuilder 來構建查詢。
@Test
public void testSort() {
FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("type", 3), ScoreFunctionBuilders.weightFactorFunction(100)),
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("type", 2), ScoreFunctionBuilders.weightFactorFunction(1)),
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("type", 1), ScoreFunctionBuilders.weightFactorFunction(1))
};
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.must(QueryBuilders.termQuery("userId", 1));
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQuery, filterFunctionBuilders);
searchSourceBuilder.query(functionScoreQueryBuilder)
.sort("_score", SortOrder.DESC)
.sort("heat", SortOrder.DESC);
SearchRequest searchRequest = new SearchRequest(elasticSearchIndexConfig.getArticleSearchIndexName());
searchRequest.types(EsConstant.DEFAULT_TYPE);
searchRequest.source(searchSourceBuilder);
List<ArticleDocument> searchResults = kittyRestHighLevelClient.search(searchRequest, ArticleDocument.class);
searchResults.forEach(doc -> {
System.out.println(doc.getId() + "\t" + doc.getType() + "\t" + doc.getHeat());
});
}
透過 ScoreFunctionBuilders.weightFactorFunction 為文章型別設定對應的權重,原創文章權重為 100,其他的都為 1,這樣原創文章的得分就高於其他型別的文章。
在排序的時候優先得分排序,然後熱度排序。就可以得到我們想要的結果了。
scriptFunction
除了使用 weightFactorFunction 來設定權重,另外介紹一種靈活度更高,適用於更復雜的排序場景的方式 scriptFunction。
scriptFunction 允許我們透過指令碼的方式來實現權重,直接看程式碼:
@Test
public void testSort() {
String scoreScript = "if (doc['type'].value == 3) {" +
" return 100;" +
"} else {" +
" return 1;" +
"}";
FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchAllQuery(), ScoreFunctionBuilders.scriptFunction(new Script(scoreScript)))
};
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.must(QueryBuilders.termQuery("userId", 1));
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQuery, filterFunctionBuilders);
searchSourceBuilder.query(functionScoreQueryBuilder)
.sort("_score", SortOrder.DESC)
.sort("heat", SortOrder.DESC);
SearchRequest searchRequest = new SearchRequest(elasticSearchIndexConfig.getArticleSearchIndexName());
searchRequest.types(EsConstant.DEFAULT_TYPE);
searchRequest.source(searchSourceBuilder);
List<ArticleDocument> searchResults = kittyRestHighLevelClient.search(searchRequest, ArticleDocument.class);
searchResults.forEach(doc -> {
System.out.println(doc.getId() + "\t" + doc.getType() + "\t" + doc.getHeat());
});
}
scoreScript 就是控制權重的指令碼,也就是一段程式碼(指令碼預設是 groovy),是不是方便的多。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31561268/viewspace-2714690/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ElasticSearch多欄位權重排序居然可以這麼玩Elasticsearch排序
- Spring MVC @SortDefault多欄位排序SpringMVC排序
- Elasticsearch 單字串多欄位查詢Elasticsearch字串
- [Elasticsearch] 多欄位搜尋 (二) - 最佳欄位查詢及其調優(轉)Elasticsearch
- vxe-table grid 使用服務端排序、多欄位排序服務端排序
- PHP陣列多個欄位分別排序PHP陣列排序
- 快排實現仿order by多欄位排序排序
- 請教一下 多欄位值如何排序?排序
- Java stream sorted使用 Comparator 進行多欄位排序Java排序
- Elasticsearch 複合查詢——多字串多欄位查詢Elasticsearch字串
- mysql多表多欄位查詢並去重MySql
- MySQL多列欄位去重的案例實踐MySql
- 居然可以像玩遊戲一樣學Git遊戲Git
- vue.js除了動態路由,前端許可權還可以這麼玩Vue.js路由前端
- MySQL VARCHAR型別欄位到底可以定義多長MySql型別
- WiFi 網路也可以這麼玩WiFi
- C# 實現list=list.OrderBy(q=>q.欄位名).ToList(); 按多個欄位排序C#排序
- 用Elasticsearch做大規模資料的多欄位、多型別索引檢索Elasticsearch多型型別索引
- 查詢/刪除重複的資料(單個欄位和多個欄位條件)
- 這。。這。。C++標頭檔案居然可以這麼打!!!! 長見識了!!!C++
- SQL字元型欄位按數字型欄位排序實現方法SQL字元排序
- 多欄位登入
- sql根據多個欄位查詢重複記錄SQL
- ElasticSearch 設定某個欄位不分詞Elasticsearch分詞
- 快速排序用C語言可以這麼寫排序C語言
- ElasticSearch7.3學習(二十二)----Text欄位排序、Scroll分批查詢場景解析Elasticsearch排序
- 分散式事務,原來可以這麼玩?分散式
- 原來vue的slot可以這麼玩轉Vue
- ca..原來 stf 還可以這麼玩...
- 下載速度居然可以這麼快,進度條就靠你拯救了!
- 逆向工程通過某個欄位排序排序
- mysql5.6生成排序欄位MySql排序
- [BUG反饋]模型管理 > 欄位管理看不見任何欄位。這表明顯有欄位、!模型
- 將多個JSON欄位對映到單個Java欄位JSONJava
- 欄位按照指定 ID 順序進行排序排序
- Elasticsearch 統計某欄位有值的文件數Elasticsearch
- ElasticSearch搜尋欄位不需要計入得分Elasticsearch
- postgresql單個表可以有多少欄位SQL