大数据下的Distinct Count(二):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的秘密.
大数据下的Distinct Count(二):Bitmap篇的更多相关文章
- 大数据下的Distinct Count(一):序
在数据库中,常常会有Distinct Count的操作,比如,查看每一选修课程的人数: select course, count(distinct sid) from stu_table group ...
- mysql优化----大数据下的分页,延迟关联,索引与排序的关系,重复索引与冗余索引,索引碎片与维护
理想的索引,高效的索引建立考虑: :查询频繁度(哪几个字段经常查询就加上索引) :区分度要高 :索引长度要小 : 索引尽量能覆盖常用查询字段(如果把所有的列都加上索引,那么索引就会变得很大) : 索引 ...
- 【阿里云产品公测】大数据下精确快速搜索OpenSearch
[阿里云产品公测]大数据下精确快速搜索OpenSearch 作者:阿里云用户小柒2012 相信做过一两个项目的人都会遇到上级要求做一个类似百度或者谷歌的站内搜索功能.传统的sql查询只能使用like ...
- 软工之词频统计器及基于sketch在大数据下的词频统计设计
目录 摘要 算法关键 红黑树 稳定排序 代码框架 .h文件: .cpp文件 频率统计器的实现 接口设计与实现 接口设计 核心功能词频统计器流程 效果 单元测试 性能分析 性能分析图 问题发现 解决方案 ...
- 大数据下的数据分析平台架构zz
转自http://www.cnblogs.com/end/archive/2012/02/05/2339152.html 随着互联网.移动互联网和物联网的发展,谁也无法否认,我们已经切实地迎来了一个海 ...
- 【CSWS2014 Summer School】大数据下的游戏营销模式革新-邓大付
大数据下的游戏营销模式革新 邓大付博士腾讯专家工程师 Bio:毕业于华中科技大学,现任腾讯IEG运营部数据中心技术副总监,负责腾讯游戏的数据挖掘相关工作,包括有用户画像,推荐系统,基础算法研究等.主要 ...
- 大数据下多流形聚类分析之谱聚类SC
大数据,人人都说大数据:类似于人人都知道黄晓明跟AB结婚一样,那么什么是大数据?对不起,作为一个本科还没毕业的小白实在是无法回答这个问题.我只知道目前研究的是高维,分布在n远远大于2的欧式空间的数据如 ...
- 大数据下基于Tensorflow框架的深度学习示例教程
近几年,信息时代的快速发展产生了海量数据,诞生了无数前沿的大数据技术与应用.在当今大数据时代的产业界,商业决策日益基于数据的分析作出.当数据膨胀到一定规模时,基于机器学习对海量复杂数据的分析更能产生较 ...
- 教你做一个牛逼的DBA(在大数据下)
一.基本概念 大数据量下,搞mysql,以下概念需要先达成一致 1)单库,不多说了,就是一个库 2)分片(sharding),水平拆分,用于解决扩展性问题,按天拆分表 3)复制(replication ...
随机推荐
- console对象-转
console对象 来自<JavaScript 标准参考教程(alpha)>,by 阮一峰 目录 开发者工具 console对象 console.log() console.debug() ...
- 【转】WriteMessage的信息在AutoCAD中命令行中实时显示
之前程序中有段发送信息到命令行上显示的代码,如下: ed.WriteMessage("开始标注横断面高程,请稍候!"); 但是发现命令行中并不马上显示,代码也明明运 ...
- 使用LinqToExcel读取Excel
我们读取和写入Excel 经常使用NPOI工具,如果我们的需求只是需要读取Excel,可以考虑使用LinqToExcel这个组件.这个组件用起来简单,实用,操作方便,而且结合了Linq的查询特性,ex ...
- C#集合类型大盘点
C#集体类型( Collections in C#) 集合是.NET FCL(Framework Class Library)中很重要的一部分,也是我们开发当中最常用到的功能之一,几乎是无处不在.俗话 ...
- 生成模型(Generative Model)与判别模型(Discriminative Model)
摘要: 1.定义 2.常见算法 3.特性 4.优缺点 内容: 1.定义 1.1 生成模型: 在概率统计理论中, 生成模型是指能够随机生成观测数据的模型,尤其是在给定某些隐含参数的条件下.它给观测值和标 ...
- Sql Server系列:聚合函数
1 SUM SUM是一个求和函数,返回指定列值的总和.SUM 只能用于数字列. 其中忽略 Null 值. 语法 SUM ( [ ALL | DISTINCT ] expression ) OVER ( ...
- LINQ系列:LINQ to SQL Concat/Union
1. Concat 单列Concat var expr = (from p in context.Products select p.ProductName) .Concat( from c in c ...
- jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + div.aaron input[type="checkb ...
- Windows phone重写返回键
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e) {//需要设置这个属性 e.Cancel ...
- Java基础之类Class使用
大家都知道Java是一门面向对象编程语言,在Java世界里,万事万物皆对象,那个Java中怎么表示对象呢?Class 我们知道Java中的对象都是Object类的子类,那么今天我们就一起来研究一下Ja ...