Java HdrHistogram依赖 直方图统计算法
介绍
HdrHistogram 可以用较少的资源计算平均值、中位数等各类统计值
源码地址,包含多种语言
https://github.com/HdrHistogram
Java使用方法
依赖
<dependency>
<groupId>org.hdrhistogram</groupId>
<artifactId>HdrHistogram</artifactId>
<version>1.2.1</version>
</dependency>
public class Test {
public static void main(String[] args) {
// 需指定预估的最大值
Histogram histogram = new Histogram(5400000000000L, 4);
for(int i = 1; i < 10000000; i = i * 2) {
// 塞入需要计算的值
histogram.recordValue(i);
}
long t1 = System.nanoTime();
// 求出平均值
double a = histogram.getMean();
long t2 = System.nanoTime();
System.out.println(a + " " + (t2 - t1) + "ns");
}
}
算法
HdrHistogram采用的是分桶的方式进行实现。
不需要将每个值都存下来,而是通过压缩存储,但结果也不是精确解。
在舍弃一点点精度的情况下省下大量内存。
接下来先来了解这个算法关键的三个步骤
- 桶的拆分
- 压缩存储
- 迭代计算
桶的拆分
该算法用桶和子桶来表示被计算的数
被计算的数: 比如一个数列需要求平均值,指数列中的每一个值
桶: 代表二进制的1位
子桶: 每个桶下面都有定量的子桶(后面会慢慢清晰)
被计算的数如何拆分成桶和子桶:
压缩存储
将上面计算得到的桶号和子桶号,再求出新的值,进行压缩存储
压缩数组: 存储长度为桶*子桶
整体流程是:
- 原始数据分解为桶与子桶
- 通过桶与子桶计算出新值
- 在压缩数组中将该新值对应的下标数量累计
- 压缩数组的每一格可对应一个近似原始数据
各个原始数据在压缩数组中的什么位置:
压缩数组中各个位置对应的值:
迭代计算
比如求平均值则会迭代上述压缩数组进行求值
压缩数组中记录原始数据的数量:
计算:
特点
HdrHistogram算法适用于数据量大,且大部分数据集中在第一个桶中,此时该计算结果更接近真实值。
子桶的大小可以根据实际情况设置,让大部分数值处于第一个子桶。
子桶容量越大结果越精确,但需要的内存越多,可适当调整大小。