Bitmap
Bitmap篇
在前一篇中介绍了使用API做Distinct Count,但是计算精确结果的API都较慢,那有没有能更快的优化解决方案呢?
1. Bitmap介绍
《编程珠玑》上是这样介绍bitmap的:
Bitmap是一个十分有用的数据结构。所谓的Bitmap就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。由于采用了Bit为单位来存储数据,因此在内存占用方面,可以大大节省。
简而言之——用一个bit(0或1)表示某元素是否出现过,其在bitmap的位置对应于其index。《编程珠玑》给出了一个用bitmap做排序的例子:
/* Copyright (C) 1999 Lucent Technologies */
/* From 'Programming Pearls' by Jon Bentley */
/* bitsort.c -- bitmap sort from Column 1
* Sort distinct integers in the range [0..N-1]
*/
#include <stdio.h>
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1 + N / BITSPERWORD];
void set(int i) { a[i >> SHIFT] |= (1 << (i & MASK)); }
void clr(int i) { a[i >> SHIFT] &= ~(1 << (i & MASK)); }
int test(int i) { return a[i >> SHIFT] & (1 << (i & MASK)); }
int main() {
int i;
for (i = 0; i < N; i++)
clr(i);
/* Replace above 2 lines with below 3 for word-parallel init
int top = 1 + N/BITSPERWORD;
for (i = 0; i < top; i++)
a[i] = 0;
*/
while (scanf("%d", &i) != EOF)
set(i);
for (i = 0; i < N; i++)
if (test(i))
printf("%d\n", i);
return 0;
}
上面代码中,用int的数组存储bitmap,对于每一个待排序的int数,其对应的index为其int值。
2. Distinct Count优化
index生成
为了使用bitmap做Distinct Count,首先需得到每个用户(uid)对应(在bitmap中)的index。有两种办法可以得到从1开始编号index表(与uid一一对应):
- hash,但是要找到无碰撞且hash值均匀分布[1, +∞)区间的hash函数是非常困难的;
- 维护一张uid与index之间的映射表,并增量更新
比较两种方法,第二种方法更为简单可行。
UV计算
在index生成完成后,RDD[(uid, V)]与RDD[(uid, index)]join得到index化的RDD。bitmap的开源实现有EWAH,采用RLE(Run Length Encoding)压缩,很好地解决了存储空间的浪费。Distinct Count计算转变成了求bitmap中1的个数:
// distinct count for rdd(not pair) and the rdd must be sorted in each partition
def distinctCount(rdd: RDD[Int]): Int = {
val bitmap = rdd.aggregate[EWAHCompressedBitmap](new EWAHCompressedBitmap())(
(u: EWAHCompressedBitmap, v: Int) => {
u.set(v)
u
},
(u1: EWAHCompressedBitmap, u2: EWAHCompressedBitmap) => u1.or(u2)
)
bitmap.cardinality()
}
// the tuple_2 is the index
def groupCount[K: ClassTag](rdd: RDD[(K, Int)]): RDD[(K, Int)] = {
val grouped: RDD[(K, EWAHCompressedBitmap)] = rdd.combineByKey[EWAHCompressedBitmap](
(v: Int) => EWAHCompressedBitmap.bitmapOf(v),
(c: EWAHCompressedBitmap, v: Int) => {
c.set(v)
c
},
(c1: EWAHCompressedBitmap, c2: EWAHCompressedBitmap) => c1.or(c2))
grouped.map(t => (t._1, t._2.cardinality()))
}
但是,在上述计算中,由于EWAHCompressedBitmap的set方法要求int值是升序的,也就是说RDD的每一个partition的index应是升序排列:
// sort pair RDD by value
def sortPairRDD[K](rdd: RDD[(K, Int)]): RDD[(K, Int)] = {
rdd.mapPartitions(iter => {
iter.toArray.sortWith((x, y) => x._2.compare(y._2) < 0).iterator
})
}
为了避免排序,可以为每一个uid生成一个bitmap,然后在Distinct Count时将bitmap进行or运算亦可:
rdd.reduceByKey(_ or _)
.mapValues(_._2.cardinality())
3. 参考资料
[1] 周海鹏, Bitmap的秘密.
Bitmap的更多相关文章
- [翻译]开发文档:android Bitmap的高效使用
内容概述 本文内容来自开发文档"Traning > Displaying Bitmaps Efficiently",包括大尺寸Bitmap的高效加载,图片的异步加载和数据缓存 ...
- 【开源毕设】一款精美的家校互动APP分享——爱吖校推 [你关注的,我们才推](持续开源更新3)附高效动态压缩Bitmap
一.写在前面 爱吖校推如同它的名字一样,是一款校园类信息推送交流平台,这么多的家校互动类软件,你选择了我,这是我的幸运.从第一次在博客园上写博客到现在,我一次一次地提高博文的质量和代码的可读性,都是为 ...
- Android Bitmap 和 ByteArray的互相转换
Android Bitmap 和 ByteArray的互相转换 移动平台图像处理,需要将图像传给native处理,如何传递?将bitmap转换成一个 byte[] 方便传递也方便cpp代码直接处理图像 ...
- Android-Drawable、Bitmap、byte[]、资源文件相互转换
我们在Android的开发中,经常可以遇到图片的处理,当中,有很多是 Bitmap.Drawable.byte[]和资源文件它们直接相互转换. 今天就此总结一下: 1.资源文件转为Drawable 2 ...
- bitmap对海量无重复的整数排序--转
原文地址:http://blog.csdn.net/u013074465/article/details/46956295 现在有n个无重复的正整数(n 小于10的7次方),如果内存限制在1.5M以内 ...
- 基于位图(Bitmap、BitmapData)的图片处理方法(C#)
目前操作位图的主流方法有三种: 1.基于Bitmap像素的处理方法,以GetPixel()和SetPixel()方法为主.方法调用简单,但是效率偏低. 2.基于内存的像素操作方法,以System.Ru ...
- android:布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!
1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayo ...
- 获取View的截图-将View转换为Bitmap对象
开发中,有时候需要获取View的截图来做动画来达到动画流程的目的 原理:将View的内容画到一个Bitmap画布上,然后取出 下面封装了一个从View生成Bitmap的工具类 /** * 将View转 ...
- bitmap解码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define BYTE unsigned c ...
- Bitmap转换成BitmapImage
public BitmapImage BitmapToBitmapImage(System.Drawing.Bitmap bitmap) { MemoryStream ms = new MemoryS ...
随机推荐
- hdoj 2066 一个人的旅行 【多源多汇最短路】
题目:hdoj 2066 一个人的旅行 方法:缩点 + 最短路 分析:看了大神的一篇博客,讲冗余压缩的,然后就想找一个多源最短路练练手. 这个题目就是典型的多源多汇最短路 方法:把全部的源点压缩成一个 ...
- 打印org.eclipse.xsd.XSDSchema对象
由于网上关于Eclipse XSD的中文资料比較少,可是有的时候.我们须要使用Eclipse XSD的API去构造或者改动一个XSD文件. 那么当我们创建了org.eclipse.xsd.XSDSch ...
- Lucene.Net 2.3.1开发介绍 —— 简介
原文:Lucene.Net 2.3.1开发介绍 -- 简介 Lucene.Net是Lucene在dot net平台上的移植版本.它的功能与Lucene一样,都是用来提供一组API,让我们能快速开发自己 ...
- Next-Key Locks
Next-Key Locks 一个next-key lock 是 一个record lock 在index record 和 一个区间锁 在一个区间在index record之前 InnoDB 执行 ...
- NDK-gdb的错误ERROR(不同于上一篇): Could not extract package's data directory...的解决方法
这个问题比较龟毛. 我的系统在4.0.4上一直调试好好的,到了2.2的系统居然fail.能检查的地方全部检查过了,居然不行. 最后仔细差了一遍,居然是由于/data目录的属性是777导致.ndk-gd ...
- hdu Crazy Circuits
Crazy Circuits 题目: 给出一个电路板,从+极出发到负极. 如今给你电路板上的最小电流限制,要你在电流平衡的时候求得从正极出发的最小电流. 算法: 非常裸的有源汇最小流.安有源汇最大流做 ...
- 明晚8点,捷微团队QQ群公开课,解说jeewx2.0版本号maven环境的搭建入门!
2014-08-13号晚8点,捷微团队QQ群公开课,解说jeewx2.0版本号maven环境的搭建入门! 讲师:刘强(团队成员) QQ群:287090836 (JAVA版本号微信开源项目) http: ...
- C++教材
C++语言: 1.<Essential C++>:Stanley B.Lipman著. 旁枝暂略,主攻核心,轻薄短小.附习题与解答,适合刚開始学习的人. 2.<The C++ Pro ...
- Nginx分时段限制下载速度解决方案(原创)_于堡舰_新浪博客
Nginx分时段限制下载速度解决方案(原创)_于堡舰_新浪博客 Nginx分时段限制下载速度解决方案(原创) (2011-03-02 16:40:49) 转载▼ 标签: ngi ...
- nginx源代码分析--event事件驱动初始化
1.在nginx.c中设置每一个核心模块的index ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]-> ...