ElasticSearch 如何计算得分及一个不太成熟的使用

news2025/2/26 5:33:10

1.背景

最近在做 ES 相关东西,只最会在查询的时候给不同的字段设置不同的权重,但是得分具体怎么算的不太明白,花了4-5 天研究和总结了一下。这样不至于被别人问到“这个分数怎么算出来的?”,两眼一抹黑,不知其所以然,总结下方便之后学习;

2.准备

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

  • 我创建了一个 book 索引,是一个分片一个副本,有三条数据;我 match 查询 java 时, java 编程思想 的得分 0.5619609,深入理解 Java 虚拟机得分 0.40390933;(分片会影响得分,请先使用一个片,后面会给出解释)

3.详情

  • 使用 explain 参数查询会给出得分计算过程
    在这里插入图片描述
  • 把 detail 全拿出来就是
"details" : [
            {
              "value" : 0.5619609,
              "description" : "score(freq=1.0), computed as boost * idf * tf from:",
              "details" : [
                {
                  "value" : 2.2,
                  "description" : "boost",
                  "details" : [ ]
                },
                {
                  "value" : 0.47000363,
                  "description" : "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                  "details" : [
                    {
                      "value" : 2,
                      "description" : "n, number of documents containing term",
                      "details" : [ ]
                    },
                    {
                      "value" : 3,
                      "description" : "N, total number of documents with field",
                      "details" : [ ]
                    }
                  ]
                },
                {
                  "value" : 0.54347825,
                  "description" : "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                  "details" : [
                    {
                      "value" : 1.0,
                      "description" : "freq, occurrences of term within document",
                      "details" : [ ]
                    },
                    {
                      "value" : 1.2,
                      "description" : "k1, term saturation parameter",
                      "details" : [ ]
                    },
                    {
                      "value" : 0.75,
                      "description" : "b, length normalization parameter",
                      "details" : [ ]
                    },
                    {
                      "value" : 3.0,
                      "description" : "dl, length of field",
                      "details" : [ ]
                    },
                    {
                      "value" : 5.0,
                      "description" : "avgdl, average length of field",
                      "details" : [ ]
                    }
                  ]
                }
              ]
            }
          ]

3.1 粗略查看 ES 得分详情

  • 我们发现第四行好像就是公式 ,而且与 details 数组的元素对应
    在这里插入图片描述
  • 而且每个元素都有一个 value 值,把 value 值带进公式,正好等于 0.5619608507173045
    在这里插入图片描述

