1. 程式人生 > >海量資料處理之BloomFilter

海量資料處理之BloomFilter

一提到元素查詢,我們會很自然的想到HashMap。通過將雜湊函式作用於key上,我們得到了雜湊值,基於雜湊值我們可以去表裡的相應位置獲取對應的資料。除了存在雜湊衝突問題之外,HashMap一個很大的問題就是空間效率低。引入Bloom Filter則可以很好的解決空間效率的問題。

掌握本文內容前,建議先熟練掌握前面一篇文章

原理

Bloom Filter是一種空間效率很高的隨機資料結構,Bloom filter 可以看做是對bit-map 的擴充套件,布隆過濾器被設計為一個具有N的元素的位陣列A(bit array),初始時所有的位都置為0。

當一個元素被加入集合時,通過K個Hash函式將這個元素對映成一個位陣列(Bit array)中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約)知道集合中有沒有它了。

如果這些點有任何一個 0,則被檢索元素一定不在;

如果都是 1,則被檢索元素很可能在。

新增元素

要新增一個元素,我們需要提供k個雜湊函式。每個函式都能返回一個值,這個值必須能夠作為位陣列的索引(可以通過對陣列長度進行取模得到)。然後,我們把位陣列在這個索引處的值設為1。例如,第一個雜湊函式作用於元素I上,返回x。類似的,第二個第三個雜湊函式返回y與z,那麼: 

A[x]=A[y]=A[z] = 1

查詢元素

查詢的過程與上面的過程類似,元素將會被不同的雜湊函式處理三次,每個雜湊函式都返回一個作為位陣列索引值的整數,然後我們檢測位陣列在x、y與z處的值是否為1。如果有一處不為1,那麼就說明這個元素沒有被新增到這個布隆過濾器中。如果都為1,就說明這個元素在布隆過濾器裡面。當然,會有一定誤判的概率。

演算法優化

通過上面的解釋我們可以知道,如果想設計出一個好的布隆過濾器,我們必須遵循以下準則:

  • 好的雜湊函式能夠儘可能的返回寬範圍的雜湊值。

  • 位陣列的大小(用m表示)非常重要:如果太小,那麼所有的位很快就都會被賦值為1,這樣就增加了誤判的機率。

  • 雜湊函式的個數(用k表示)對索引值的均勻分配也很重要。

計算m的公式如下: 

m = - nlog p / (log2)^2 

這裡p為可接受的誤判率。

計算k的公式如下: 

k = m/n log(2) 

這裡k=雜湊函式個數,m=位陣列個數,n=待檢測元素的個數(後面會用到這幾個字母)。

雜湊演算法

雜湊演算法是影響布隆過濾器效能的地方。我們需要選擇一個效率高但不耗時的雜湊函式,在論文《更少的雜湊函式,相同的效能指標:構造一個更好的布隆過濾器》中,討論瞭如何選用2個雜湊函式來模擬k個雜湊函式。首先,我們需要計算兩個雜湊函式h1(x)與h2(x)。然後,我們可以用這兩個雜湊函式來模仿產生k個雜湊函式的效果: 

gi(x) = h1(x) + ih2(x) 

這裡i的取值範圍是1到k的整數。

Google Guava類庫使用這個技巧實現了一個布隆過濾器,雜湊演算法的主要邏輯如下:

long hash64 = ...;
int hash1 = (int) hash64;
int hash2 = (int) (hash64 >>> 32);

for (int i = 1; i <= numHashFunctions; i++) {
 int combinedHash = hash1 + (i * hash2);
 // Flip all the bits if it's negative (guaranteed positive number)
 if (combinedHash < 0) {
   combinedHash = ~combinedHash;
 }
}

Guava中的Bloom Filter使用示例:

int expectedInsertions = ...; //待檢測元素的個數
double fpp = 0.03; //誤判率(desired false positive probability)
BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF-8")), expectedInsertions,fpp);

優點

它的優點是空間效率和查詢時間都遠遠超過一般的演算法,布隆過濾器儲存空間和插入/查詢時間都是常數O(k)。另外, 雜湊函式相互之間沒有關係,方便由硬體並行實現。布隆過濾器不需要儲存元素本身,在某些對保密要求非常嚴格的場合有優勢。

缺點

布隆過濾器的缺點和優點一樣明顯,誤算率是其中之一。

