【问题排查篇】一次业务问题对 ES 的 cardinality 原理探究 | 京东云技术团队

news2024/11/14 15:41:54

作者:京东科技 王长春

业务问题

小编工作中负责业务的一个服务端系统,使用了 Elasticsearch 服务做数据存储,业务运营人员反馈,用户在使用该产品时发现,用户后台统计的订单笔数和导出的订单笔数不一致

交易订单笔数不对,出现差错订单了?这一听极为震撼!出现这样的问题,在金融科技公司里面是绝对不允许发生的,得马上定位问题并解决!

线上反馈业务数据查询和导出数据不一致

小编马上联系业务和相关人员,通过梳理上游系统的调用关系,发现业务系统使用到的是我这边的 ES 的存储服务,然后对线上情况进行复现,基本了解问题的现象:

  1. 用户操作后台里的订单总笔数:商户页面的"订单总笔数","订单总笔数"使用的是小编 ES 存储服务中 ES 的统计聚合功能,其中订单总笔数是使用了 cardinality 操作,并且使用的是 orderId(订单编号)进行统计去重。
  2. 导出功能里的订单总笔数:导出功能使用的是 ES 存储服务中的 ES 条件查询功能,导出功能是进行分页查询的。

问题定位

这两个查询数量不一致,首先看查询条件是否一致呢?

经过一番排查,业务系统在调用查询订单总数和导出订单总数的这两个查询条件是一致的,也就是请求到我这边 ES 服务时,统计聚合的查询和分页导出的查询条件是一致的,但是为什么会在 ES 里面查询的结果是不一致的呢?难道 ES 里面的数据不全?统计聚合或分页导出的其中有一个不准了?

为了具体排查哪个操作可能存在问题,于是通过相同条件下查询数据库的总数和 ES 里面的数据进行对比。发现相同条件下,数据库里面的数据和 ES 条件查询的总数是一致的, 同时业务的 orerId 字段是没有重复,所以可以确定的是:通过 orderId 进行统计聚合去重的操作是有问题的。

数据库查询数量

运营后台查询数量

数据库查询:数据库是做分库分表,此处数据库查询使用的是公司内的数据部银河大表——公司数据部会 T+1日从业务从库数据库中抽取 T 日的增量数据放在建立的"大表"中, 方便各业务进行数据使用。

运营后台查询:运营后台查询是直接查询 ES 存储服务。

数据部大表数量 = MySQL 数据库分库分表表里数量 = 运营控制台查询数量 = ES 存储文档数量

问题定位:
ES 存储服务对外给业务提供的: 通过 orderId 进行统计聚合去重(cardinality)的功能应该是有问题的。

ES 的 cardinality 原理探究

上面说过,小编负责的 ES 存储服务对外给业务提供了通过指定业务字段进行统计聚合去重的功能,统计聚合去重使用的是 ES 的 cardinality 功能。通过业务的查询的条件,使用 ES 的聚合功能 cardinality 操作,映射到 ES 层的操作命令如下代码所示,

执行业务的查询条件操作,从 ES 的管理端后台里面查询竟然复现了和线上生产一样的结果,聚合统计的是 21514,条件查询的是 21427!!!

可以确定的就是这个 cardinality 操作,导致了两个查询的数据不一致,如下图所示:

GET datastore_big_es_1_index/datastore_big_es_1_type/_search
{
  "size": 3,
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "v021.raw": "selfhelp"
          }
        },
        {
          "match": {
            "v012.raw": "1001"
          }
        },
        {
          "match": {
            "typeId": "00029"
          }
        },
        {
          "range": {
            "createdDate": {
              "gte": "2021-02-01",
              "lt": "2021-03-01"
            }
          }
        },
        {
          "bool": {
            "should": [
              {
                "match": {
                  "v031.raw": "113692300"
                }
              }
            ]
          }
        }
      ]
    }
  },
  "aggs": {
    "distinct_orderId": {
      "cardinality": {
        "field": "v033.raw"
      }
    }
  }
}


ES集群控制台cardinality操作

为什么 cardinality 操作会出现这样的结果呢?

小编开始陷入了想当然的陷阱—— 以为这就是一个简简单单的统计去重的功能,ES 做的多好,帮你去重并统计数量了。然后事实并不是,通过 Elasticsearch 对 cardinality 官方文档解释,终于找到了原因。

可以参考Elasticsearch 2.x 版本官方文档对 cardinality的解释:cardinality

其中对 cardinality 算法核心解释是:

ES文档中对cardinality算法介绍

可以总结如下:

  1. cardinality 并不是像关系型数据库 MySQL 一样精确去重的,cardinality做的是一个近似值,是 ES 帮你"估算"出的,这个估算使用的HyperLogLog++(HLL)算法,在速度上非常快,遍历一次即可统计去重,具体可看文档中推荐的论文。
  2. ES 做cardinality估算,是可以设置估算精确度,即设置参数 precision_threshold 参数,但是这个参数在 0-40000, 这个值越大意味着精度越高,同时意味着损失更多的内存,是以内存空间换精度。
  3. 在小数据量下,ES 的这个"估算"精度是非常高的,几乎可以说是等于实际数量。

