ElasticSearch 如何使用 TDigest 算法计算亿级数据的百分位数?

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 今天,我们就来了解一下其聚合分析中较为常见的 percentiles 百分位数分析。n 个数据按数值大小排列,处于 p% 位置的值称第 p 百分位数。比如说,ElasticSearch 记录了每次网站请求访问的耗时,需要统计其 TP99,也就是整体请求中的 99% 的请求的最长耗时。

大家好,我是历小冰。


ElasticSearch 作为一个分布式的开源搜索和分析引擎,不仅能够进行全文匹配搜索,还可以进行聚合分析。


今天,我们就来了解一下其聚合分析中较为常见的 percentiles 百分位数分析。n 个数据按数值大小排列,处于 p% 位置的值称第 p 百分位数。比如说,ElasticSearch 记录了每次网站请求访问的耗时,需要统计其 TP99,也就是整体请求中的 99% 的请求的最长耗时。

近似算法

当数据量较小或者数据集中存储在同一位置时,进行类似 TP99 这样的百分位数分析就很容易。但当数据量不断增长时,对于数据进行聚合分析就需要在数据量,精确度和实时性三个方面进行取舍,只能满足其中两项。

image.png

如上图所示,我们一共有三种选择方案:

  • 有限数据计算:选择了精确度高和实时性,必然不能处理较大量级的数据,比如 MySQL 对单机数据进行统计分析;
  • 离线计算:选择了大数据量和精确度高,导致实时性较差,比如 Hadoop 可以在 PB 级别数据上提供精确分析,但是可能要很长时间;
  • 近似计算:选择了大数据量和实时性,但会损失一定的精确度,比如0.5%,但提供相对准确的分析结果。

Elasticsearch 目前支持两种近似算法,分别是 cardinality 和 percentiles。


cardinality 用于计算字段的基数,即该字段的 distinct 或者 unique 值的数量。cardinality 基于 HyperLogLog(HLL)算法实现, HLL 会先对数据进行哈希运算,然

后根据哈希运算的结果中的位数做概率估算从而得到基数。有关 HLL 算法的细节可以阅读《Redis HyperLogLog 详解》一文。


而 percentiles 则是本文的重点。

百分位数

ElasticSearch 可以使用 percentiles 来分析指定字段的百分位数,具体请求如下所示,分析 logs 索引下的 latency 字段的百分位数,也就是计算网站请求的延迟百分位数。

image.png

percentiles 默认情况下会返回一组预设的百分位数值,分别是 [1, 5, 25, 50, 75, 95, 99] 。它们表示了人们感兴趣的常用百分位数值,极端的百分位数在范围的两边,其他的一些处于中部。具体的返回值如下图所示,我们可以看到最小延时在 75ms 左右,而最大延时差不多有 600ms。与之形成对比的是,平均延时在 200ms 左右。

image.png

和前文的 cardinality 基数一样,计算百分位数需要一个近似算法。


对于少量数据,在内存中维护一个所有值的有序列表, 就可以计算各类百分位数,但是当有几十亿数据分布在几十个节点时,这类算法是不现实的。


因此,percentiles 使用 TDigest 算法,它是一种近似算法,对不同百分位数的计算精确度不同,较为极端的百分位数范围更加准确,比如说 1% 或 99% 的百分位要比 50% 的百分位要准确。这是一个好的特性,因为多数人只关心极端的百分位。

TDigest 算法

TDigest 是一个简单,快速,精确度高,可并行化的近似百分位算法,被 ElastichSearch、Spark 和 Kylin 等系统使用。TDigest 主要有两种实现算法,一种是 buffer-and-merge 算法,一种是 AV L树的聚类算法。


TDigest 使用的思想是近似算法常用的 Sketch,也就是素描,用一部分数据来刻画整体数据集的特征,就像我们日常的素描画一样,虽然和实物有差距,但是却看着和实物很像,能够展现实物的特征。