另外,一般情況下不能從布隆過濾器中刪除元素。我們很容易想到把位陣列變成整數陣列,每插入一個元素相應的計數器加 1,這樣刪除元素時將計數器減掉就可以了。然而要保證安全地刪除元素並非如此簡單。首先我們必須保證刪除的元素的確在布隆過濾器裡面,而這一點單憑這個過濾器是無法保證的。

其實,用java實現bloomfilter也是很簡單的,主要思想是在java的BitSet的基礎上擴充套件一下hash函式即可。程式碼如下:

package bigdata.spark.distinct;

import java.util.BitSet;

public class BloomFilter {
   /* BitSet初始分配2^25個bit */
   private static final int DEFAULT_SIZE = 1 << 25;
   /* 不同雜湊函式的種子,一般應取質數 */
   private static final int[] seeds = new int[]{5, 7, 11, 13, 31, 37, 61};
   /* 儲存海量資料使用bitset */
   private BitSet bits = new BitSet(DEFAULT_SIZE);
   /* 雜湊函式物件用於判斷元素是否存在於表中 */
   private SimpleHash[] func = new SimpleHash[seeds.length];

   //建構函式
   public BloomFilter() {
       for (int i = 0; i < seeds.length; i++) {
           func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);
       }
   }

   // 將字串標記到bits中
   public void add(String value) {
       for (SimpleHash f : func) {
           bits.set(f.hash(value), true);
       }
   }

   //判斷字串是否已經被bits標記
   public boolean contains(String value) {
       if (value == null) {
           return false;
       }
       boolean ret = true;
       for (SimpleHash f : func) {
           ret = ret && bits.get(f.hash(value));
       }
       return ret;
   }



   /* 雜湊函式類 */
   public static class SimpleHash

   {
       //cap為hash函式的容量
       private int cap;
       //不同hash函式的種子
       private int seed;

       public SimpleHash(int cap, int seed) {
           this.cap = cap;
           this.seed = seed;
       }

       //hash函式,採用簡單的加權和hash
       public int hash(String value) {
           int result = 0;
           /* 對Value的每個字元進行hash 獲取每個Hash值 */
           int len = value.length();

           for (int i = 0; i < len; i++) {
               result = seed * result + value.charAt(i);
           }
           return (cap - 1) & result;
       }
   }
}

整理自網路:

https://blog.csdn.net/foreverling/article/details/79242968 

https://blog.csdn.net/it_dx/article/details/71640504

推薦閱讀:

640

歡迎點贊,轉發,星球入口點選原文閱讀!

相關推薦

海量資料處理BloomFilter

一提到元素查詢,我們會很自然的想到HashMap。通過將雜湊函式作用於key上,我們得到了雜湊值

[算法系列十八]海量資料處理BitMap

一:簡介 所謂的BitMap就是用一個bit位來標記某個元素對應的Value, 而Key即是該元素。由於採用了bit為單位來儲存資料,因此在儲存空間方面,可以大大節省。 二:基本思想 我們用一個具體的例子來講解,假設我們要對0-7內的5個元素(4,7,2,5,3)排

海量資料處理Bloom Filter詳解

一、什麼是Bloom Filter    Bloom Filter是一種空間效率很高的隨機資料結構,它的原理是,當一個元素被加入集合時,通過K個Hash函式將這個元素對映成一個位陣列(Bit array)中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約

Python海量資料處理_Hadoop(二)概念和原理

1. 說明  Hadoop是個分散式的架構,它將海量資料處理工作分配到叢集中的多個機器上執行。前篇介紹了Hadoop的安裝,在安裝過程中會產生一些疑問,比如NameNode是什麼東西?本篇就以問題&解答的方式介紹Hadoop的相關概念及其原理。 2. NameNode,DataNode,以及Seco

海量資料處理系列——BloomFilter

