Lucene的Vint类型压缩
1.vint,vlong是什么
lucene实现了可变长度int,使用1-5个字节存放一个int类型的数据,正常的int类型是4个字节,
2.vint,vlong策略
Vint压缩策略是,用每个字节的最高位做标志位,后7位为有效算术位,如果标志位为1,则说明后一个字节和当前字节是同一个数字,为0说明后一个字节是一个新的数字
说明: 大致理解是VINT每个字节8位,第一位表示后面的字节是否属于这个int,后面7位正常表示int值,
例如:
16,383 11111111 01111111
这一个这么解释: 第一个字节的第一位为1: 则后面的字节计入int,
第二个字节的第一位为0,则后面的字节不计入int,
该int的值为 第一个自己的后7位+第二个字节的后7位。 11111111111111(2进制) = 16383(10进制);
java的二进制里,是用 0 和 1 来表示正负的,最高位为符号位,最高位为 1 代表负数,最高位为 0 代表正数。
VINT压缩效率:
1个字节:0~127
2个字节: -127~0 和 127~16383
3个字节: -16383~-127 和 16363~2097151
4个字节: -2097151~-16383 和 2097151~268435455
5个字节: 7*5=35 > 32(位) 范围比整个int还要大,不过因为转化的值是存到int里,所以这里的范围就是int
压缩率根据数据组成不同而有差异
变长长整型和变长整型原理相同,位数加大了而已。
lucene-7.5.0写代码如下:
org.apache.lucene.store.DataOutput
public final void writeVInt(int i) throws IOException {
while ((i & ~0x7F) != 0) {
writeByte((byte)((i & 0x7F) | 0x80));
i >>>= 7;
}
writeByte((byte)i);
}
lucene-7.5.0 读代码如下:
org.apache.lucene.store.DataInput
public final int readVInt() throws IOException {
/* This is the original code of this method,
* but a Hotspot bug (see LUCENE-2975) corrupts the for-loop if
* readByte() is inlined. So the loop was unwinded!
byte b = readByte();
int i = b & 0x7F;
for (int shift = 7; (b & 0x80) != 0; shift += 7) {
b = readByte();
i |= (b & 0x7F) << shift;
}
return i;
*/
byte b = readByte();
if (b >= 0) return b;
int i = b & 0x7F;
b = readByte();
i |= (b & 0x7F) << 7;
if (b >= 0) return i;
b = readByte();
i |= (b & 0x7F) << 14;
if (b >= 0) return i;
b = readByte();
i |= (b & 0x7F) << 21;
if (b >= 0) return i;
b = readByte();
// Warning: the next ands use 0x0F / 0xF0 - beware copy/paste errors:
i |= (b & 0x0F) << 28;
if ((b & 0xF0) == 0) return i;
throw new IOException("Invalid vInt detected (too many bits)");
}