ES 中 cardinality 参数验证

下面对 ES 的 cardinality 的precision_threshold参数进行验证:

1、大数据量下,设置最高精度及其以上,仍然会存在误差:

大数据量下,设置percision_threshold高精度值验证

2、小数据量下,设置最高精度,可以和实际数量保持一致:

小数据量下,设置percision_threshold高精度验证

那么线上的为什么聚合统计的是 21514,条件查询的是 21427?

线上代码运行和ES集群设置都没有主动设置过 precision_threshold 参数,那么可以知道,这个应该是 ES 集群设置的默认值。线上 ES 集群版本为 5.4x 因此找到 5.4 版本的官方文档,发现 5.4 版本中设置的是默认值 precision_threshold=3000, 在此条件下查询的统计聚合出来的值是 21514。

另外 ES 官方对 cardinality 操作中的precision_threshold参数也做了研究,研究了官方文档中precision_threshold设置cardinality查询失败率查询数据量级的关系,可作为我们在业务开发中进行参考,如下图所示:
官方文档中precision_threshold设置和cardinality查询失败率的关系研究

Elasticsearch 5.4版本官方文档对cardinality中precision_threshold参数的研究文档:precision_threshold

总结与方案

通过对 cardinality 的原理探究, 需要明白的是 : 我们使用 cardinality 是需要区分使用场景的。

  1. 对于精确统计的业务场景,是不建议使用的。例如:订单数的统计(统计结果会引起歧义)的场景下,不建议使用。
  2. **对于非精确统计的业务场景,那么可以说是很有用了,尤其是在大数据量的场景下,在保持一定的准确性下,同时能提供高性能。**例如:监控指标数据,大盘比例计算等场景,在非精确统计下,是有很大用处。

基于小编的这个业务场景,对商户订单进行统计,是属于精确统计场景,那 cardinality 操作就不适合了。又因为业务的 orderId 是不会重复的,理论上在我们 ES 集群中每个记录的 orderId 都是唯一的,因此可以不用进行去重,而可以直接使用 ES 的 count 操作,将订单数统计汇总出,对应 Elasticsearch 开发包中 COUNT API 如下:

org.springframework.data.elasticsearch.core.ElasticsearchTemplate
#count(org.springframework.data.elasticsearch.core.query.SearchQuery, java.lang.Class<T>)


public <T> long count(SearchQuery searchQuery, Class<T> clazz) {
    QueryBuilder elasticsearchQuery = searchQuery.getQuery();
    QueryBuilder elasticsearchFilter = searchQuery.getFilter();
    return elasticsearchFilter == null ? this.doCount(this.prepareCount(searchQuery, clazz), elasticsearchQuery) : this.doCount(this.prepareSearch(searchQuery, clazz), elasticsearchQuery, elasticsearchFilter);
}


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

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

相关文章

21.动态组件 component与keep-alive

目录 1 基本使用 2 按钮切换组件 3 keep-alive 3.1 在切换组件的时候&#xff0c;默认情况下被切换的组件就会被销毁 3.1.1 数据情况 3.1.2 生命周期函数情况 3.2 使用 keep-alive 3.3 keep-alive的生命周期函数 3.4 缓存指定组件 include 3.5 不缓存指定组…

【51单片机】点亮一个LED灯(看开发板原理图十分重要)

&#x1f38a;专栏【51单片机】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【The Right Path】 &#x1f970;大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; 目录 &#x1f354;基础内容 &#x1f3f3…

HMS Core 6.10.0版本发布公告

分析服务 ◆ 事件分析下新增商品订阅分析报告&#xff0c;帮助开发者了解应用内用户付费订阅概况&#xff0c;评估订阅付费价值&#xff1b; ◆ 营销分析、用户质量、转化分析以及过滤器中&#xff0c;新增广告系列/广告任务通过ID进行搜索的功能&#xff0c;通过更便捷高效的…

【笔试强训选择题】Day8.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 文章目录…

Skywalking

Skywalking skywalking是一个apm系统&#xff0c;包含监控&#xff0c;追踪&#xff0c;并拥有故障诊断能力的 分布式系统 一、Skywalking介绍 1.什么是SkyWalking Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的产品&#xff0c;它同时吸收了Zipkin /Pinpoint …

C语言初阶之常量和变量

常量和变量 什么是常量和变量常量示例 定义变量的方法变量的命名变量的分类示例 变量的使用变量的作用域和生命周期作用域生命周期 结语 什么是常量和变量 在C程序执行过程中&#xff0c;其值不发生改变的量称为常量&#xff0c;其值可变的量称为变量。它们可与数据类型结合起…

BoldReports Embedded Reporting 5.1 Crack

Embed Paginated Reports 嵌入式报告平台&#xff0c;商业智能报告解决方案&#xff0c;探索满足各种业务需求的报告功能&#xff0c;所有功能View Features&#xff0c;像素完美报告&#xff0c;创建像素完美的分页业务报表&#xff0c;随处部署&#xff0c;选择适合您的部署环…