import java.util.BitSet;publicclass BloomFilter {/* BitSet初始分配2^24個bit */privatestaticfinalint DEFAULT_SIZE =1<<25; /* 不同雜湊函式的種子,一般應取質數 */privatest

Python海量資料處理_Hadoop&Spark

1. 說明  前篇介紹了安裝和使用Hadoop,本篇將介紹Hadoop+Spark的安裝配置及如何用Python呼叫Spark。  當資料以TB,PB計量時,用單機處理資料變得非常困難,於是使用Hadoop建立計算叢集處理海量資料,Hadoop分為兩部分,一部分是資料儲存HDFS,另一部分是資料計算MapR

海量資料處理Tire樹(字典樹)

第一部分、Trie樹 1.1、什麼是Trie樹     Trie樹,即字典樹,又稱單詞查詢樹或鍵樹,是一種樹形結構,是一種雜湊樹的變種。典型應用是用於統計和排序大量的字串(但不僅限於字串),所以經常被搜尋引擎系統用於文字詞頻統計。它的優點是:最大限度地減少無謂的字串比較,

海量資料處理專題(八)——倒排索引(搜尋引擎基石)(轉)

引言:在資訊大爆炸的今天,有了搜尋引擎的幫助,使得我們能夠快速,便捷的找到所求。提到搜尋引擎,就不得不說VSM模型,說到VSM,就不得不聊倒排索引。可以毫不誇張的講,倒排索引是搜尋引擎的基石。VSM檢索模型VSM全稱是Vector Space Model(向量空間模型),是IR(Information Ret

海量資料處理-BloomFilter

import java.util.BitSet;publicclass BloomFilter  {/* BitSet初始分配2^24個bit */privatestaticfinalint DEFAULT_SIZE =1<<25; /* 不同雜湊函式的種子,一般應取質數 */privatesta

由散列表到BitMap的概念與應用(三):面試中的海量資料處理

一道面試題 在面試軟體開發工程師時,經常會遇到海量資料排序和去重的面試題,特別是大資料崗位。 例1:給定a、b兩個檔案,各存放50億個url,每個url各佔64位元組,記憶體限制是4G,找出a、b檔案共同的url? 首先我們最常想到的方法是讀取檔案a,建立雜湊表,然後再讀取檔案b,遍歷檔

十道海量資料處理面試題與十個方法大總結:

轉載之處:http://blog.csdn.net/liuqiyao_01/article/details/26567237 筆試 = (資料結構+演算法) 50%+ (計算機網路 + 作業系統)30% +邏輯智力題10%  + 資料庫5% + 歪門邪道題5%,而面

海量資料處理方法及應用

一、雜湊切割top K問題 1. 給一個超過100G大小的log file, log中存著IP地址, 設計演算法找到出現次數最多的IP地址? (1)首先使用雜湊函式HashFunc(ip)將每一個IP地址轉化為整型,再通過HashFunc(i

海量資料處理例項

在bat等大公司,基本所有業務的資料量級都很龐大,那麼如何在保證資料完整性的情況下快速處理成了一個通用的難題,這裡列舉幾個例子,大致反應一些處理思想。 1.一個檔案中,每一行有一個整數,有上億行,目的:統計出現次數超過三次的整數寫入到另一個檔案中。 分析: (1)首先資料

海量資料處理演算法—Bit-Map

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Python資料處理(三)Numpy建立array

一、關鍵字 array:建立陣列 dtype:指定資料型別 zeros:建立資料全為0 ones:建立資料全為1 empty:建立資料接近0 arrange:按指定範圍建立資料 linspace:建立線段

Python資料處理(二)Numpy屬性

簡單介紹一下numpy中常見的三個屬性: ndim:    維度 shape:  行數和列數 size:     元素個數 使用numpy首先要匯入模組,為了方便

Python資料處理(一)為什麼要學習 Numpy & Pandas?

今天我們介紹兩個科學運算當中最為重要的兩個模組,一個是numpy,一個是 pandas。任何關於資料分析的模組都少不了它們兩個。 一、主要用途: 資料分析 機器學習 深度學習 二、為什麼使用 numpy & pandas

Python資料處理(四)numpy基礎運算1

一、一維矩陣的基礎運算 下例中 a和b是兩個屬性為array也就是矩陣的變數,而且二者都是1行4列的矩陣, 其中b矩陣中的元素分別是從0到3。 如果我們想要求兩個矩陣之間的減法,你可以嘗試著輸入:a-b,得到的結果是對應元素相減的結果也就是[10 19 28 37],同理元素的相加相

Python資料處理(七)Numpy array 合併

一、np.vstack() 對array的合併,我們可以想到按行、按列等多種方式進行合併。 vertical stack本身屬於一種上下合併,即對括號中的兩個整體進行對應操作。 >>> import numpy as np >>> A=np.a

Python資料處理(十 一)Pandas 選擇資料

首先先建立一個6X4的矩陣 >>> import pandas as pd >>> import numpy as np >>> dates=pd.date_range('20181121',periods=6) >>