压缩算法生效的前提是什么?
数据本身至少要符合以下两种特性其一:
- 数据存在冗余
- 数据符合特定的概率分布
根据压缩算法的不同,可以将整型数据分为以下 3 类:
- 无符号整型 —— Varint
- 有符号整型 —— ZigZag
- 时间戳 —— Delta2 + Simple8b
VarInt编码
数字在日常生活中出现的概率并不是均匀分布的,一个著名的例子是本福特定律
,该定律常被用于辨别数据的真伪。
varint是一种对正整数进行可变长字节编码的方法,大多数情况下可起到数据压缩的作用。通常,一个int型整数占4个字节,若该整数的数值小于256,显然一个字节的空间就能存储,浪费了3个字节的空间,而varint就起到了压缩数据的作用。整数数值越小,需要存储的字节数就越少。
在实际场景中小数字的使用率远远多于大数字,因此通过Varint编码对于大部分场景都可以起到很好的压缩效果。
Varint编码通常使用7位表示一个字节,其中最高位(第8位)用作标记位,表示是否还有更多的字节用于表示该整数。如果最高位为0,则表示该字节是该整数的最后一个字节;如果最高位为1,则表示还有更多的字节用于表示该整数。
Varint编码后数据的字节是按照小端序排列的。最低有效组在前,或者叫最低有效字节在前
VarInt编码
public static byte[] intToVInt(int i){
if (i<0){
throw new IllegalArgumentException("VInt编码仅支持正整数或无符号整数");
}
byte[] arr = new byte[5];
int index = 0;
while ((i & ~0x7F) != 0) {
arr[index++] = ((byte)((i & 0x7f) | 0x80));
i >>>= 7;
}
arr[index] = (byte) i;
if (index !=4){
byte[] news = new byte[index+1];
System.arraycopy(arr,0,news,0,index+1);
return news;
}
return arr;
}
VarInt解码
public static int vintToInt(byte[] i){
if (i.length>5 || i.length<=0){
throw new IllegalArgumentException("无效的VInt编码");
}
int result = 0;
for (int j = 0; j < i.length; j++) {
result |= ((i[j]&0x7f) <<(j*7));
if ((i[j]&0x80)==0){
break;
}
}
return result;
}