当前位置: 首页 > news >正文

通过案例实战详解elasticsearch自定义打分function_score的使用

前言

elasticsearch给我们提供了很强大的搜索功能,但是有时候仅仅只用相关度打分是不够的,所以elasticsearch给我们提供了自定义打分函数function_score,本文结合简单案例详解function_score的使用方法,关于function-score-query的文档最权威的莫过于官方文档:
function_score官方文档

基本数据准备

我们创建一张新闻表,包含如下字段:

字段类型说明
idLong新闻ID
titlestring标题
tagsstring标签
read_countlong阅读数
like_countlong点赞数
comment_countlong评论数
rankdouble自定义权重
locationarrays文章发布经纬度
pub_timedate发布时间

创建elasticsearchMapping

PUT /news
{"mappings": {"properties": {"id": {"type": "long"},"title": {"type": "text","analyzer": "standard"},"tags": {"type": "keyword"},"read_count": {"type": "long"},"like_count": {"type": "long"},"comment_count": {"type": "long"},"rank": {"type": "double"},"location": {"type": "geo_point"},"pub_time": {"type": "date","format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm||yyyy-MM-dd||epoch_millis"}}}
}

准备测试数据:

idtitletagsread_countcomment_countlike_countranklocationpub_time
1台风“杜苏芮”登陆福建晋江 多部门多地全力应对台风;杜苏芮;福建1000020006000118.55199,24.781442023-07-29 09:47
2受台风“杜苏芮”影响 北京7月29日至8月1日将有强降雨台风;杜苏芮;北京1000200600116.23128,40.220772023-06-29 14:49:38
3杭州解除台风蓝色预警信号台风;杭州10260.9120.21201,30.20842020-07-29 14:49:38

批量添加数据到elasticsearch中:

POST _bulk
{"create": {"_index": "news", "_id": 1}}
{"comment_count":600,"id":1,"like_count":2000,"location":[118.55199,24.78144],"pub_time":"2023-07-29 09:47","rank":0.0,"read_count":10000,"tags":["台风","杜苏芮","福建"],"title":"台风“杜苏芮”登陆福建晋江 多部门多地全力应对"}
{"create": {"_index": "news", "_id": 2}}
{"comment_count":60,"id":2,"like_count":200,"location":[116.23128,40.22077],"pub_time":"2023-06-29 14:49:38","rank":0.0,"read_count":1000,"tags":["台风","杜苏芮","北京"],"title":"受台风“杜苏芮”影响 北京7月29日至8月1日将有强降雨"}
{"create": {"_index": "news", "_id": 3}}
{"comment_count":6,"id":3,"like_count":20,"location":[120.21201,30.208],"pub_time":"2020-07-29 14:49:38","rank":0.99,"read_count":100,"tags":["台风","杭州"],"title":"杭州解除台风蓝色预警信号"}

random_score的使用

我们通过random_score理解一下weightscore_mode,boost_mode的作用分别是什么,先直接看Demo


GET /news/_search
{"query": {"function_score": {"query": {"match": {"title": "台风"}},"functions": [{"random_score": {}, "weight": 1},{"filter": { "match": { "title": "杭州" } },"weight":42}],"score_mode": "sum","boost_mode": "replace"}}
}

对应JAVA查询代码:

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();queryBuilder.should(QueryBuilders.matchQuery("title","杭州"));FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[1];ScoreFunctionBuilder<RandomScoreFunctionBuilder> randomScoreFilter = new RandomScoreFunctionBuilder();((RandomScoreFunctionBuilder) randomScoreFilter).seed(2);filterFunctionBuilders[0] = new FunctionScoreQueryBuilder.FilterFunctionBuilder(randomScoreFilter);FunctionScoreQueryBuilder query = QueryBuilders.functionScoreQuery(queryBuilder, filterFunctionBuilders).scoreMode(FunctionScoreQuery.ScoreMode.SUM).boostMode(CombineFunction.SUM);SearchSourceBuilder searchSourceBuilder= new SearchSourceBuilder().query(query);SearchRequest searchRequest= new SearchRequest().searchType(SearchType.DFS_QUERY_THEN_FETCH).indices("news").source(searchSourceBuilder);SearchResponse response =  restClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = response.getHits();String searchSource;for (SearchHit hit : hits){searchSource = hit.getSourceAsString();System.out.println(searchSource);}

查询结果:
image.png

