源码系列去重编码
原文: https://www.amazingkoala.com.cn/Lucene/yasuocunchu/2019/0130/29.html
去重编码是 Lucene 中对 int 类型数据的一种压缩存储方式,在 FacetsConfig 类中用到此方法来处理 int 类型数据。其优点在于,存储一个原本需要固定 4 个字节空间大小的 int 类型的数据,最好的情况下只要 1 个字节,最差的情况下需要 5 个字节。
处理过程
去重编码的过程主要分三步:
- 排序
- 去重
- 差值存储
关系图
根据 int 数值的大小,在去重编码后存储该数值所需要的字节大小关系图如下
数值范围(指数)数值范围(10 进制)字节大小0 ~ (2^7 - 1)0 ~ 12712^7 ~ (2^14 - 1)128 ~ 1638322^14 ~ (2^21 - 1)16384 ~ 209715132^21 ~ (2^28 - 1)2097152 ~ 26843545542^28 ~ *268435456 ~ *5
去重编码中最重要的一点是差值存储,从上图可以看出,我们在存储一组有序的数值时,除第一个数值外,其他的数值如果只存储跟它前面数值的差值,那么可以使得达到最大的压缩比。这种方式在存储大数值时的有点更明显。
例如我们有一组数据:{17832,17842,17844},如果我们直接对3个数值进行存储(不存储差值),那么最终需要9个字节才能存储这三个数值,而如果我们进行差值存储,那么我们需要存储的数据就变为: {17832,10,2},其中10是17842跟17832的差值,2是17844跟17842的差值,那么最终只需要5个字节存储即可。
去重编码源码
相比较源码,删除了代码中的 IntsRef 类,便于理解
encode
public class ConvertIntToByteRef {
public static BytesRef dedupAndEncode(int[] ordinals) {
// 对 ordinal[]数组排序,目的是为了去重跟计算差值
Arrays.sort(ordinals, 0, ordinals.length);
// 先给每一个int类型分配5个字节大小的空间, 每个字节中只有7位是有效字节(描述数值),最高位是个定界符, 所以一个int类型最多要5个字节
byte[] bytes = new byte[5*ordinals.length];
// 记录上次处理的值,用于去重判断
int lastOrd = -1;
int upto = 0;
// 遍历处理每一个int数值
for(int i=0;i<ordinals.length;i++) {
int ord = ordinals[i];
// ord could be == lastOrd, so we must dedup:
// 去重操作,当前处理的数值跟上一个如果一样的话,skip
if (ord > lastOrd) {
// 存储差值的变量
int delta;
if (lastOrd == -1) {
// 处理第一个值, 只能储存原始的数值
delta = ord;
} else {
// 处理非第一个值,就可以储存这个值与前一个值的差值
delta = ord - lastOrd;
}
// if语句为真说明delta是 0~(2^7 - 1)内的值, 需要1个字节存储
if ((delta & ~0x7F) == 0) {
// 注意的是第8位是0(位数从0计数), 一个byte的最高位如果是0,表示是数值的最后一个byte
bytes[upto] = (byte) delta;
upto++;
// if语句为真说明delta是 2^7 ~ (2^14 - 1)内的值, 需要2个字节存储
} else if ((delta & ~0x3FFF) == 0) {
// 这个字节的最高位是1, 表示下一个byte字节和当前字节属于同一个int类型的一部分
bytes[upto] = (byte) (0x80 | ((delta & 0x3F80) >> 7));
// 这个字节的最高位是0, 表示表示是数值的最后一个byte
bytes[upto + 1] = (byte) (delta & 0x7F);
upto += 2;
// if语句为真说明delta是 2^14 ~ (2^21 - 1)内的值, 需要3个字节存储
} else if ((delta & ~0x1FFFFF) == 0) {
// 这个字节的最高位是1, 表示下一个byte字节和当前字节属于同一个int类型的一部分
bytes[upto] = (byte) (0x80 | ((delta & 0x1FC000) >> 14)
- 原文作者:知识铺
- 原文链接:https://geek.zshipu.com/post/%E4%BA%92%E8%81%94%E7%BD%91/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97%E5%8E%BB%E9%87%8D%E7%BC%96%E7%A0%81/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com