背景
今年在公司内部主导了两个的行情数据系统的构建,两者均使用到了常见的时序数据压缩算法。
这里简单总结一下过程中积累的一些经验。
让我们先来思考一个问题:压缩算法生效的前提是什么?
数据本身至少要符合以下两种特性其一:
- 数据存在冗余
- 数据符合特定的概率分布
在时序数据领域,数据冗余度与相似度较高,因此天生适合进行压缩。
但对于不同类型的数据,其所适用的压缩算法也大相径庭。
下面我们逐一介绍这些数据相应的压缩算法。
整数
整型数据是构建各种应用的基石,时序型应用也不例外。
在行情数据中,存在大量的整型数据,例如:逐笔成交中的时间戳、成交量。
根据压缩算法的不同,可以将整型数据分为以下 3 类:
- 无符号整型 —— Varint
- 有符号整型 —— ZigZag
- 时间戳 —— Delta2 + Simple8b
Varint
一个 32 位的无符号整型能表达 0 - 4294967295 之间的任意数字
但这些数字在日常生活中出现的概率并不是均匀分布的,一个著名的例子是 本福特定律 ,该定律常被用于辨别数据的真伪。
通常情况下,较小的数字出现的概率会高于极大的数据。
以年龄为例,无论人口如何分布,大部分人的年龄都位于 0 ~ 100 之间。
表示 128 仅需要 7bit 足矣,如果使用 32bit 的无符号整型进行存储,意味着至少浪费了 24bit。
幸运的是,我们能通过一种自适应编码方式来减少这种浪费 —— Varint。
public class VarIntCodec {
static int encodeInt(int v, byte[] bytes, int offset) {
if (v < 0) {
throw new IllegalStateException();
} else if (v < 128) {
bytes[offset++] = (byte) v;
} else if (v < 16384) {
bytes[offset++] = (byte) (v | 0x80);
bytes[offset++] = (byte) ((v >>> 7) & 0x7F);
} else if (v < 2097152) {
bytes[offset++] = (byte) (v | 0x80);
bytes[offset++] = (byte) ((v >>> 7) | 0x80);
bytes[offset++] = (byte) (v >>> 14);
} else if (v < 268435456) {
bytes[offset++] = (byte) (v | 0x80);
bytes[offset++] = (byte) ((v >>> 7) | 0x80);
bytes[offset++] = (byte) ((v >>> 14) | 0x80);
bytes[offset++] = (byte) (v >>> 21);
} else {
bytes[offset++] = (byte) (v | 0x80);
bytes[offset++] = (byte) ((v >>> 7) | 0x80);
bytes[offset++] = (byte) ((v >>> 14) | 0x80);
bytes[offset++] = (byte) ((v >>> 21) | 0x80);
bytes[offset++] = (byte) (v >>> 28);
}
return offset;
}
static int decodeInt(byte[] bytes, int[] offset) {
int val;
int off = offset[0];
byte b0, b1, b2, b3;
if ((b0 = bytes[off++]) >= 0) {
val = b0;
} else if ((b1 = bytes[off++]) >= 0) {
val = (b0 & 0x7F) + (b1 << 7);
} else if ((b2 = bytes

本文介绍了时序数据压缩算法的应用背景和各种压缩方法,包括整数压缩(Varint、ZigZag、Delta2、Simple8b)、浮点数压缩(有损和无损)以及字符串压缩(标签型和非标签型)。通过这些算法,可以有效地减少存储空间,提高数据处理效率。
最低0.47元/天 解锁文章
1687

被折叠的 条评论
为什么被折叠?



