背景

读者提问: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多字段权重排序居然可以这么玩的更多相关文章

  1. elasticsearch简介和倒排序索引介绍

    介绍 我们为什么要用搜索引擎?我们的所有数据在数据库里面都有,而且 Oracle.SQL Server 等数据库里也能提供查询检索或者聚类分析功能,直接通过数据库查询不就可以了吗?确实,我们大部分的查 ...

  2. DEDECMS5.7 首页和栏目页调用文章按权重排序

    dedecms 5.7版本已增加按权重排序功能: [arclist]标签增加按权重排序,在后台管理DEDE里找到以下目录\include\taglib中的arclist.lib.php文件并打开 大约 ...

  3. solr入门之权重排序方法初探之使用edismax改变权重

    做搜索引擎避免不了排序问题,当排序没有要求时,solr有自己的排序打分机制及sorce字段 1.无特殊排序要求时,根据查询相关度来进行排序(solr自身规则) 2.当涉及到一个字段来进行相关度排序时, ...

  4. SQLServer 2008 R2 对同时含有数字和中文的字段进行排序

    若是数据库中的某一个字段名为bedNO,类型为nvchar,里面有{1,2,3,11,12,23,加2,加3}这些数据. 此时我需要对这些数据进行排序,数字按大小拍前面,汉字按第一个字拼音首字母的顺序 ...

  5. dedecms 按权重排序不准或BUG的处理方法

    dede:list 的方法 1.找到"根目录\include\arc.listview.class.php"文件. 2.修改代码:在文件第727行处添加按weight排序判断代码( ...

  6. SQL 按特定字段值排序

    SQL 按特定字段值排序的代码,有需要的朋友可以参考下. id, name shandong01 name1 shandong02 name2 shandong03 name3 beijing01 n ...

  7. LINQ找出重复和不重复的元素及linq OrderBy 方法 两个字段同时排序有关问题

    //重复元素:3,4,5 //不重复元素:1,8,9 , , , , , , , , , , }; //不重复元素 var unique = arr.GroupBy(i => i) .Where ...

  8. SQL按照指定顺序对字段进行排序

    SqlServer按照指定顺序对字段进行排序 问题如下,在SqlServer有一个这样的SQL查询 SELECT *FROM ProductWHERE ID IN ( 12490, 12494, 12 ...

  9. DedeCMS让{dede:list}标签支持weight权重排序

    1.找到"根目录\include\arc.listview.class.php"文件. 2.修改代码:在文件第727行处添加按weight排序判断代码(红色部分为新添加代码). / ...

随机推荐

  1. 记一次针对静态页面的DDOS基本防护

    可以说是我试图进入安全口的天才第一步了,能走多远鬼知道呢 背景 去年年前接到的一个外包项目,是一个base在日本的中国人留学机构做的静态页面.出于锻炼自己的目的,选择为他们按次结薪做长期服务维护.20 ...

  2. 解决SyntaxError: Non-UTF-8 code starting with '\xbb'问题

    在第一行加入 # coding=utf-8 2020-06-13

  3. 再见了Antirez永远的Redis之神

    其实antirez(Redis作者)退出Redis维护一发布我就在很多咨询网站上面看到了,当时也没太多感慨. 今天比较有空想去看看霉霉Twitter的,然后看到了antirez,我就又一次回顾了他的退 ...

  4. PHP is_iterable() 函数

    is_iterable() 函数用于检测变量的是否是一个可迭代的值. PHP 版本要求: PHP 7 >= 7.1.0高佣联盟 www.cgewang.com 语法 bool is_iterab ...

  5. Skill 脚本演示 ycSchReGrid.il

    https://www.cnblogs.com/yeungchie/ ycSchReGrid.il 修复 schematic 或 schematicSymbol 视图中 offGrid 的问题. 回到 ...

  6. react-ts模板/脚手架

    react-ts-template 脚手架 使用 npm i -g maple-react-cli maple-react-cli init 选择模板 'react-ts-template' 输入自定 ...

  7. DataGrip,一款数据库客户端工具,IDEA的兄弟是真香!

    DataGrip 是一款数据库管理客户端工具,方便的连接到数据库服务器,执行sql语句.创建表.创建索引以及导出数据等. DataGrip 支持几乎所有主流的关系数据库产品,如 DB2.Derby.H ...

  8. CAS(乐观锁)以及ABA问题

    https://blog.csdn.net/wwd0501/article/details/88663621独占锁是一种悲观锁,synchronized就是一种独占锁:它假设最坏的情况,并且只有在确保 ...

  9. 事件 - DOM编程

    何为 DOM 事件,HTML DOM 使JavaScript 有能力对 HTML 事件做出反应. 1. 事件流 一个 DOM 事件可以分为捕获过程.触发过程.冒泡过程. 下面一个<a>元素 ...

  10. 用 cgo 生成用于 cgo 的 C 兼容的结构体

    假设(并非完全假设,这里有 demo)你正在编写一个程序包,用于连接 Go 和其它一些提供大量 C 结构体内存的程序.这些结构可能是系统调用的结果,也可能是一个库给你提供的纯粹信息性内容.无论哪种情况 ...