下面,我们来介绍一下 TDigest 的原理。比如有 500 个 -30 ~ 30 间的数字,我们可以使用概率密度函数(PDF)来表示这一数据集。该函数上的某一点的 y 值就是其 x 值在整体数据集中的出现概率,整个函数的面积相加就正好为 1 ,可以说它刻画了数据在数据集中的分布态势(大家较为熟悉的正太分布示意图展示的就是该函数)。

image.png

有了数据集对应的 PDF 函数,数据集的百分位数也能用 PDF 函数的面积表示。如下图所示,75% 百分位数就是面积占了 75% 时对应的 x 坐标。

image.png

我们知道,PDF 函数曲线中的点都对应着数据集中的数据,当数据量较少时,我们可以使用数据集的所有点来计算该函数,但是当数据量较大时,我们只有通过少量数据来代替数据集的所有数据。


这里,我们需要将数据集进行分组,相邻的数据分为一组,用 平均数(Mean)和 个数(Weight)来代替这一组数。这两个数合称为 Centroid(质心数),然后用这个质心数来计算 PDF,这就是 TDigest 算法的核心思想。

image.png

如上图所示,质心数的平均值作为 x 值,个数作为 y 值,可以通过这组质心数大致绘制出这个数据集的 PDF 函数。


对应的,计算百分位数也只需要从这些质心数中找到对应的位置的质心数,它的平均值就是百分位数值。

image.png

很明显,质心数的个数值越大,表达它代表的数据越多,丢失的信息越大,也就越不精准。如上图所示,太大的质心数丢失精准度太多,太小的质心数则有消耗内存等资源较大,达不到近似算法实时性高的效果。


所以,TDigest 在压缩比率(压缩比率越大,质心数代表的数据就要越多)的基础上,按照百分位数来控制各个质心数代表的数据的多少,在两侧的质心数较小,精准度更高,而在中间的质心数则较大,以此达到前文所说的 1% 或 99% 的百分位要比 50% 的百分位要准确的效果。

源码分析

ElasticSearch 直接使用了 TDigest 的开源实现 t-digest,其 github 地址为 https://github.com/tdunning/t-digest,我们可以在 ElastichSearch 的 TDigestState 类看到其对 t-digest 实现的封装。

t-digest 提供了两种 TDigest 算法的实现:

  • MergingDigest 对应上文所说的 buffer-and-merge 算法
  • AVLGroupTree对应 AVL 树的聚类算法。

MergingDigest 用于数据集已经排序的场景,可以直接根据压缩比率计算质心数,而 AVLGroupTree 则需要使用 AVL 树来自信对数据根据其”接近程度“进行判断,然后计算质心数。

MergingDigest的实现较为简单,顾名思义,其算法名称叫做 buffer-and-merge,所以实现上使用 tempWeight 和  tempMean 两个数组来代表质心数数组,将数据和保存的质心数进行 merge,然后如果超出 weight 上限,则创建新的质心数,否则修改当前质心数的平均值和个数。

AVLGroupTreeMergingDigest 相比,多了一步通过 AVL 二叉平衡树搜索数据最靠近质心数的步骤,找到最靠近的质心数后,也是将二者进行 merge,然后判断是否超过 weight 上线,进行修改或者创建操作。

下面,我们直接来看 AVLGroupTree 的 add 方法。

image.png

当 ElasticSearch 处理一个数据集时,就是不断将数据集中的数据通过调用 add 函数加入到质心数中,然后统计完毕后,调用其 quantile 来计算百分位数。

后记

欢迎大家继续关注程序员历小冰,后续会继续为大家带来有关数据存储,数据分析,分布式相关的文章。下一篇文章我们回来学习一下 ElasticSearch 的其他聚合分析操作的实现原理。

个人博客,欢迎来玩

参考


