哇,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),是不是方便的多。
关于作者:尹吉欢,简单的技术爱好者,《Spring Cloud 微服务-全栈技术与案例解析》, 《Spring Cloud 微服务 入门 实战与进阶》作者, 公众号猿天地发起人。
我整理了一份很全的学习资料,感兴趣的可以微信搜索「猿天地」,回复关键字 「学习资料」获取我整理好了的 Spring Cloud,Spring Cloud Alibaba,Sharding-JDBC 分库分表,任务调度框架 XXL-JOB,MongoDB,爬虫等相关资料。
哇,ElasticSearch多字段权重排序居然可以这么玩的更多相关文章
- elasticsearch简介和倒排序索引介绍
介绍 我们为什么要用搜索引擎?我们的所有数据在数据库里面都有,而且 Oracle.SQL Server 等数据库里也能提供查询检索或者聚类分析功能,直接通过数据库查询不就可以了吗?确实,我们大部分的查 ...
- DEDECMS5.7 首页和栏目页调用文章按权重排序
dedecms 5.7版本已增加按权重排序功能: [arclist]标签增加按权重排序,在后台管理DEDE里找到以下目录\include\taglib中的arclist.lib.php文件并打开 大约 ...
- solr入门之权重排序方法初探之使用edismax改变权重
做搜索引擎避免不了排序问题,当排序没有要求时,solr有自己的排序打分机制及sorce字段 1.无特殊排序要求时,根据查询相关度来进行排序(solr自身规则) 2.当涉及到一个字段来进行相关度排序时, ...
- SQLServer 2008 R2 对同时含有数字和中文的字段进行排序
若是数据库中的某一个字段名为bedNO,类型为nvchar,里面有{1,2,3,11,12,23,加2,加3}这些数据. 此时我需要对这些数据进行排序,数字按大小拍前面,汉字按第一个字拼音首字母的顺序 ...
- dedecms 按权重排序不准或BUG的处理方法
dede:list 的方法 1.找到"根目录\include\arc.listview.class.php"文件. 2.修改代码:在文件第727行处添加按weight排序判断代码( ...
- SQL 按特定字段值排序
SQL 按特定字段值排序的代码,有需要的朋友可以参考下. id, name shandong01 name1 shandong02 name2 shandong03 name3 beijing01 n ...
- LINQ找出重复和不重复的元素及linq OrderBy 方法 两个字段同时排序有关问题
//重复元素:3,4,5 //不重复元素:1,8,9 , , , , , , , , , , }; //不重复元素 var unique = arr.GroupBy(i => i) .Where ...
- SQL按照指定顺序对字段进行排序
SqlServer按照指定顺序对字段进行排序 问题如下,在SqlServer有一个这样的SQL查询 SELECT *FROM ProductWHERE ID IN ( 12490, 12494, 12 ...
- DedeCMS让{dede:list}标签支持weight权重排序
1.找到"根目录\include\arc.listview.class.php"文件. 2.修改代码:在文件第727行处添加按weight排序判断代码(红色部分为新添加代码). / ...
随机推荐
- Python编程语言简介
Python诞生于20世纪90年代初,由荷兰人吉多·范罗苏姆发明.那么,Python这一门编程语言是如何发明的呢?这之中又有怎么的故事呢?请看下面. 故事发生在1989年的圣诞节上,吉多先生为了打发无 ...
- isinstance方法判断可迭代和迭代器
from collections import Iterable print(isinstance([],Iterable)) print(isinstance( {}, Iterable)) pri ...
- SUM and COUNT -- SQLZOO
SUM and COUNT 注意:where语句中对表示条件的需要用单引号, 下面的译文使用的是有道翻译如有不正确,请直接投诉有道 01.Show the total population of th ...
- PHP fread() 函数
定义和用法 fread() 函数读取打开的文件. 函数会在到达指定长度或读到文件末尾(EOF)时(以先到者为准),停止运行. 该函数返回读取的字符串,如果失败则返回 FALSE. 语法 string ...
- P3239 [HNOI2015]亚瑟王 期望 dp
LINK:亚瑟王 Saber!Excalibur! 比较难的期望dp. 可以发现如果暴力枚举所有的局面复杂度很高 . 转换的思路则是 期望的线性性. 求出每张牌的期望累加即可. 考虑每张牌的期望=这张 ...
- SET DYNAMICS 365 COLORS AND LOGO USING THEMES
https://carldesouza.com/dynamics-365-colors-logo-themes/ BEFORE WE START, I NEED YOUR HELP. I AM SPE ...
- django--各个文件的含义
当你创建项目或者应用后你是不是发现多了很多个文件,现在我们来看看各代表什么意思 与你项目名相同的文件夹:是项目的管理功能目录,这个目录的名称因用户所创建的项目名称的不同而不同 在该目录下还有四个文件: ...
- 25-Object类的使用
1.java.lang.Object类的说明: * 1.Object类是所Java类的根父类 * 2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object ...
- Python环境搭建、python项目以docker镜像方式部署到Linux
Python环境搭建.python项目以docker镜像方式部署到Linux 本文的项目是用Python写的,记录了生成docker镜像,然后整个项目在Linux跑起来的过程: 原文链接:https: ...
- 【av68676164(p38-p40)】进程调度
6.1 进程调度概念 进程调度 在合适的时候以一定策略选择一个就绪进程运行 进程调度的目标 响应速度尽可能快 进程处理的时间尽可能短 系统吞吐量尽可能大 资源利用率尽可能高 对所有进程要公平 避免饥饿 ...