Elasticsearch:了解和解决文档更新后 Elasticsearch 分数的变化

news2024/10/5 15:24:46

问题

问卷中有如下这样的文档,开发者想通过 match query 搜索这些文档来使用分数。

POST sample-index-test/_doc/1
{
    "first_name": "James",
    "last_name" : "Osaka"
}

以下是对上述文档的示例查询:

GET sample-index-test/_explain/1
{
  "query": {
    "match": {
      "first_name": "James"
    }
  }
}

上述命令给出来的结果是:

{
  "_index": "sample-index-test",
  "_id": "1",
  "matched": true,
  "explanation": {
    "value": 0.2876821,
    "description": "weight(first_name:james in 0) [PerFieldSimilarity], result of:",
    "details": [
      {
        "value": 0.2876821,
        "description": "score(freq=1.0), computed as boost * idf * tf from:",
        "details": [
          {
            "value": 2.2,
            "description": "boost",
            "details": []
          },
          {
            "value": 0.2876821,
            "description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
            "details": [
              {
                "value": 1,
                "description": "n, number of documents containing term",
                "details": []
              },
              {
                "value": 1,
                "description": "N, total number of documents with field",
                "details": []
              }
            ]
          },
          {
            "value": 0.45454544,
            "description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
            "details": [
              {
                "value": 1,
                "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": 1,
                "description": "dl, length of field",
                "details": []
              },
              {
                "value": 1,
                "description": "avgdl, average length of field",
                "details": []
              }
            ]
          }
        ]
      }
    ]
  }
}

如你所知,Elasticsearch 根据相关性对文档进行评分。 在为该文档建立索引后,让我们现在搜索索引。我们目前只有一份关于该索引的文档。

GET sample-index-test/_search
{
  "query": {
    "match": {
      "first_name": "James"
    }
  }
}

搜索后,你将看到以下结果:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "sample-index-test",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "first_name": "James",
          "last_name": "Osaka"
        }
      }
    ]
  }
}

我想提请你注意结果的 _score 字段。 如你所见,我们文档的 _score 值为 0.2876821 。 例如,当你多次更新文档时,假设我们使用以下请求更新了记录 10 次:

POST sample-index-test/_update/1
{
  "script" : "ctx._source.first_name = 'James'; ctx._source.last_name = 'Cena';"
}

或者 

POST sample-index-test/_doc/1
{
    "first_name": "James",
    "last_name" : "Cena"
}

不会有任何添加到索引中。 我们又有了一份文件,没有了。 我们刚刚更新了文档的 last_name 字段。 让我们再次进行精确搜索并尝试查看结果:

GET sample-index-test/_search
{
  "query": {
    "match": {
      "first_name": "James"
    }
  }
}

上面的命令显示的结果是:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.046520013,
    "hits": [
      {
        "_index": "sample-index-test",
        "_id": "1",
        "_score": 0.046520013,
        "_source": {
          "first_name": "James",
          "last_name": "Cena"
        }
      }
    ]
  }
}

正如你在此处看到的,分数发生了变化。 该文档的分数现在为 0.046520013 。 但根据 TF/IDF 计算,我们需要看到与我们的第一个搜索响应相同的分数。 因为当我们将它与文档的第一个状态进行比较时,没有任何变化。 即使我没有更改 first name 字段,我也只是更改了 last_name 字段并继续搜索 first_name 。 让我们对 _explain 端点进行更多挖掘。

GET sample-index-test/_explain/1
{
  "query": {
    "match": {
      "first_name": "James"
    }
  }
}

Explain API 端点将为查询和特定文档计算得分解释。 上述请求的结果如下所示:

{
  "_index": "sample-index-test",
  "_id": "1",
  "matched": true,
  "explanation": {
    "value": 0.046520013,
    "description": "weight(first_name:james in 0) [PerFieldSimilarity], result of:",
    "details": [
      {
        "value": 0.046520013,
        "description": "score(freq=1.0), computed as boost * idf * tf from:",
        "details": [
          {
            "value": 2.2,
            "description": "boost",
            "details": []
          },
          {
            "value": 0.046520017,
            "description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
            "details": [
              {
                "value": 10,
                "description": "n, number of documents containing term",
                "details": []
              },
              {
                "value": 10,
                "description": "N, total number of documents with field",
                "details": []
              }
            ]
          },
          {
            "value": 0.45454544,
            "description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
            "details": [
              {
                "value": 1,
                "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": 1,
                "description": "dl, length of field",
                "details": []
              },
              {
                "value": 1,
                "description": "avgdl, average length of field",
                "details": []
              }
            ]
          }
        ]
      }
    ]
  }
}

去掉一些对我们来说是可选的部分。 现在让我们关注 IDF 计算。 如你所知,反向文档频率(Inverse Document Frequency)查看一个词在语料库中的常见(或不常见)程度。 这意味着我们将使用索引中的文档数来计算 IDF。有关 IDF 的更多知识,请阅读文章 “Elasticsearch:分布式计分”。

idf, computed as log(1 + (N - n + 0.5) / (n + 0.5))

