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

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.mfbz.cn/a/778581.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端面试题19(vue性能优化)

Vue.js应用的性能优化是一个多方面的过程,涉及初始化加载、运行时渲染以及用户交互等多个环节。以下是一些关键的Vue性能优化策略,包括详细的说明和示例代码: 1. 懒加载组件 对于大型应用,可以使用懒加载来减少初始加载时间。Vu…

策略模式的应用

前言 系统有一个需求就是采购员审批注册供应商的信息时,会生成一个供应商的账号,此时需要发送供应商的账号信息(账号、密码)到注册填写的邮箱中,通知供应商账号信息,当时很快就写好了一个工具类&#xff0…

华为机试HJ34图片整理

华为机试HJ34图片整理 题目: 想法: 将输入的字符串中每个字符都转为ASCII码,再通过快速排序进行排序并输出 input_str input() input_list [int(ord(l)) for l in input_str]def partition(arr, low, high):i low - 1pivot arr[high]f…

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

一. LightWeight概述 light weight openpose是openpose的简化版本,使用了openpose的大体流程。 Light weight openpose和openpose的区别是: a 前者使用的是Mobilenet V1(到conv5_5),后者使用的是Vgg19(前10…

啥?你没听过SpringBoot的FatJar?

写在最前面: SpringBoot是目前企业里最流行的框架之一,SpringBoot的部署方式多数采用jar包形式。通常,我们使用java -jar便可以直接运行jar文件。普通的jar只包含当前 jar的信息,当内部依赖第三方jar时,直接运行则会报…

数字化精益生产系统--MRP 需求管理系统

MRP(Material Requirements Planning,物料需求计划)需求管理系统是一种在制造业中广泛应用的计划工具,旨在通过分析和计划企业生产和库存需求,优化资源利用,提高生产效率。以下是对MRP需求管理系统的功能设…

[FreeRTOS 功能应用] 事件组 功能应用

文章目录 一、基础知识点二、代码讲解三、结果演示四、代码下载 一、基础知识点 [FreeRTOS 基础知识] 事件组 概念 [FreeRTOS 内部实现] 事件组 本实验是基于STM32F103开发移植FreeRTOS实时操作系统,事件组实战操作。(当task1和task2同时完成,才执行ta…

Python爬虫教程第1篇-基础知识

文章目录 什么是爬虫爬虫的工作原理用途搜索引擎爬虫Robots协议HTTP的请求过程URL的含义HTTP常见请求头爬虫常用的技术 什么是爬虫 信息的交互是通过web网页、或者移动端等不同的客户端端形式进行交互,这个过程是一个人与网路正常的交互行为。而爬虫可以用来模拟人…

easyx图形库

目录 1、绘制简单的图形化窗口 2、设置窗口属性 2.1 颜色设置 2.2 刷新 3、基本绘图函数 3.1 绘制直线 3.2 绘制圆 3.3 绘制矩形 4、贴图 4.1 原样贴图 4.1.1 IMAGE变量去表示图片 4.1.2 加载图片 4.1.3 显示图片 4.2 透明贴图 4.2.1 认识素材 4.3 png贴图 5…

使用块的网络 VGG

一、AlexNet与VGG 1、深度学习追求更深更大,使用VGG将卷积层组合为块 2、VGG块:3*3卷积(pad1,n层,m通道)、2*2最大池化层 二、VGG架构 1、多个VGG块后接全连接层 2、不同次数的重复块得到不同的架构&a…

go语言day10 接口interface 类型断言 type关键字

接口: 空接口类型: 要实现一个接口,就要实现该接口中的所有方法。因为空接口中没有方法,所以自然所有类型都实现了空接口。那么就可以使用空接口类型变量去接受所有类型对象。 类比java,有点像Object类型的概念&#x…

使用Docker、Docker-compose部署单机版达梦数据库(DM8)

安装前准备 Linux Centos7安装:https://blog.csdn.net/andyLyysh/article/details/127248551?spm1001.2014.3001.5502 Docker、Docker-compose安装:https://blog.csdn.net/andyLyysh/article/details/126738190?spm1001.2014.3001.5502 下载DM8镜像 …

数据按月分表

当数据量过大,从数据层面可以按月分表,报表查询时可以根据,查询时间来计算查询的年月,查询对应的表 1、按月分表: 存储过程SP_BRANCH_TABLE_TEST 以下存储过程分表,加了索引可以方便后续查询 USE [DASHBOAR…

三分钟内了解卷轴模式

在数字化时代的浪潮中,卷轴商业模式巧妙地将积分体系、互动任务、社交裂变、虚拟经济体系以及个性化成长路径等多元要素融为一体。 积分体系:激发参与动力的源泉 卷轴商业模式的核心在于其精心构建的积分系统。新用户踏入平台,即获赠一笔启…

Windows上Docker的安装与初体验

Docker Desktop下载地址 国内下载地址 一、基本使用 1. 运行官方体验镜像 docker run -d -p 80:80 docker/getting-started执行成功 停止体验服务 docker stop docker/getting-started删除体验镜像 docker rmi docker/getting-started2. 修改docker镜像的存储位置 3. …

vofa+:一款超级好用的可视化串口调试软件

目录 一、软件配置 1、先配置好usart1串口 2、重定向printf: 3&#xff0c;勾选魔术棒中的LIB 二、vofa的使用 1、RawData模式 2、FireWater 一、软件配置 1、先配置好usart1串口 2、重定向printf: 在 stm32f4xx_hal.c中添加&#xff1a; #include <stdio.h> e…

【nvm管理nodejs版本,切换node指定版本】

nvm管理nodejs版本 nvm管理nodejs版本主要功能使用 nvm nvm管理nodejs版本 nvm&#xff08;Node Version Manager&#xff09;顾名思义node版本管理器&#xff0c;无须去node管网下载很多node安装程序;用于管理多个 Node.js 版本的工具。它允许你在同一台机器上同时安装和管理…

文件上传(本地、OSS)

什么是文件上传&#xff1a;将文件上传到服务器。 文件上传-本地存储 前端 <template> <div><!-- 上传文件需要设置表单的提交方式为post&#xff0c;并设置enctype属性、表单项的type属性设置为file --><form action"http://localhost:8080/wedu/…

使用Python绘制和弦图

使用Python绘制和弦图 和弦图效果代码 和弦图 和弦图用于展示数据的多对多关系&#xff0c;适合用于社交网络、交通流量等领域的分析。 效果 代码 import pandas as pd import holoviews as hv from holoviews import opts hv.extension(bokeh)# 示例数据 data [(A, B, 2),…

价格预言机的使用总结(一):Chainlink篇

文章首发于公众号&#xff1a;Keegan小钢 前言 价格预言机已经成为了 DeFi 中不可获取的基础设施&#xff0c;很多 DeFi 应用都需要从价格预言机来获取稳定可信的价格数据&#xff0c;包括借贷协议 Compound、AAVE、Liquity &#xff0c;也包括衍生品交易所 dYdX、PERP 等等。…