3.2 详细查看 es 得分

  • 第一项 2.2 不用解释,是 es 默认的一个常数,我们看第二项 idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:和第三项 tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:
  • 第二项截图
    在这里插入图片描述
    小 n :number of documents containing term,翻译一下,包含词项(也就是 java) 的文档数量,因为我们查询的是 name 字段,所以就是所有文档中 name 字段,包含 java 的文档数量,即 Java 编程思想深入理解 Java 虚拟机 ,vulue 等于 2 。
    大 N :total number of documents with field,翻译一下,有 name 这个字段的文档的数量,我们的三个文档都有 name 这个字段,即 Java 编程思想深入理解 Java 虚拟机Spring 5 个核心原理 value 等于 3 。
  • log(1 + (N - n + 0.5) / (n + 0.5)) = log(1 + (3 - 2 + 0.5) / (2 + 0.5) = log(1 + 1.5 / 2.5) = log1.6 =0.47000363,取的是自然数的对数,如图:
    在这里插入图片描述

3.2 第三项

  • 第三项截图
    在这里插入图片描述
    freq:occurrences of term within document,翻译一下,freq 是 frequency 的简写,频率的意思,即词项(java)在 Java 编程思想发生的频率, value 等于 1.
    k1:term saturation parameter,翻译一下,词项饱和度参数,value 是一个常数 1.2
    b:length normalization parameter,翻译一下,长度规格化参数,value 是一个常数 0.75
    dl:length of field,翻译一下,“字段”的长度,这里长度可不是 Java 编程思想.length(),而是Java 编程思想能分成多少个词,看下面 3.3 截图,
    avgdl:average length of field,翻译一下,“字段”的平均长度,同样也不是Java 编程思想 、 深入理解 Java 虚拟机、Spring 5 个核心原理.length()/3,而是Java 编程思想 、 深入理解 Java 虚拟机、Spring 5 个核心原理分词后的长度除以 33是有name 字段的数量,也看下面 3.3 截图

3.3 ik 分词器分词

在这里插入图片描述

  • Java 编程思想 、 深入理解 Java 虚拟机、Spring 5 个核心原理,分词后词项太多截图不全,我放到 JSON 解析器下,可以看到 数量是 15 ,平均数量是 5
    在这里插入图片描述
    在这里插入图片描述
  • freq / (freq + k1 * (1 - b + b * dl / avgdl) = 1 /(1 + 1.2 * (1 - 0.75 + 0.75 * 3 /5)) = 1 / (1 + 1.2 * (0.25 + 0.75 * 0.6)) = 1 / (1 + 1.2 * 0.7) = 1 / 1.84 = 0.54347826 约等于0.54347825,不纠结那 0.00000001至此,得分的所有项解读完毕,另一个查询结果“深入理解 Java 虚拟机”也可以按照这个方式计算出来

4.公式解释

  • 已经知其然了,现在看知其所以然,它是根据公式及经过大数据量实验设置参数后计算的结果。主角就是 BM25 算法,公式如下
    在这里插入图片描述
  • 我们在 kibana 上 explain 后公式的第二项和第三项分别对应这个公式的这两部分:
    在这里插入图片描述
  • 倒写的 3,表示求和,就是查询项分词后,每个分词都要计算分数,把每个查询词项的分数相加,比如我查询的是 “Java Spirng”,那么会把 Java 得分计算出来,再把 Spring 得分计算出来,然后相加;
  • 第二项,原谅我打不出这个公式,就是上面截图中上面两个箭头的第一个, idf 是 inverse document frequency 的简写,翻译一下,逆文档频率,详情是 log(1 + (N - n + 0.5) / (n + 0.5));如果小 n 趋近于 大 N,那么整个公式值越小,大家可以把 N 固定为 3,然后小 n 分别为 1、2、3 时,换算下是不是 小 n 越大,计算结果越小。翻译成人话就是,当一个词在所有文档中都出现了,那么它显得不那么重要,得分就低了。
  • 第三项,上面截图中上面两个箭头的第二个,如果说第二项是各个文档之间的纵向的比较,那么第三项更倾向于定位某个文档后的横向比较,
  • 第三项(1),比较频率,即这个词项出现的次数 ,ES 的的公式是freq / (freq + k1 * (1 - b + b * dl / avgdl)),比 BM25 分子少乘了一个 (k1 + 1)有区别,但差别不大;因为分母 k1 * (1 - b + b * dl / avgdl))可以看作是一个常数,那么当 freq 越大时,freq / (freq + k1 * (1 - b + b * dl / avgdl))值越大,但是最大值不超过 1,是无限趋近于 1 的数,当 freq 越小时,计算结果越小,翻译成人话也好理解,此项频率越高,得分越高。
  • 第三项(2),比较词项占比,这里的此项是 name 字段分词后的个数除以所有 name 字段分词平均值,当 dl 越大时分母越大,得分越小,翻译成人话是,比如我的 name 有一千个字且包含 java ,其他文档是十个字且包含 Java,那么我一千个字里面有个 Java 显得没那么重要。

4.分片情况下

如果你按照我上面计算时,发现中分词数量计算不对,那么很可能是你有多个分片,ES 不会把同一个字段各个分片的内容统一计算,而是每个片单独计算得分后就排名了,你可以通过指定 routing 来固定某个分片,验证得分结果。
在这里插入图片描述

5.前人的解读,帮助很大

bm25算法详解-bilibili
Elasticsearch BM25相关度评分算法超详细解释

6.一个不太成熟的使用

  • 我项目中有一个索引,有两个字段,分别记录用户搜索的内容 searchFor 和这个内容被搜索的次数 count,我想要把 count 也融入得分公式中,ES 默认的得分记作 _score,我本想把 count 按 log10 取对数变成 _score*log10(count),但是当 count 超过很大时会把 _score的得分放大很多倍,不同次数的文档得分跨度也比较大;
  • 研究 ES 的得分步骤后,我发现我的次数和第三项 freq / (freq + k1 * (1 - b + b * dl / avgdl))特别像,count 没有字段长度的比较所以我直接把关于长度 b(饱和度)dl/avgdl去掉了,改成 count / (count+k1) = count / (count + 1.2),最终得分是 _score*count / (count + 1.2)
  • 当然这样算不一定成熟,但是看起来起作用了,而且不同次数的文档得分跨度也变小了;但是因为我工作中的测试数据量不够,这个类 BM25的公式可能也不能这么硬套,要经过实际数据测试及业务需求匹配度验证后才能下定论,这只是一个不太成熟但是有点道理的使用,希望大家多留言讨论

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1901812.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】模板进阶--保姆级解析(什么是非类型模板参数?什么是模板的特化?模板的特化如何应用?)

目录 一、前言 二、什么是C模板? 💦泛型编程的思想 💦C模板的分类 三、非类型模板参数 ⚡问题引入⚡ ⚡非类型模板参数的使用⚡ 🔥非类型模板参数的定义 🔥非类型模板参数的两种类型 &#x1f52…

【Unity2D 2022:Particle System】添加命中粒子特效

一、创建粒子特效游戏物体 二、修改粒子系统属性 1. 基础属性 (1)修改发射粒子持续时间(Duration)为1s (2)取消勾选循环(Looping) (2)修改粒子存在时间&…

Vue表单输入绑定v-model

表单输入绑定 在前端处理表单时&#xff0c;我们常常需要将表单输入框的内容同步给Javascript中相应的变量。手动连接绑定和更改事件监听器可能会很麻&#xff0c;v-model 指令帮我们简化了这一步骤。 <template><h3>表单输入绑定</h3><hr> <inpu…

推荐Bulk Image Downloader插件下载网页中图片链接很好用

推荐&#xff1a;Bulk Image Downloader chome浏览器插件下载图片链接&#xff0c;很好用。 有个网页&#xff0c;上面放了数千的gif的电路图&#xff0c;手工下载会累瘫了不可。想找一个工具分析它的静态链接并下载&#xff0c;找了很多推荐的下载工具&#xff0c;都是不能分…

docker部署mycat,连接上面一篇的一主二从mysql

一、docker下载mycat镜像 查看安装结果 这个名称太长&#xff0c;在安装容器时不方便操作&#xff0c;设置标签为mycat docker tag longhronshens/mycat-docker mycat 二、安装容器 先安装一个&#xff0c;主要目的是获得配置文件 docker run -it -d --name mycat -p 8066:…

算法系列--分治排序|再谈快速排序|快速排序的优化|快速选择算法

前言:本文就前期学习快速排序算法的一些疑惑点进行详细解答,并且给出基础快速排序算法的优化版本 一.再谈快速排序 快速排序算法的核心是分治思想,分治策略分为以下三步: 分解:将原问题分解为若干相似,规模较小的子问题解决:如果子问题规模较小,直接解决;否则递归解决子问题合…

【JVM 的内存模型】

1. JVM内存模型 下图为JVM内存结构模型&#xff1a; 两种执行方式&#xff1a; 解释执行&#xff1a;JVM是由C语言编写的&#xff0c;其中有C解释器&#xff0c;负责先将Java语言解释翻译为C语言。缺点是经过一次JVM翻译&#xff0c;速度慢一点。JIT执行&#xff1a;JIT编译器…

java自旋锁

Java自旋锁&#xff08;Spin Lock&#xff09;是一种用于多线程同步的锁机制&#xff0c;通过反复检查某个条件&#xff08;通常是一个共享变量的状态&#xff09;而不是挂起线程来实现锁的获取。自旋锁的核心思想是让线程在尝试获取锁时保持活动状态&#xff0c;即进行“自旋”…

KBPC3506-ASEMI储能专用整流桥KBPC3506

编辑&#xff1a;ll KBPC3506-ASEMI储能专用整流桥KBPC3506 型号&#xff1a;KBPC3506 品牌&#xff1a;ASEMI 封装&#xff1a;KBPC-4 正向电流&#xff08;Id&#xff09;&#xff1a;35A 反向耐压&#xff08;VRRM&#xff09;&#xff1a;600V 正向浪涌电流&#xf…

进程控制-exec函数

让父子进程来执行不相干的操作 能够替换进程地址空间的代码.text段 执行另外的程序&#xff0c;不需要创建额外的的地址空间 当前程序中调用另外一个应用程序 指定执行目录下的程序 int execl(const char *path, const char *arg&#xff0c;/* (char *) NULL */); /* pat…

【MindSpore学习打卡】应用实践-自然语言处理-基于RNN的情感分类:使用MindSpore实现IMDB影评分类

情感分类是自然语言处理&#xff08;NLP&#xff09;中的一个经典任务&#xff0c;广泛应用于社交媒体分析、市场调研和客户反馈等领域。本篇博客将带领大家使用MindSpore框架&#xff0c;基于RNN&#xff08;循环神经网络&#xff09;实现一个情感分类模型。我们将详细介绍数据…

数据结构之“栈”(全方位认识)

&#x1f339;个人主页&#x1f339;&#xff1a;喜欢草莓熊的bear &#x1f339;专栏&#x1f339;&#xff1a;数据结构 前言 栈是一种数据结构&#xff0c;具有" 后进先出 "的特点 或者也可见说是 ” 先进后出 “。大家一起加油吧冲冲冲&#xff01;&#xff01; …

SpringBoot | 大新闻项目后端(redis优化登录)

该项目的前篇内容的使用jwt令牌实现登录认证&#xff0c;使用Md5加密实现注册&#xff0c;在上一篇&#xff1a;http://t.csdnimg.cn/vn3rB 该篇主要内容&#xff1a;redis优化登录和ThreadLocal提供线程局部变量&#xff0c;以及该大新闻项目的主要代码。 redis优化登录 其实…

基于深度学习LightWeight的人体姿态检测跌倒系统源码

一. LightWeight概述 light weight openpose是openpose的简化版本&#xff0c;使用了openpose的大体流程。 Light weight openpose和openpose的区别是&#xff1a; a 前者使用的是Mobilenet V1&#xff08;到conv5_5&#xff09;&#xff0c;后者使用的是Vgg19&#xff08;前10…

Charles拦截发送数据包-cnblog

Charles拦截发送数据包 打开允许断点 右键要打断点的数据包&#xff0c;打断点 重新发请求进入断点模式 修改完毕后发送

uniapp实现一个键盘功能

前言 因为公司需要&#xff0c;所以我.... 演示 代码 键盘组件代码 <template><view class"keyboard_container"><view class"li" v-for"(item, index) in arr" :key"index" click"changArr(item)" :sty…

数据库管理-第216期 Oracle的高可用-01(20240703)

数据库管理216期 2024-07-03 数据库管理-第216期 Oracle的高可用-01&#xff08;20240703&#xff09;1 MAA简介2 MAA等级2.1 BRONZE2.2 SILVER2.3 GOLD2.4 PLATINUM 3 业务延续性总结 数据库管理-第216期 Oracle的高可用-01&#xff08;20240703&#xff09; 作者&#xff1a;…

Google Play上架:恶意软件、移动垃圾软件和行为透明度详细解析和解决办法 (一)

近期整理了许多开发者的拒审邮件和内容,也发现了许多问题,今天来说一下关于恶意软件这类拒审的问题。 目标邮件如下: 首先说一下各位小伙伴留言私信的一个方法,提供你的拒审邮件和时间,尽可能的详细,这样会帮助我们的团队了解你们的问题,去帮助小伙伴么解决问题。由于前…

Java面试八股之MySQL存储货币数据,用什么类型合适

MySQL存储货币数据&#xff0c;用什么类型合适 在MySQL中存储货币数据&#xff0c;最合适的类型是DECIMAL。这是因为货币数据通常需要高精度&#xff0c;尤其是对于财务交易&#xff0c;即使是极小的精度损失也可能导致严重的会计错误。DECIMAL类型可以提供固定的精度&#xf…

ASP.NET Core----基础学习02----中间件的执行顺序 静态文件中间件

文章目录 1.终端中间件&#xff08;Middleware&#xff09;2.中间件的执行顺序&#xff08;1&#xff09;当只有2个中间件的时候&#xff0c;先执行普通中间件&#xff0c;再执行终端中间件&#xff08;2&#xff09;当有多个中间件的时候&#xff0c;中间件的执行顺序 3.添加静…