正如你在上面看到的,我们使用的是文档总数,但问题是我们在索引中有一个文档,但它显示的是 10。

              {
                "value": 10,
                "description": "n, number of documents containing term",
                "details": []
              },
              {
                "value": 10,
                "description": "N, total number of documents with field",
                "details": []
              }

因此,如果你使用此分数来计算其他服务的内容,这就是问题所在。

为什么会这样?

Elasticsearch 使用 Lucene 并将所有文档存储在段中。 段(segment)是不可变的,文档更新操作有两步过程。 更新文档时,将创建一个新文档,并将旧文档标记为已删除。 所以,当你在 Elasticsearch 索引中创建第一个文档时,Elasticsearch 会将它保存在一个段中,并且只有一个文档。 然后你更新同一个文档 10 次; 在任何更新操作中,Elasticsearch 都会在一个段中创建另一个文档,并将最旧的文档标记为已删除。 但是当你搜索索引时,你会从段中找到最新的文档状态。 暂时删除的文档数量为10。你会再次搜索到文档的最新状态,但 Elasticsearch 会继续在内部统计它们以进行IDF 计算。 因此,每次更新后,“the number of documents with field” 和 “number of documents containing term” 都会发生变化。

解决方案

如你所知,如果你知道什么是段,这个问题会在一段时间后自行解决。 所以,如果你想自己做这件事而不等待,你需要使用 _forcemerge。 我需要在这里放一个来自 Elasticsearch 文档的解释。在我们稍微等一段时间后,我们再去搜索,我们将会看到最终的分数和我们刚开始搜索的结果是一样的。

合并通过将其中的一些合并在一起来减少每个分片中的段数,并且还释放已删除文档所使用的空间。 合并通常会自动发生,但有时手动触发合并很有用。
我们建议只强制合并只读索引(意味着索引不再接收写入)。

为了对我们的索引执行 _forcemerge,我们使用了以下请求:

POST sample-index-test/_forcemerge

根据你的索引大小,此请求可能需要一些时间,你可以通过在 Kibana 上执行以下请求来完成任务:

GET _tasks?actions=*forcemerge*&detailed

另一种方法就是等待。 Elasticsearch 还有一个调度程序和合并策略来自动合并段。 在使用强制合并之前,我建议仔细阅读相关的官方文档。

最后,还有一个索引生命周期操作,用于使用策略执行强制合并操作。 根据你的逻辑,你可以使用不同的解决方案来获得更好的搜索评分结果。

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

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

相关文章

阿里6面,成功唬住面试官拿了26K,突然感觉软件测试面试貌似不太难...

一次闲聊,一个在阿里上班的朋友突然说起他在阿里的面试经历。 朋友说,阿里的面试挺独特,每轮面试都没有 HR 约时间,一般是晚上 8 点左右面试官来一个电话,问是否能面试,能的话开始面,不能就约一…

【MYSQL】索引与事务(超详细)

