🚀 优质资源分享 🚀
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
背景
今年在公司内部主导了两个的行情数据系统的构建,两者均使用到了常见的时序数据压缩算法。
这里简单总结一下过程中积累的一些经验。
让我们先来思考一个问题:压缩算法生效的前提是什么?
数据本身至少要符合以下两种特性其一:
- 数据存在冗余
- 数据符合特定的概率分布
在时序数据领域,数据冗余度与相似度较高,因此天生适合进行压缩。
但对于不同类型的数据,其所适用的压缩算法也大相径庭。
下面我们逐一介绍这些数据相应的压缩算法。
整数
整型数据是构建各种应用的基石,时序型应用也不例外。
在行情数据中,存在大量的整型数据,例如:逐笔成交中的时间戳、成交量。
根据压缩算法的不同,可以将整型数据分为以下 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 >>>