范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

BitmapRoaringBitmap原理分析

  作者:京东科技 曹留界
  在人群本地化实践中我们介绍了人群ID中所有的pin的偏移量可以通过Bitmap存储,而Bitmap所占用的空间大小只与偏移量的最大值有关系。假如现在要向Bitmap内存入两个pin对应的偏移量,一个偏移量为1,另一个偏移量为100w,那么Bitmap存储直接需要100w bit的空间吗?数据部将偏移量存入Bitmap时,又如何解决数据稀疏问题呢?本文将为大家解答这个问题。 一、BitMap
  Bitmap的基本思想就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。由于采用了Bit为单位来存储数据,因此可以大大节省存储空间。
  如果想将数字2存入位图中,则只需要将位图数组中下标为2的数组值置为1。
  但是,如果现在要存储两个人群ID对应的偏移量,一个偏移量为1,另一个偏移量为100w,如果将这两个值直接放到位图数组中,那么位图数组所需要的空间就是100wbit,会产生大量的空间浪费。那么有什么方法可以避免空间浪费吗?答案就是 RoaringBitMap ! 二、RoaringBitMap
  RoaringBitMap是一种高效压缩位图,简称RBM。RBM的概念于2016年由S. Chambi、D. Lemire、O. Kaser等人在论文《Better bitmap performance with Roaring bitmaps》  《Consistently faster and smaller compressed bitmaps with Roaring》中提出。下面我们结合java中的实现对其进行介绍。 2.1 实现思路
  RBM主要将32位的整型(int)分为高16位和低16位(两个short),其中高16位对应的数字使用16位整型有序数组存储,低16位根据不同的情况选择三种不同的container来存储,这三种container分别为:
  •Array Container
  底层数据结构为short类型的数组,直接将数字低16位的值存储到该数组中。short类型的数组始终保持有序,方便使用二分查找,且不会存储重复数值。因为这种Container存储数据没有任何压缩,因此只适合存储少量数据。其内部数组容量是动态变化的,当容量不够时会进行扩容,最大容量为4096。由于数组是有序的,存储和查询时都可以通过二分查找快速定位其在数组中的位置。
  ArrayContainer占用的空间大小与存储的数据量为线性关系,每个short为2字节,因此存储了N个数据的ArrayContainer占用空间大致为2N字节。存储一个数据占用2字节,存储4096个数据占用8kb。
  •Bitmap Container
  底层实现为位图 。这种Container使用long[]存储位图数据。我们知道,每个Container处理16位整形的数据,也就是0~65535,因此根据位图的原理,需要65536个比特来存储数据,每个比特位用1来表示有,0来表示无。每个long有64位,因此需要1024个long来提供65536个比特。
  因此,每个BitmapContainer在构建时就会初始化长度为1024的long[]。这就意味着,不管一个BitmapContainer中只存储了1个数据还是存储了65536个数据,占用的空间都是同样的8kb。
  •Run Container
  RunContainer中的Run指的是行程长度压缩算法(Run Length Encoding),对连续数据有比较好的压缩效果。
  它的原理是,对于连续出现的数字,只记录初始数字和后续数量。即:
  •对于数列 11  ,它会压缩为11,0  ;
  •对于数列 11,12,13,14,15  ,它会压缩为11,4  ;
  •对于数列 11,12,13,14,15,21,22  ,它会压缩为11,4,21,1  ;
  源码中的short[] valueslength中存储的就是压缩后的数据。
  这种压缩算法的性能和数据的连续性(紧凑性)关系极为密切,对于连续的100个short,它能从200字节压缩为4字节,但对于完全不连续的100个short,编码完之后反而会从200字节变为400字节。
  如果要分析RunContainer的容量,我们可以做下面两种极端的假设:
  最好情况,即只存在一个数据或只存在一串连续数字,那么只会存储2个short,占用4字节
  最坏情况,0~65535的范围内填充所有的奇数位(或所有偶数位),需要存储65536个short,128kb
  也就RBM在存入一个32位的整形数字时,会先按照该数字的高16位进行分桶,以确定该数字要存入到哪个桶中。确定好分桶位置后,再将该数字对应的低16位放入到当前桶所对应的container中。
  举个栗子
  以十进制数字131122为例,现在我们要将该数字放入到RBM中。第一步,先将该数字转换为16进制,131122对应的十六进制为0x00020032;其中,高十六位对应0x0002,首先我们找到0x0002所在的桶,再将131122的低16位存入到对应的container中,131122的低16位转换为10进制就是50,没有超过ArrayContainer的容量4096,所以将低16位直接放入到对应的ArrayContainer中。
  如果要插入的数字低16位超过了4096,RBM会将ArrayContainer转换为BitMapContainer。反之,如果数据在删除之后,数组中的最大数据小于4096,RBM会将BitMapContainer转换回ArrayContainer。
  RBM处理的是32位的数字,如果我们想处理Long类型的数字怎么办呢?这个时候可以使用Roaring64NavigableMap。Roaring64NavigableMap也是使用拆分模式,将一个long类型数据,拆分为高32位与低32位,高32位代表索引,低32位存储到对应RoaringBitmap中,其内部是一个TreeMap类型的结构,会按照signed或者unsigned进行排序,key代表高32位,value代表对应的RoaringBitmap。 三、空间占用对比
  1、连续数据
  分别向位图中插入1w、10w、100w、1000w条连续数据,并且对比BitMap和RoaringBitMap占用空间的大小。比较结果如下表所示:
  10w数据占用空间
  100w数据占用空间
  1000w数据占用空间
  BitMap
  97.7KB
  976.6KB
  9.5MB
  RoaringBitMap
  16KB
  128KB
  1.2MB @Test     public void testSizeOfBitMap() {          //对比占用空间大小 - 10w元素         RoaringBitmap roaringBitmap3 = new RoaringBitmap();         byte[] bits2 = new byte[100000];         for (int i = 0; i < 100000; i++) {                 roaringBitmap3.add(i);                 bits2[i] = (byte) i;         }         System.out.println("10w数据 roaringbitmap byte size:"+ roaringBitmap3.getSizeInBytes());         System.out.println("10w数据 位图数组 byte size:"+bits2.length);          RoaringBitmap roaringBitmap4 = new RoaringBitmap();         byte[] bits3 = new byte[1000000];         for (int i = 0; i < 1000000; i++) {             roaringBitmap4.add(i);             bits3[i] = (byte) i;         }         System.out.println("100w数据 roaringbitmap byte size:"+ roaringBitmap4.getSizeInBytes());         System.out.println("100w数据 位图数组 byte size:"+bits3.length);          RoaringBitmap roaringBitmap5 = new RoaringBitmap();         byte[] bits4 = new byte[10000000];         for (int i = 0; i < 10000000; i++) {             roaringBitmap5.add(i);             bits4[i] = (byte) i;         }         System.out.println("1000w数据 roaringbitmap byte size:"+ roaringBitmap5.getSizeInBytes());         System.out.println("1000w数据 位图数组 byte size:"+bits4.length);     }
  运行截图:
  2、稀疏数据
  我们知道,位图所占用空间大小只和位图中索引的最大值有关系,现在我们向位图中插入1和999w两个偏移量位的元素,再次对比BitMap和RoaringBitMap所占用空间大小。
  占用空间
  BitMap
  9.5MB
  RoaringBitMap
  24Byte @Test     public void testSize() {         RoaringBitmap roaringBitmap5 = new RoaringBitmap();         byte[] bits4 = new byte[10000000];         for (int i = 0; i < 10000000; i++) {             if (i == 1 || i == 9999999) {                 roaringBitmap5.add(i);                 bits4[i] = (byte) i;             }         }         System.out.println("两个稀疏数据 roaringbitmap byte size:"+ roaringBitmap5.getSizeInBytes());         System.out.println("两个稀疏数据 位图数组 byte size:"+bits4.length);     }
  运行截图:

摄影师皮克砸坏我的手机带孩子超速连闯红灯近日巴萨中卫皮克与夏奇拉分居引关注,根据狗仔摄影师JordiMartn透露,皮克摔坏了自己的手机,随后带着儿子米兰驾车离开,一路连闯了好几个红灯。JordiMartn在推特上写道我孩子夏天不能吹空调?错!正确吹空调让娃睡得香,不长痱子文菁妈婆婆推开房间门感觉凉飕飕的,马上大声嚷嚷起来,孩子睡觉怎么能吹空调?会着凉感冒的,真是不懂事,就立马把空调给关了!你们年轻人睡觉要用空调,孩子可不能吹,以后就让孩子跟我睡吧。想要孩子将来少走弯路,家长要谨记养儿三不和养女四忌大家好,我是践行终身学习的西红柿妈妈!家长们,你家生的女儿还是男孩呢?现在养育孩子很不容易,需要我们科学育儿,而且男孩和女孩也是不同的养法。一旦父母用错了方法犯了不该犯的禁忌,孩子孩子无六月?夏季别盲目捂宝宝,关键部位不着凉就好天气越来越热了,相比之下,宝妈最怕在6月份左右坐月子,不仅自己遭罪,宝宝也不好过。虽然一直在倡导科学坐月子,但还是有很多人相信捂月子这一方法。让宝妈多穿多盖还不够,新生儿也要盖得厚适合去海边发的文案1海的那边是海2一场海边的旅行3落日余晖连着海洋4撞进夏日的海风里5零碎的岛屿会找到海6海风会吹走所有烦恼7海是一座没有墙的城8你说大海会不会等风9海的故事只要海鸥聆听10今天的快值!1000块能换大约5000泰铢,当地人告诉你能享受什么样的服务1000元人民币在泰国能兑换5000泰铢,这笔钱可以享受哪些服务呢?就让泰国美女告诉我们吧!(此处已添加小程序,请到今日头条客户端查看)现如今,出国旅行已经成了国民休闲娱乐的主要方T恤阔腿裤,夏天这样穿,时髦高级又显瘦,关键还不易撞衫每年夏天都会出现一大批新潮的服装款式,但是,也正是有了越来越多的选择项,女性便产生了更多的选择难题。其实,比起花哨繁琐的服装款式,倒不如选择夏日最经典好穿的单品,那就是T恤阔腿裤的Woj湖人会在明年夏天分崩离析,开启下一轮重建2020年总冠军湖人ESPN记者Woj在节目中提到湖人队未来的前景。Woj说有消息源告诉我,詹姆斯对于重返克利夫兰,持开放态度。而今年夏天是否跟湖人续约,就成为他是否离开的关键。而观天池瀑布,赏峡谷奇观,让我带你看看夏天的长白山究竟有多美?长白山是我国十大名山之一,与五岳齐名。是风光秀丽景色迷人的关东第一山,素有千年积雪万年松,直上人间第一峰的美誉。其在吉林省东南部,最近的落脚点是吉林省安图县二道白河镇。长白山有自己夏天,少不了一件碎花裙!今年流行这样穿,优雅甜美还有气质市面上裙子款式千千万,甜美又浪漫的碎花裙始终占领着重要的一席之地,可以轻松营造出优雅恬淡的氛围感,彰显女性柔美气质。时髦女孩们一定要抓紧潮流的风向标,碎花裙今年流行这样穿!学会这些牛仔裤普普通通的,却随便搭配一下就好看,夏天穿太合适不会有人真的讨厌穿牛仔裤吧?虽然牛仔裤已经烂大街了,但受欢迎程度一点儿也不低,毕竟牛仔裤它不仅实用,看着还好看,搭配方式还复杂多变,可以说是夏天必备的一条裤子了。牛仔裤普普通通的,
财看闪电投资2。1亿元建设5GW光伏大硅片项目青岛高测股份年内第3次扩产齐鲁网闪电新闻12月9日讯青岛高测科技股份有限公司(简称高测股份)官方微信公众号发布消息称,近日,高测股份与河南省滑县先进制造业开发区管理委员会签署5GW光伏大硅片项目合作协议,公前11个月进出口同比增长8。6我国外贸展现强劲韧性海关总署12月7日发布数据显示,前11个月,我国进出口总值38。34万亿元人民币,比去年同期增长8。6。其中,出口21。84万亿元,增长11。9进口16。5万亿元,增长4。6贸易顺没了欧美,俄罗斯跨境电商盯上中国市场?文荀诗林在欧美东南亚等市场之后,俄罗斯成为跨境电商的新蓝海。据俄罗斯电商平台Ozon中国区总裁SimonHuang表示,欧美电商品牌的撤离将是国内卖家入驻俄罗斯市场极大的机会。11我国前11个月外贸进出口保持稳定增长本报北京12月8日电(记者杜海涛)海关总署日前发布数据今年前11个月,我国进出口总值38。34万亿元,比去年同期(下同)增长8。6。其中,出口21。84万亿元,增长11。9进口16王晗下课!山东球迷愤怒,带队能力堪忧,巩晓彬归队呼声高头条创作挑战赛12月7日CBA联赛第二阶段首个比赛日,多支球队出战参加比赛,其中最受关注的就是青岛男篮与山东男篮的山东德比。两队的比拼非常激烈,最后一秒才分出胜利,青岛男篮以989北京111月新设企业创近五年同期新高确认制登记企业超万户中新网北京12月9日电(记者杜燕)今天,北京市市场监督管理局表示,自2022年9月1日起,北京自贸区内资公司及其分支机构,可自主选择适用确认制办理市场主体登记业务。改革政策施行3个2022年东盟杯国际藤球邀请赛在南宁开赛来源广西自治区外事办地方外事12月7日,2022年东盟杯国际藤球邀请赛在南宁开赛。来自柬埔寨老挝马来西亚泰国印度尼西亚越南和我国的7支代表队汇聚南宁,将进行为期2天的比拼。在与中国浙报观察丨浙产新能源车,步子能否再快些?金华市新能源汽车小镇零跑汽车有限公司总装车间内,新能源汽车生产热火朝天。共享联盟金华胡肖飞摄新能源汽车,近来很热。继嵊州仙居之后,比亚迪电池项目再次选址永嘉前几天,吉利极氪工厂宣布在火热中冷静,在寒冬中乐观编者语本文作者英特尔资本董事总经理和中国区总经理王天琳,钛媒体创投家经授权发布半导体是一个周期性行业。年初大家还在谈产能紧缺,没想到下行周期竟来得又快又猛资本市场热情消退,下游客户动力升级还能选装激光雷达新款小鹏p7能否挽回市场近日,有媒体发布了一张2022。11中国新能源汽车销量天梯图。不说其中比亚迪连续几个月亮眼的成绩,单看新势力,目前哪吒领衔。而曾经销量不错的小鹏汽车11月却掉队明显。于是决定将对目均悦充深耕家用充电桩领域,重新定义家庭充电近年来,随着新能源汽车渗透率的不断提升和国内新基建的全面展开,充电基础设施市场规模快速扩大。站在新能源汽车风口下,众多企业纷纷入局新能源产业赛道,为充电桩技术链迸发活力夯实基础。宁