1. 程式人生 > >大資料下的Distinct Count(二):Bitmap篇

大資料下的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
defdistinctCount(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. 參考資料

相關推薦

資料Distinct CountBitmap

在前一篇中介紹了使用API做Distinct Count,但是精確計算的API都較慢,那有沒有能更快的優化解決方案呢? 1. Bitmap介紹 《程式設計珠璣》上是這樣介紹bitmap的: Bitmap是一個十分有用的資料結構。所謂的Bitmap就是用一個bit位來標記某個元素對應的Value,而

2016全球資料戰略版圖剖析1架構

本文為數盟原創文章,轉載時請註明出處為“數盟社群”。 上圖是2016大資料版圖英文完整版。 為了更好的使大家瞭解行業現狀,我們整理出了對應公司的中文介紹,以饗讀者。 本次介紹的公司為如圖所示的部分公司,請悉知: 基礎設施 1.基於Hadoop Cloud

資料Hadoop學習筆記

Single Node Setup 官網地址 1. 本地模式 2.偽分散式模式 ************************* 本地模式 **************************** . grep input output ‘dfs[a-

資料的核心技術

我們在上一篇文章中給大家介紹了大資料的部分核心技術,分別是資料探勘和機器學習。在大資料中,資料探勘和機器學習都是發揮了不同的功能。在這篇文章中我們給大家介紹一下人工智慧和其他大資料處理的基礎技術,希望這篇文章能能夠給大家帶來幫助。 首先說說人工智慧,AI和大資料是相互促進的關係,一方面,AI基礎理論技術

蘇先生之資料面試經驗總結

1、flume與kafka的區別 flume適合做日誌採集,可以定製多種資料來源,減少開發量;而kafka是分散式訊息處理的中介軟體,自帶儲存功能,適合做日誌快取;flume主要用於將資料往HDFS、HBASE傳送;如果涉及多個系統的使用,可以選擇用kafka

資料庫種類發展史和資料的資料庫NoSQL

本文側重於大資料下的NoSQL資料庫特點,在介紹NoSQL資料庫之前,需要簡單介紹下資料庫種類的發展史,有因有果的邏輯才能被大家所認可嘛。       計算機剛剛興起的年代,是沒有專門儲存資料的庫的,基本上所有的資料資訊都是以檔案的形式存取,也就是無庫,所以當時計算機也是比較

資料實時監控平臺Telegraf簡介及安裝

接著上一篇部落格:InfluxDB簡介及安裝,這篇部落格介紹下Linux環境下Telegraf安裝以及其功能特點。。。 官網地址:influxdata 官方文件:telegraf文件   環境:CentOS7.4 64位 Telegraf版本:0.11.1-1   一、Tel

資料之JAVA基礎集合ArrayList

1.集合的建立1).ArrayList集合看作一個長度可變的陣列2).ArrayList<要儲存元素的資料型別> 變數名 = new ArrayList<要儲存元素的資料型別>();3).集合中儲存的元素,只能為<>括號中指定的資料型別元素

資料之JAVA基礎迴圈和陣列方法練習

案例1:編寫 1+3+5+7+......+99的值 /* * 求1-99的基數和 */ public static void fun01() { int i = 1; int sum = 0; for(;i<100;i+=2) { sum += i;

React Native探索佈局

可以看到iphone 6的寬度為 375pt,對應了上邊的375,由此可見react的單位為pt。 那如何獲取實際的畫素尺寸呢? 這對圖片的高清化很重要,如果我的圖片大小為100*100 px. 設定寬度為100 * 100. 那在iphone上的尺寸就是模糊的。 這個時候需要的影象大小應該是 100 *

Docker 入門部署

部署篇開頭以兩個簡單的例子快速入門,然後介紹 Dockerfile 的常用命令 簡單的例子 以下使用兩個例子快速入題 官網的例子 這是來自 Docker 官方文件的例子,例子中使用了 Python,但不需要 Python 知識

android studio git使用總結 高階 分支管理

轉載請標註來源:http://blog.csdn.net/lsyz0021/article/details/51842774     前段時間寫過一篇文章介紹如何在AndroidStudio使用上傳專案到github,今天接著給大家帶來了他的高階篇——新建分支(branch

微服務架構資料一致性保證可靠事件模式

第一篇分享中講到實現可靠事件模式的關鍵在於:可靠事件投遞和避免事件重複消費,其中避免事件重複消費需要微服務滿足冪等性。那麼又該如何實現可靠事件投遞?又該如何保證服務滿足冪等性? 轉載本文需註明出處:EAII企業架構創新研究院,違者必究。如需加入微信群參與微課堂、架構設計與討論直播請

Arcg​isDEM資料進行水文分析

第一步:需要的工具 第二步驟:通過BIGEMAP下載高程資料        1. 啟動BIGEMAP地圖下載器軟體,檢視左上角是否顯示【已授權:所有地圖】,如果沒有該顯示,請聯絡我們的客服人員。如下圖所示:        2. 選擇左上角屬性選項,選擇【

資料結構與演算法——複雜度分析

資料結構與演算法(二)—— 複雜度分析(下) 除了前面記錄的複雜度的基礎知識,還有四個複雜度分析方面的知識點:最好情況時間複雜度、最壞情況時間複雜度、平均情況時間複雜度、均攤時間複雜度。 一、最好、最壞情況時間複雜度 最好情況時間複雜度,就是在最理想的情況下,

上期資料結構實驗記錄【初版】C實現簡單一元多項式加減乘求導及代值計算有借鑑刪改

想要記錄自己程式設計思維的成長所以發到部落格,歡迎並且感激大家指出缺點和錯誤! 一、【實驗構思(Conceive)】 本次實驗要求是用C或C++語言設計並實現一個一元稀疏多項式的簡單計算器,要求是要有如下功能 1、輸入並建立多項式 2、輸出多項式,序列按指數降序

資料筆記sparkpyspark的安裝

開篇 關於spark的配置其實沒有必要詳細地寫,這邊我放上我學習參考的廈門大學的部落格,拖了n年,我總算把單機版的spark給安裝上了。 環境變數 export JAVA_HOME=/usr/lib/jvm/default-java export HA

資料進階22個免費的資料視覺化和分析工具推薦

22個免費的資料視覺化和分析工具推薦   本文總結推薦22個免費的資料視覺化和分析工具。列表如下: 資料清理(Data cleaning)   當你分析和視覺化資料前,常需要“清理”工作。比如一些輸入性列表“New York City” ,同時其他人會

資料探勘十演算法——支援向量機SVM線性支援向量機的軟間隔最大化模型

首先感謝“劉建平pinard”的淵博知識以及文中詳細準確的推導!!! 支援向量機原理SVM系列文章共分為5部分: (一)線性支援向量機 (二)線性支援向量機的軟間隔最大化模型 (三)線性不可分支援向量機與核函式 (四)SMO演算法原理 (五)線性支援迴歸

資料架構簡述資料獲取

1.資料分類 按資料形態,我們把資料分為結構化資料和非結構化資料兩種。 結構化資料如傳統的Data Warehouse資料,欄位有固定的長度和語義,計算機程式可以直接處理 非結構化資料有文字資料、影象