文章目录 🌷 1.索引⭐️ 1.1 定义⭐️ 1.2 为什么要用索引⭐️ 1.3 作用⭐️ 1.4 使用场景⭐️ 1.5 使用🍁 1.5.1 查看索引🍁 1.5.2 创建索引🍁 1.5.3 删除索引 ⭐️ 1.6 创建索引的⽅式⭐️ 1.7 选择索引的数据结构(面…

MySQL的索引与SQL优化策略

文章目录 存储引擎常见的存储引擎 索引索引结构BTree的优点索引分类索引语法explain执行计划索引的使用原则最左前缀法则范围查询索引列进行运算操作字符串不加引号模糊查询or连接的条件数据分布影响 覆盖索引前缀索引索引的设计原则 SQL优化insert优化主键优化order by优化gro…

途虎养车三闯IPO,如何突破亏损“魔咒”?

近日,汽车后市场的“资本宠儿”途虎养车更新招股书,再次闯关港股IPO。 途虎养车是一家中国线上线下一体化汽车服务平台。2013-2021年,途虎养车共进行16轮融资,融资总额超过90亿元。这是继2022年1月和8月先后两次递表失效后&#…

layui框架实战案例(20):常用条件判断和信息展示技巧(图片预览、动态表格、短信已读未读、链接分享、信息脱敏、内置框架页)

本文档是近期layui的汇总,部分内容可能会重复。 文章目录 前言一、上传图片预览1.HTML代码2.JQ渲染代码 二、动态表格数据返回条件判断1.动态表格返回列状态判断2.cols列数据事件操作3.删除信息4.短信已读未读状态处理5.confirm确认事件6.链接分享7.信息脱敏 三、内…

【分享】解压文件一直显示失败,如何处理?

想要解压压缩文件,却发现一直显示失败,有可能是以下几个原因引起的。 1、原压缩文件在下载或者发送过程中出现漏洞,导致文件数据不完整。 2、压缩文件感染病毒,或者杀毒软件等阻止解压缩操作。 3、源文件在压缩的过程中&#x…

参展第六届中国城市轨道交通智慧运维大会 | 图扑软件

2022(第六届)中国城市轨道交通智慧运维大会在西安顺利举行。此次大会由现代轨道交通网联合中国机械工程学会设备智能运维分会主办,西安市轨道交通集团有限公司运营分公司、轨道交通工程信息化国家重点实验室(中铁一院)协办。来自行业学会、地…

【vue.js】前端生成随机图片组件

文章目录 前言效果代码 前言 这是一个前端随机生成图片的组件&#xff0c;可以用作滑块验证组件的背景图。 效果 以下效果是结合滑块验证组件一起构建的。 代码 <template><img ref"random-image" /> </template> <script> export defau…

V2.4版本商超标签专用路由器

PICK_Router_V2.4 产品参数 产品型号 PICK_Router_V2.4 尺寸(mm) 21*14*4.3mm 工作温度 -10-70℃ 产品重量 465g 供电方式 DC12V or POE 工作频率 2.4G 通信速率 50-250kbps 通信方式 10/100Mbps有线网络&2.4G 通信半径 30m 支持标签数量 >10000…

ChatGPT其实并不想让开发人员做这5件事情,但却已经被玩坏了

前言 ChatGPT已经火爆了快半年了吧&#xff0c;紧接着国内也开始推出了各种仿制品&#xff0c;我甚至一度怀疑&#xff0c;如果人家没有推出ChatGPT&#xff0c;这些仿制品会不会出现。而很多人也嗨皮得不行&#xff0c;利用各种方法开始科学上网&#xff0c;用ChatGPT做各种觉…

PostMan笔记(四)Mock服务与API文档管理

1. Mock服务 1.1 为什么使用Mock服务 Postman的Mock服务是一种API模拟工具&#xff0c;可以用于模拟API的行为并返回虚拟的响应。它可以帮助开发人员在实际API实现之前测试和验证API设计&#xff0c;以及在客户端应用程序开发过程中进行测试和调试。 使用Postman的Mock服务可…

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(Feign、Gateway)

http客户端Feign &#xff08;一&#xff09;基于Feign远程调用 1、RestTemplate方式调用存在的问题 2、Feign的介绍 3、定义和使用Feign客户端 这个接口里面将来的封装的就是所有对userservice发起的远程调用 1、orderserivce的pom <!--feign客户端依赖--> <depe…

花生壳内网穿透步骤详解,感兴趣的小伙伴可以自己去尝试哦~

花生壳是什么&#xff1f; 花生壳是款具备内网穿透功能的软件。是通过云服务器快速与内网服务器建立连接&#xff0c;同时把内网端口映射到云端&#xff0c;实现各类基于域名的互联网应用服务。花生壳能够实现反向代理应用&#xff0c;支持TCP、HTTP、HTTPS协议&#xff0c;端…

数据结构基础day3

题目&#xff1a;119. 杨辉三角II 我的解法&#xff1a;先将杨辉三角存储起来&#xff0c;取出第rowIndex行 class Solution { public:vector<int> getRow(int rowIndex) {vector<vector<int>> ans(rowIndex1); //初始化rowIndex1行的杨辉三角for(int i0; …

贾其萃 : 笃行实践 筑梦扬帆 | 提升之路系列(二)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

如何开发一款用户体验优秀的语音交友app?

在数字时代&#xff0c;人们越来越依赖智能手机上的应用程序来与他人进行交流。其中&#xff0c;语音交友app成为了最受欢迎的应用之一。然而&#xff0c;开发一款成功的语音交友app需要深入了解用户需求与体验。本文将探讨如何开发一款用户体验优秀的语音交友app。 着眼于用户…

微信小程序uniapp基于Android的大学生社交论坛交流app系统

实现一个基于Android的社交APP小程序,一共3个身份&#xff0c;包括老师、学生和管理员&#xff0c;其中老师和学生在手机端注册登录&#xff0c;管理员在web端后台登录。学生和老师登录后可以查询通知新闻信息&#xff0c;收藏信息&#xff0c;查看好友推荐&#xff0c;论坛发帖…

短视频app开发:如何实现实时短视频录制功能

简介 在当今的移动互联网时代&#xff0c;短视频app已经成为了人们生活中不可或缺的一部分。短视频app的数量和用户量都在不断增加。如今&#xff0c;越来越多的人开始关注短视频app的开发&#xff0c;尤其是如何实现实时短视频录制功能。本文将分享如何开发短视频app并实现实…

【TS】1660- 4 个 TypeScript 5.1 Beta 版重要更新内容

TypeScript 5.1 在 5.0 发布后不久就发布了测试版&#xff0c;但测试版不代表最终正式版。 官方原文 Announcing TypeScript 5.1 Beta(https://devblogs.microsoft.com/typescript/announcing-typescript-5-1-beta/) 中提供了完整的更新内容&#xff0c;以下是我梳理了 4 个 T…

总结829

学习目标&#xff1a; 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 暴力英语&#xff1a;背完第5轮核心词&#xff0c;那些没掌握的还是没掌握&#xff0c;必须重点揪出来&#xff0c;单独…