大資料下的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())
原文地址: https://www.linuxprobe.com/big-data-bitmap.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2678184/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 7.14 APPROX_COUNT_DISTINCTAPP
- 7.36 BITMAP_COUNT
- 7.15 APPROX_COUNT_DISTINCT_AGGAPP
- 7.16 APPROX_COUNT_DISTINCT_DETAILAPPAI
- 【Leetcode】1180. Count Substrings with Only One Distinct LetterLeetCode
- Redis 實戰篇:巧用Bitmap 實現億級海量資料統計Redis
- AI大模型時代下運維開發探索第二篇:基於大模型(LLM)的資料倉儲AI大模型運維
- 百萬資料 mysql count(*)優化MySql優化
- Redis 基礎 -- 點陣圖(bitmap)資料結構和 bitmap的常用命令Redis資料結構
- [Laravel系列] 解決laravel中paginate()與distinct() count語句錯誤問題Laravel
- Salesforce 大資料量處理篇(二)IndexSalesforce大資料Index
- 大資料教程之大資料的影響二大資料
- 從"hello".count想到的之二--scal
- 【大資料】科普一下大資料的那些事兒大資料
- 大資料之Flume(二)大資料
- PostgreSQL 資料庫中 DISTINCT 關鍵字的 4 種用法SQL資料庫
- MySQL的COUNT語句--count(*)、 count(常量)、 count(列名)MySql
- 【資料結構與演算法】bitmap資料結構演算法
- 大資料技術之資料採集篇大資料
- SSIS 資料型別 第二篇:變數的資料型別資料型別變數
- count(*)、count(1)和count(列名)的區別
- 大資料開發之路:hive篇大資料Hive
- 大資料分析之資料下鑽上卷大資料
- sklearn 第二篇:資料預處理
- Android粒子篇之Bitmap畫素級操作Android
- 海量資料處理利器 Roaring BitMap 原理介紹
- 大資料解決方案-(基礎篇)大資料
- LINUX下查詢大檔案及大的資料夾Linux
- js學習 第二篇資料型別JS資料型別
- 大資料計算生態之資料計算(二)大資料
- 物件代理資料庫:大資料時代下的應需之作物件資料庫大資料
- 第二屆資料安全大賽“數信杯”資料安全大賽 WP
- Saprk distinct
- 大資料基礎教程:建立RDD的二種方式大資料
- 有必要了解的大資料知識(二) Hadoop大資料Hadoop
- 大資料下的質量體系建設大資料
- 大資料分析疫情下電影院的現狀大資料
- 玩轉大資料系列之二:資料分析與處理大資料