这个查询使用的function_scorequery中通过title搜索“台风”,在functions我们增加了两个打分,一个是random_score,随机生成一个得分,得分的weight权重是1,第二个是如果标题中有“杭州”,得分权重为42,

  • random_score
    顾名思义就是生成一个(0,1)之间的随机得分,我能想到的一个应用场景是,有一天产品要求:每个人看到新闻都不一样,要做到“千人千面”,而且只给你一天的时间,这样我们就可以使用random_score,每次拉取的数据都是随机的,每个人看到的新闻都是不一样的,这个随机查询比Mysql实现简单多了,0成本实现了“千人千面”。

  • weight
    这个就是给生成的得分增加一个权重,在上面的Demo中,我们第一个 weight=1,第二个weight=42,从搜索结果得分可以看出“杭州解除台风蓝色预警信号”这条得分是42.40192,而下面的只有0.8194501,因为增加了42倍的权重。

  • score_mode

score_mode的作用是对functions中计算出来的多个得分做汇总计算,比如我用了是sum,就是指将上面random_score得到的打分和filter中得到的42分相加,也就是说第一条42.40192得分是random_score生成了0.40192再加上filter中得到了42分。score_mode默认是采用multiply,总共有6种计算方式:

random_score函数计算方式
multiplyscores are multiplied (default)
sumscores are summed
avgscores are averaged
firstthe first function that has a matching filter is applied
maxmaximum score is used
minminimum score is used
  • boost_mode

boost_mode作用是将functions得到的总分数和我们query查询的得到的分数做计算,比如我们使用的是replace就是完全使用functions中的得分替代query中的得分,boost_mode总共有6种计算方式:

boost_mode函数得分计算方式
multiplyquery score and function score is multiplied (default)
replaceonly function score is used, the query score is ignored
sumquery score and function score are added
avgaverage
maxmax of query score and function score
minmin of query score and function score

script_score的使用

script_score就是用记可以通过各种函数计算你文档中出现的字段,算出一个自己想要的得分,我们直接看Demo

image.png

GET /news/_search
{"query": {"function_score": {"query": {"match": { "title": "台风" }},"script_score": {"script": {"params": {"readCount": 1,"likeCount":5,"commentCount":10},"source": "Math.log(params.readCount* doc['read_count'].value +params.likeCount* doc['like_count'].value+params.commentCount* doc['comment_count'].value) "}},"boost_mode": "multiply"}}
}

每篇新闻有阅读数点赞数据评论数,我们可以通过这三个指标算出一个分值来评价一篇文章的热度,然后将这个热度和query中的得分相乘,这样热度很高的文章可以排到更前面。在这个Demo中我使用了一个简单的加权来计算文章热度,一般来说阅读数是最大的,点赞数次之,评论数是最小的。

文章热度 = L o g ( 评论数 × 10 + 点赞数 × 5 + 阅读数 ) 文章热度=Log(评论数\times 10+点赞数\times5+阅读数) 文章热度=Log(评论数×10+点赞数×5+阅读数)

这里为了演示,简单算一下文章热度,真实的要比这个复杂的多,可能不同种类的文章重要性也是不一样的。

field_value_factor的使用

field_value_factor可以理解成elasticsearch给你一些内置的script_score,每次写script_score必定不是太方便,如果有一些内置的函数,开箱即用就方便多了,我们直接看Demo

GET /news/_search
{"query": {"function_score": {"query": {"match": {"title": "台风"}},"field_value_factor": {"field": "rank","factor": 10,"modifier": "sqrt","missing": 1},"boost_mode": "multiply"}}
}

这里的field_value_factor就对相当script_scoresqrt(10 * doc['rank'].value),这里的factor是乘以多少倍,默认是1倍,missing是如果没有这个字段默认值为1,modifier是计算函数,field是要计算的字段。

modifier计算函数有以下类型可以选择

modifier函数得分计算方式
noneDo not apply any multiplier to the field value
logTake the common logarithm of the field value. Because this function will return a negative value and cause an error if used on values between 0 and 1, it is recommended to use log1p instead.
log1pAdd 1 to the field value and take the common logarithm
log2pAdd 2 to the field value and take the common logarithm
lnTake the natural logarithm of the field value. Because this function will return a negative value and cause an error if used on values between 0 and 1, it is recommended to use ln1p instead.
ln1pAdd 1 to the field value and take the natural logarithm
ln2pAdd 2 to the field value and take the natural logarithm
squareSquare the field value (multiply it by itself)
sqrtTake the square root of the field value
reciprocalReciprocate the field value, same as 1/x where x is the field’s value

衰减函数Decay functions的使用

衰减函数可以理解成计算文档中某一个字段与给定值的距离,如果距离越近得分就越高,距离越远得分就越低,这个就比较适用于新闻发布时间的衰减了,越久前发布的新闻,得分应该越小,排序越往后。我们直接看Demo

GET /news/_search
{"query": {"function_score": {"query": {"match": {"title": "台风"}},"functions": [{"gauss": {"pub_time": {"origin": "now","offset": "7d","scale": "60d","decay": 0.9}}},{"exp": {"location": {"origin": {"lat": 120.21551,"lon": 30.25308},"offset": "50km","scale": "50km","decay": 0.1}}}],"score_mode": "sum", "boost_mode": "sum"}}
}