Android---ANR问题分析

目录 ANR 概念 超时检测机制 如何避免 ANR 问题&#xff1f; ANR 分析 ANR 问题线上监控 ANR 概念 ANR(Application Not Response)&#xff0c;是指应用程序未响应&#xff0c;Android 系统对于一些事情需要在一定时间范围内完成&#xff0c;如果超过预定时间未能得到有效…

VSCode作业1:猜数字游戏和简单计数器(包含完整代码)

目录 猜数字游戏 一、使用‘random’函数获取随机数 二、 分情况讨论输入值大小情况 三、HTML代码 四、CSS样式及运行效果 简单计数器&#xff08;计时器&#xff09; 一、使用‘setInterval’函数实现计数效果 二、使用’clearInterval‘函数实现暂停计数和重新计数效果 …

【机器学习】sklearn的集成学习用于图像分类从0到1,注意点和坑点

文章目录 前言1.需求分析1.1 场景1.2 解决方案 2. 代码2.1 提取特征2.2 构建分类器2.4 集成模型2.5 总的训练代码 3.fast api 封装4.总结 前言 深度学习崛起后&#xff0c;好像机器学习就没落了&#xff0c;但在固定场景下&#xff0c;还是很好用的。下面就是展厅项目的识别任…

解决Edge Dev更新后NewBing侧边栏消失的问题,并使用NewBing作画

文章目录 解决Edge Dev更新后NewBing侧边栏消失的问题&#xff0c;并使用NewBing作画问题来源操作步骤打开侧边栏步骤尝试让NewBing给出图像输出表情包或者其他图片使用NewBing作画 查看聊天记录插件 总结 解决Edge Dev更新后NewBing侧边栏消失的问题&#xff0c;并使用NewBing…

标签制作软件如何批量制作DotCode码

DotCode码是由不连续的点组成的二维条形码符号。设计的初衷是工业流水线上使用高速喷墨/激光打印机印刷产品有效期、批号以及序列号等。其尺寸是灵活可变的&#xff0c;可以根据货品表面的大小来调整印刷。下面带大家一起看一下在标签制作软件中如何批量制作&#xff1a; 打开…

STM32F4_十进制和BCD码的转换

目录 前言 1. BCD码 2. BCD码和十进制转换的算法 前言 最近在学习STM32单片机&#xff08;不仅仅是32&#xff09;的RTC实时时钟系统的过程中&#xff0c;需要配置时钟的时间、日期&#xff1b;这些都需要实现BCD码和十进制之间进行转换。这里和大家一起学习BCD码和十进制之…

C++函数必备简单知识

目录 1、函数的定义与声明 &#xff08;1&#xff09;定义 &#xff08;2&#xff09;声明 2、指针传参 3、引用 4、函数的引用传参 5、函数重载 overlord &#xff08;1&#xff09;参数数量不同 &#xff08;2&#xff09;参数类型不同 6、避免overlord歧义 7、内…

Opencv+Python图像像素处理

目录 二值图像的像素访问、修改 单个像素访问、修改 多个像素修改 彩色图像&#xff08;三维数组&#xff09; 像素访问、修改 BGR模式 像素访问、修改 二值图像的像素访问、修改 单个像素访问、修改 import numpy as np import cv2 as cv # 使用Numpy库中的函数zeros()可…

springboot登录验证

案例-登录认证 已经实现了部门管理、员工管理的基本功能&#xff0c;但是大家会发现&#xff0c;但没有登录&#xff0c;就直接访问到了Tlias智能学习辅助系统的后台。 这是不安全的&#xff0c;今天的主题就是登录认证。 最终要实现的效果就是用户必须登录之后&#xff0c;才…

Spark学习笔记【shuffle】

本文基本上是大数据处理框架Apache Spark设计与实现的Shuffle部分的学习。以及Spark基础知识Bambrow Shuffle解决啥问题 上游和下游&#xff0c;不同stage&#xff0c;不同的task之间是如何传递数据的。ShuffleManager管理ShuffleWrite和ShuffleRead 分为两个阶段&#xff1…

基于JavaWeb实现的寻码网文章资讯管理系统

一、技术结构 前端&#xff1a;html ajax 后端&#xff1a;SpringBootMybatis-plus 环境&#xff1a;JDK1.8 | Mysql | Maven | Redis 二、功能简介 数据库与代码截图 后端管理-登录页 后端管理-首页 后端管理-文章管理-发布文章 后端管理-文章管理-文章列表 后端管理-文…

Vue快速入门,常用指令,生命周期

Vue常用指令 案例&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"…

MySQL一次大量内存消耗的跟踪

GreatSQL社区原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。GreatSQL是MySQL的国产分支版本&#xff0c;使用上与MySQL一致。文章来源&#xff1a;GreatSQL社区原创 线上使用MySQL8.0.25的数据库&#xff0c;通过监控发现数据库在查询一个视图(80张表的u…