lucene索引中有许多数字(整形)需要存储,因此也就针对单个int进行了压缩处理。
对于一个字节的8个bit,后7个bit表示实际的值,第一个bit表示后面是否还有其他的字节。比如:
比如00000001 最高位表示0,那么说明这个数就是一个字节表示,有效位是后面的七位0000001,值为1。10000010 00000001 第一个字节最高位为1,表示后面还有字节,第二位最高位0表示到此为止了,即就是两个字节。
需要主要的是,字节的排列顺序是由右到左的,比如说
128为 1000 0000 0000 0001 右边的字节代表有一个128,左边的为补满128的余数。即是由左向右进位的
129为 1000 0001 0000 0001
对于一个字节的8个bit,后7个bit表示实际的值,第一个bit表示后面是否还有其他的字节。比如:
比如00000001 最高位表示0,那么说明这个数就是一个字节表示,有效位是后面的七位0000001,值为1。10000010 00000001 第一个字节最高位为1,表示后面还有字节,第二位最高位0表示到此为止了,即就是两个字节。
需要主要的是,字节的排列顺序是由右到左的,比如说
128为 1000 0000 0000 0001 右边的字节代表有一个128,左边的为补满128的余数。即是由左向右进位的
129为 1000 0001 0000 0001
130为 1000 0010 0000 0001
如下
有点总结:
1,由于java中一个int占用4个字节,因此对于小整数,那么将会节省空间。
2,这种方式解压缩的效率会更好,其中的原因主要是由于其位运算造成的(我还没研究透),先把代码贴出来以后研究吧。
<span style="font-size:18px;">/** Writes an int in a variable-length format. Writes between one and
* five bytes. Smaller values take fewer bytes. Negative numbers are not
* supported.
* @see IndexInput#readVInt()
*/
public void writeVInt(int i) throws IOException {
while ((i & ~0x7F) != 0) {
writeByte((byte)((i & 0x7f) | 0x80));
i >>>= 7;
}
writeByte((byte)i);
}
/** Reads an int stored in variable-length format. Reads between one and
* five bytes. Smaller values take fewer bytes. Negative numbers are not
* supported.
* @see IndexOutput#writeVInt(int)
*/
public int readVInt() throws IOException {
byte b = readByte();
int i = b & 0x7F;
for (int shift = 7; (b & 0x80) != 0; shift += 7) {
b = readByte();
i |= (b & 0x7F) << shift;
}
return i;
}
</span>
下面介绍另外一种压缩规则(差值压缩Delta)
比如在lucene索引中会保存文档id等整数,term在文档中的位置。lucene中使用vint来代替整数,但是随着整数的增大,其压缩效率几乎就没有了,甚至由于其字节头标示位的原因,可能还会造成索引变大。
差值规则即存储一系列整数的时候,后面的整数仅仅保存和前面整数的差值即可。如:
12345 12348 12389
上面3个整数的存储如下:
(vint)0 12345
(vint)3
(vint)41