搜索结果:
image.png

衰减函数有3种,分别为gauss高斯函数、lin线程函数、exp对数函数,具体的计算公式可以参考官方文档,这里我们主要理解衰减函数的4个参数作用是什么。

image.png

  • origin
    可以理解成计算距离的原点,比如上面计算新闻发布时间的原点是当前时间,计算经纬度的原点是用户搜索位置,比如我在杭州,那么origin就是杭州的经纬度

  • offset
    这个偏移量可以理解成不需要衰减的距离,比如在上面的Demo中,距离pub_timeoffset为7d,意思是说近7天内发布的新闻都不需要衰减,得分直接为1。计算经纬度中的offset为50km意思是说距离用户50km里的新闻不需要衰减,50km内的基本都是杭州本地的新闻,就没必要衰减了。

  • scaledecay
    这两个参数可以参考官方给的三种函数衰减图,scaledecay表示距离为scale后得分衰减到原来的scale倍。比如上面时间衰减offset=7d, scale=60d,decay= 0.9加起来的意思就是7天内的新闻不衰减,67天(7d+60d)前的新闻得分为0.9,在经纬度衰减中offset=50km, scale=50km,decay= 0.1的意思是50km内的距离不衰减,100km(50km+50km)外的数据得分为0.1。

总结

elasticsearchfunction_score给我提供了好几种很灵活的自定义打分策略,在实际项目中需要根据自己的需求合理的组合这些打分策略并调整对应参数才能满足自己的搜索需求,本文主要介绍function_score的使用,接下来我会根据一个实际的搜索应用介绍一下如何组合、设置这些函数以达到比较理解的搜索效果。

相关文章:

通过案例实战详解elasticsearch自定义打分function_score的使用

前言 elasticsearch给我们提供了很强大的搜索功能&#xff0c;但是有时候仅仅只用相关度打分是不够的&#xff0c;所以elasticsearch给我们提供了自定义打分函数function_score&#xff0c;本文结合简单案例详解function_score的使用方法&#xff0c;关于function-score-query…...

SpringBoot第28讲:SpringBoot集成MySQL - MyBatis-Plus方式

SpringBoot第28讲&#xff1a;SpringBoot集成MySQL - MyBatis-Plus方式 本文是SpringBoot第28讲&#xff0c;MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。MyB…...

AI 绘画Stable Diffusion 研究(三)sd模型种类介绍及安装使用详解

本文使用工具&#xff0c;作者:秋葉aaaki 免责声明: 工具免费提供 无任何盈利目的 大家好&#xff0c;我是风雨无阻。 今天为大家带来的是 AI 绘画Stable Diffusion 研究&#xff08;三&#xff09;sd模型种类介绍及安装使用详解。 目前&#xff0c;AI 绘画Stable Diffusion的…...

Docker 命令没有提示信息

问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; linux安装docker后发现使用docker命令没有提示功能&#xff0c;使用 Tab 键的时候只是提示已有的文件 解决方案&#xff1a; 提示&#xff1a;这里填写该问题的具体解决方案&#xff1a; Bash命令补全 Docke…...

springboot第33集:nacos图

./startup.sh -m standalone Nacos是一个内部微服务组件&#xff0c;需要在可信的内部网络中运行&#xff0c;不可暴露在公网环境&#xff0c;防止带来安全风险。Nacos提供简单的鉴权实现&#xff0c;为防止业务错用的弱鉴权体系&#xff0c;不是防止恶意攻击的强鉴权体系。 鉴…...

学习gRPC(一)

gRPC 简介 根据官网的介绍&#xff0c;gRPC 是开源高性能远程过程调用&#xff08;RPC&#xff09;框架&#xff0c;可以在任何环境中运行。它可以有效地连接数据中心内部和数据中心之间的服务&#xff0c;并为负载平衡、跟踪、运行状况检查和身份验证提供支持。同时由于其建立…...

【二进制安全】堆漏洞:Double Free原理

参考&#xff1a;https://www.anquanke.com/post/id/241598 次要参考&#xff1a;https://xz.aliyun.com/t/6342 malloc_chunk 的源码如下&#xff1a; struct malloc_chunk { INTERNAL_SIZE_T prev_size; /*前一个chunk的大小*/ INTERNAL_SIZE_T size; /*当前chunk的…...

python之open,打开文件时,遇到解码错误处理方式

在Python中&#xff0c;当我们打开一个文件时&#xff0c;我们可以指定文件的编码方式。如果文件的编码方式与我们指定的编码方式不同&#xff0c;那么就会出现解码错误。为了避免这种情况&#xff0c;我们可以使用errors参数来指定如何处理解码错误。 errors参数用于指定解码…...

