大資料下的Distinct Count(二):Bitmap篇
大資料(big data),IT行業術語,是指無法在一定時間範圍內用常規軟體工具進行捕捉、管理和處理的資料集合,是需要新處理模式才能具有更強的決策力、洞察發現力和流程最佳化能力的海量、高增長率和多樣化的資訊資產。 |
《程式設計珠璣》上是這樣介紹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#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值。
為了使用bitmap做Distinct Count,首先需得到每個使用者(uid)對應(在bitmap中)的index。有兩種辦法可以得到從1開始編號index表(與uid一一對應):
- hash,但是要找到無碰撞且hash值均勻分佈[1, +∞)區間的hash函式是非常困難的;
- 維護一張uid與index之間的對映表,並增量更新
比較兩種方法,第二種方法更為簡單可行。
在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())
原文地址:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2678184/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Sql優化(二) 快速計算Distinct CountSQL優化
- 7.36 BITMAP_COUNT
- count_sum_distinct與nullNull
- 7.14 APPROX_COUNT_DISTINCTAPP
- 7.16 APPROX_COUNT_DISTINCT_DETAILAPPAI
- 從零開始學資料庫(二)——select顯示、where、%、排序、limit、distinct、count、max等、刪和改資料庫排序MIT
- 7.15 APPROX_COUNT_DISTINCT_AGGAPP
- ora-600 [rwoirw: check ret val] with count distinct and order by
- 使用子查詢可提升 COUNT DISTINCT 速度 50 倍
- 大資料下的資料安全大資料
- AI大模型時代下運維開發探索第二篇:基於大模型(LLM)的資料倉儲AI大模型運維
- java Bitmap 資料結構Java資料結構
- Oracle 12c新特性之:APPROX_COUNT_DISTINCT 函式OracleAPP函式
- Salesforce 大資料量處理篇(二)IndexSalesforce大資料Index
- 第二篇:智慧電網(Smart Grid)中的資料工程與大資料案例分析大資料
- Redis 實戰篇:巧用Bitmap 實現億級海量資料統計Redis
- 【Leetcode】1180. Count Substrings with Only One Distinct LetterLeetCode
- 大資料教程之大資料的影響二大資料
- 大資料之Flume(二)大資料
- 【大資料】科普一下大資料的那些事兒大資料
- 百萬資料 mysql count(*)優化MySql優化
- 提高MSSQL資料庫效能(1)對比count(*) 和 替代count(*)SQL資料庫
- 迎戰大資料-Oracle篇大資料Oracle
- [大資料量]BitMap即java.util.BitSet的應用大資料Java
- 大資料技術之資料採集篇大資料
- PostgreSQL 資料庫中 DISTINCT 關鍵字的 4 種用法SQL資料庫
- MySQL的COUNT語句--count(*)、 count(常量)、 count(列名)MySql
- 大資料開發之路:hive篇大資料Hive
- 迎戰大資料-SAP篇(上)大資料
- 零和博弈下的城市戰爭:房地產大資料之人口遷徙篇大資料
- 第二篇:資料倉儲與資料集市建模
- SSIS 資料型別 第二篇:變數的資料型別資料型別變數
- 探索大資料背景下的基因研究大資料
- 大資料時代下的雲端計算大資料
- 大資料分析之資料下鑽上卷大資料
- count(1),count(*),count(列)的區別
- 有關Bitmap Join Indexes的精彩帖二Index
- 大資料下的天貓11•11:基於強大的大資料分析和運營能力大資料