背景

读者提问: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. encode 和 decode 的使用

    txt = '我是字符串' txt_encode = txt.encode() print(txt) # 我是字符串 print(txt_encode) # b'\xe6\x88\x91\xe6\x9 ...

  2. MOS 预夹断到底是什么

    https://www.cnblogs.com/yeungchie/ MOS管就像一个开关,栅极(Gate)决定源极(Souce)到漏极(Drain)的沟道(Channel)是开还是关.以NMOS为例 ...

  3. JavaScript正则表达式相关方法

    一.正则表达式方法 var str="abcdefabcdef"; (1)reg.test(str); 查看字符串是否有满足正则表达式的内容,并返回一个布尔值true/false ...

  4. C/C++编程笔记:C语言入门知识点(一),请收藏C语言最全笔记!

    C语言简介 C 语言是一种通用的高级语言,最初是由丹尼斯·里奇在贝尔实验室为开发 UNIX 操作系统而设计的.C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现. 原文链接: ...

  5. ABC 162 F Select Half dp 贪心

    LINK:Select Half 考试的时候调了一个小时给调自闭了 原来是dp的姿势不太对. 首先 容易发现 奇数最多空2个位置 偶数最多空1一个位置 然后 设f[i][j][k]表示第i个数选了没有 ...

  6. 实战:docker搭建FastDFS文件系统并集成SpringBoot

    实战:docker搭建FastDFS文件系统并集成SpringBoot 前言 15年的时候,那时候云存储还远远没有现在使用的这么广泛,归根结底就是成本和安全问题,记得那时候我待的公司是做建站开发的,前 ...

  7. iOS苹果美区 Apple ID 账号最新注册教程,iPhone用户务必收藏!

    编の语 前言 今天杀手宝宝出一个注册美区ID的教程,这是目前注册苹果美区ID最快的方法,所有人适合使用! 提の示 温馨提示: 所有内容均免费分享,部分资源来自于 网络,如与版权问题联系宝宝处理! 知道 ...

  8. 树形DP 学习笔记(树形DP、树的直径、树的重心)

    前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...

  9. 利用描述符自定制property

    利用描述符自定制property class Lazyproperty: def __init__(self,func): # print('==========>',func) self.fu ...

  10. 2019.12.9Java课堂总结

    今天在课堂上进行了练习.现进行成果及不足汇报: 1.完成了登录界面的设计 2.完成了数据库的连接. 3.完成了数据库表的设计   4.完成了变量的定义与初始化以及get.set的设立. 5.对整体框架 ...