STM32 CAN通信-CubeMX环境下CAN通信程序的编程与调试经验

文章目录 STM32 CAN通信-CubeMX环境下CAN通信程序的编程 STM32 CAN通信-CubeMX环境下CAN通信程序的编程 STM32F103ZE芯片 CAN通信测试代码&#xff1a; #include "main.h" #include "can.h"CAN_HandleTypeDef hcan1;void SystemClock_Config(void);int ma…...

windows创建不同大小的文件命令

打开命令窗口&#xff08;windowsR输入cmd打开&#xff09; 输入&#xff1a;fsutil file createnew C:\Users\Desktop\fileTran\10M.txt 10240000&#xff0c;创建10M大小的文件。 文件若存在需要先删除。...

Attention Is All You Need

Attention Is All You Need 摘要1. 简介2. Background3. 模型架构3.1 编码器和解码器堆栈3.2 Attention3.2.1 缩放的点积注意力&#xff08;Scaled Dot-Product Attention&#xff09;3.2.2 Multi-Head Attention3.2.3 Attention 在我们模型中的应用 3.3 Position-wise前馈网络…...

手写线程池 - C++版 - 笔记总结

1.线程池原理 创建一个线程&#xff0c;实现很方便。 缺点&#xff1a;若并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间较短的任务就结束了。 由于频繁的创建线程和销毁线程需要时间&#xff0c;这样的频繁创建线程会大大降低 系统的效率。 2.思考 …...

PHP 容器化引发线上 502 错误状态码的修复

最后更新时间 2023-01-24. 背景 笔者所在公司技术栈为 Golang PHP&#xff0c;目前部分项目已经逐步转 Go 语言重构&#xff0c;部分 PHP 业务短时间无法用 Go 重写。 相比 Go 语言&#xff0c;互联网公司常见的 Nginx PHP-FPM 模式&#xff0c;经常会出现性能问题—— 特…...

QT中UDP之UDPsocket通讯

目录 UDP&#xff1a; 举例&#xff1a; 服务器端&#xff1a; 客户端&#xff1a; 使用示例&#xff1a; 错误例子并且改正&#xff1a; UDP&#xff1a; &#xff08;User Datagram Protocol即用户数据报协议&#xff09;是一个轻量级的&#xff0c;不可靠的&#xff0…...

【C语言】10-三大结构之循环结构-1

1. 引言 在日常生活中经常会遇到需要重复处理的问题,例如 统计全班 50 个同学平均成绩的程序求 30 个整数之和检查一个班级的同学程序是否及格要处理以上问题,最原始的方法是分别编写若干个相同或相似的语句或者程序段进行处理 例如:处理 50 个同学的平均成绩可以先计算一个…...

Windows下RocketMQ的启动

下载地址&#xff1a;下载 | RocketMQ 解压后 一、修改runbroker.cmd 修改 bin目录下的runbroker.cmd set "JAVA_OPT%JAVA_OPT% -server -Xms2g -Xmx2g" set "JAVA_OPT%JAVA_OPT% -XX:MaxDirectMemorySize15g" set "JAVA_OPT%JAVA_OPT% -cp %CLASSP…...

linux内核升级 docker+k8s更新显卡驱动

官方驱动 | NVIDIA在此链接下载对应的显卡驱动 # 卸载可能存在的旧版本nvidia驱动(如果没有安装过可跳过&#xff0c;建议执行) sudo apt-get remove --purge nvidia* # 安装驱动需要的依赖 sudo apt-get install dkms build-essential linux-headers-generic sudo vim /etc/mo…...

express学习笔记2 - 三大件概念

中间件 中间件是一个函数&#xff0c;在请求和响应周期中被顺序调用&#xff08;WARNING&#xff1a;提示&#xff1a;中间件需要在响应结束前被调用&#xff09; 路由 应用如何响应请求的一种规则 响应 / 路径的 get 请求&#xff1a; app.get(/, function(req, res) {res…...

Steam搬砖蓝海项目

这个项目早在很久之前就已经存在&#xff0c;并且一直非常稳定。如果你玩过一些游戏&#xff0c;你一定知道Steam是什么平台。Steam平台是全球最大的综合性数字发行平台之一&#xff0c;玩家可以在该平台购买、下载、讨论、上传和分享游戏和软件。 今天我给大家解释一下什么是…...

就业并想要长期发展选数字后端还是ic验证?

“就业并想要长期发展选数字后端还是ic验证&#xff1f;” 这是知乎上的一个热点问题&#xff0c;浏览量达到了13,183。看来有不少同学对这个问题感到疑惑。之前更新了数字后端&数字验证的诸多文章&#xff0c;从学习到职业发展&#xff0c;都写过&#xff0c;唯一没有做过…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...