相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
1月前
|
数据采集 机器学习/深度学习 算法
【优秀设计案例】基于K-Means聚类算法的球员数据聚类分析设计与实现
本文通过K-Means聚类算法对NBA球员数据进行聚类分析,旨在揭示球员间的相似性和差异性,为球队管理、战术决策和球员评估提供数据支持,并通过特征工程和结果可视化深入理解球员表现和潜力。
【优秀设计案例】基于K-Means聚类算法的球员数据聚类分析设计与实现
|
10天前
|
存储 算法 测试技术
预见未来?Python线性回归算法:数据中的秘密预言家
【9月更文挑战第11天】在数据的海洋中,线性回归算法犹如智慧的预言家,助我们揭示未知。本案例通过收集房屋面积、距市中心距离等数据,利用Python的pandas和scikit-learn库构建房价预测模型。经过训练与测试,模型展现出较好的预测能力,均方根误差(RMSE)低,帮助房地产投资者做出更明智决策。尽管现实关系复杂多变,线性回归仍提供了有效工具,引领我们在数据世界中自信前行。
25 5
|
17天前
|
算法 数据可视化 数据安全/隐私保护
基于LK光流提取算法的图像序列晃动程度计算matlab仿真
该算法基于Lucas-Kanade光流方法,用于计算图像序列的晃动程度。通过计算相邻帧间的光流场并定义晃动程度指标(如RMS),可量化图像晃动。此版本适用于Matlab 2022a,提供详细中文注释与操作视频。完整代码无水印。
|
19天前
|
编解码 算法 图形学
同一路RTSP|RTMP流如何同时回调YUV和RGB数据实现渲染和算法分析
我们播放RTSP|RTMP流,如果需要同时做渲染和算法分析的话,特别是渲染在上层实现(比如Unity),算法是python这种情况,拉两路流,更耗费带宽和性能,拉一路流,同时回调YUV和RGB数据也可以,但是更灵活的是本文提到的按需转算法期望的RGB数据,然后做算法处理
|
22天前
|
存储 缓存 监控
|
1月前
|
存储 算法 大数据
小米教你:2GB内存搞定20亿数据的高效算法
你好,我是小米。本文介绍如何在2GB内存中找出20亿个整数里出现次数最多的数。通过将数据用哈希函数分至16个小文件,每份独立计数后选出频次最高的数,最终比对得出结果。这种方法有效解决大数据下的内存限制问题,并可应用于更广泛的场景。欢迎关注我的公众号“软件求生”,获取更多技术分享!
147 12
|
1月前
|
编解码 算法 Linux
Linux平台下RTSP|RTMP播放器如何跟python交互投递RGB数据供视觉算法分析
在对接Linux平台的RTSP播放模块时,需将播放数据同时提供给Python进行视觉算法分析。技术实现上,可在播放时通过回调函数获取视频帧数据,并以RGB32格式输出。利用`SetVideoFrameCallBackV2`接口设定缩放后的视频帧回调,以满足算法所需的分辨率。回调函数中,每收到一帧数据即保存为bitmap文件。Python端只需读取指定文件夹中的bitmap文件,即可进行视频数据的分析处理。此方案简单有效,但应注意控制输出的bitmap文件数量以避免内存占用过高。
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习的伦理困境:数据隐私与算法偏见
【8月更文挑战第9天】随着深度学习技术的飞速发展,其对个人隐私和数据安全的威胁日益凸显。本文探讨了深度学习在处理敏感信息时可能导致的数据泄露风险,以及训练数据中固有偏见如何影响算法公正性的问题。文章分析了当前隐私保护措施的局限性,并提出了减少算法偏见的方法。最后,本文讨论了如何在保障技术进步的同时,确保技术应用不侵犯个人权益,呼吁建立更为全面的伦理框架以指导深度学习的发展。
|
1月前
|
算法 Go Python
[算法]计算斐波拉契数列
[算法]计算斐波拉契数列
|
1月前
|
数据采集 算法 数据可视化
基于K-Means聚类算法对球员数据的聚类分析,可以自主寻找最优聚类数进行聚类
本文介绍了一个基于K-Means聚类算法的NBA球员数据分析项目,该项目通过采集和分析球员的得分、篮板、助攻等统计数据,使用轮廓系数法和拐点法确定最优聚类数,将球员分为不同群组,并提供了一个可视化界面以便直观比较不同群组的球员表现。
基于K-Means聚类算法对球员数据的聚类分析,可以自主寻找最优聚类数进行聚类