本文介紹了布隆過濾器的概念及變體,這種描述很是適合代碼模擬實現。重點在於標準布隆過濾器和計算布隆過濾器,其餘的大都在此基礎上優化。文末附上了標準布隆過濾器和計算布隆過濾器的代碼實現(Java版和Python版)java
本文內容皆來自 《Foundations of Computers Systems Research》一書,本身翻譯的,轉載請註明出處,不許確的部分請告知,歡迎討論。算法
布隆過濾器是一個高效的數據結構,用於集合成員查詢,具備很是低的空間複雜度。 |
基本狀況數組
布隆過濾器是一個含有 m 個元素的位數組(元素爲0或1),在剛開始的時候,它的每一位都被設爲0。同時還有 k 個獨立的哈希函數 h1, h2,..., hk 。須要將集合中的元素加入到布隆過濾器中,而後就能夠支持查詢了。說明以下:
|
假陽性率評估
最後得出:
|
最佳的哈希函數數量緩存
|
部分佈隆過濾器(partial bloom filters)
|
標準的布隆過濾器有一個致命的缺點:不支持刪除元素。CBF協議解決的這個問題。 |
|
在網絡應用中,布隆過濾器一般被做爲信息在各節點間傳送,爲了節約資源,天然而然就想能不能壓縮布隆過濾器後再傳送。 |
|
上面提到的計算布隆過濾器存在這樣的缺點:存儲空間是標準布隆過濾器的數倍(取決於計數值的位數)和計數值的不均勻(有些始終爲0,有些則可能溢出)。下面看看 D-left Counting Bloom Filters 的特色。D-left Counting Bloom Filters 基於 D-left Hashing。 |
D-left Hashing 基本結構網絡
插入操做
假設有 d 個子表,元素爲 x,哈希函數爲 f
|
D-left Counting Bloom Filters數據結構
|
爲何會出現上面的狀況?由三個因素促成dom
|
如何解決?ide 說實話,沒看懂英文描述的內容。。。。大體是作了排列置換等操做
比普通的計算布隆過濾器空間少了一半甚至更多,並且效率也有提高(假陽性更低) |
Counting Bloom Filters 能夠進行元素的刪除操做,然而卻不能記錄一個元素被映射的頻率,並且不少應用中元素出現的頻率相差很大,也就是說,CBF中每一個計數值的位數同樣,那麼有些計數值很快就會溢出,而另外一些則一直都很小。這些問題能夠被 Spectral Bloom Filters 解決。 |
在SBF中,每個計數值的位數都是動態改變的。它的構造我沒看懂,先留着吧 |
Spectral bloom filter 被提出來解決元素頻率查詢問題,可是,它構造了一個複雜的索引數據結構去解決動態計算器的存儲問題。Dynamic counting bloom filter(比SBF好理解多了) 是一個空間時間都很高效的數據結構,支持元素頻率查詢。相比於SBF,在實際應用中(計數器不是很大,改變不是很頻繁時)它有更快的訪問時間和更小的內存消耗。 |
構成部分
|
特色
|
Summary Cache 在網絡中有極大的資源請求,若是全部的請求都由服務器來處理,網絡就會出現擁堵,性能就會降低。因此網絡中有大量的中間代理節點。這些代理會把一部分資源放在本身的本地緩存,當用戶向服務器請求資源時,該代理先會檢查該資源是否在本身的緩存中,若是在就直接發送給用戶,不然再向服務器請求。一個代理可以存儲的資源是很是有限的,爲了進一步減輕服務器的負載,網絡中相鄰的代理均可以共享本身的緩存。這樣,當代理 A 本地緩存沒有時,就會向相鄰代理廣播請求,查詢他們是否有該緩存。 |
IP Traceback 網絡中存在許多攻擊,有時候須要根據一些數據包去還原IP路徑,找到攻擊者。一個可行的辦法是在路由器中存儲數據包信息。然而,有些網絡中通訊量巨大,存儲全部的包是不現實的,所以能夠存儲這些包的摘要信息。這時,選用布隆過濾器能夠極大的節省空間,並且具備很是快的查詢。 |
標準布隆過濾器構建、測試代碼(Python 面向過程版) 1 import math 2 import random 3 import time 4 5 6 def hash_function(a, b, c, item, tablelen): 7 return (a * item ** 2 + b * item + c) % tablelen #哈希函數 8 9 10 def construction_of_SBF(tablelen = 1000, set = []): 11 12 k = int(math.log(2, math.e) * (tablelen / len(set))) 13 hash = [] 14 random.seed(time.time()) 15 for i in range(k): #隨機生成哈希函數的三個參數 16 a = random.randint(1, 1000) 17 b = random.randint(1, 1000) 18 c = random.randint(1, 1000) 19 hash.append((a, b, c)) 20 21 bitArray = [0] * tablelen 22 23 for element in set: #映射集合元素到位數組 24 for i in range(k): 25 hx = hash_function(hash[i][0], hash[i][1], hash[i][2], element, tablelen) 26 bitArray[hx] = 1 27 28 filter = [bitArray, hash] 29 return filter 30 31 # 測試 32 def test_bloom_filters(bloom_filter = None): 33 if bloom_filter == None: 34 return False 35 36 testSet = [1, 3, 7, 111, 99, 54, 34, 67, 81, 121, 101, 100, 23, 0, 845, 3339, 44] 37 for item in testSet: 38 flag = True 39 for i in range(len(filter[1])): 40 hx = hash_function(filter[1][i][0], filter[1][i][1], filter[1][i][2], item, len(filter[0])) 41 if bloom_filter[0][hx] != 1: 42 flag = False 43 break 44 45 if flag is True: 46 print("%d is in filter\n" % item) 47 else: 48 print("%d is not in filter\n" % item) 49 50 return True 51 52 53 if __name__ == "__main__": 54 filter = construction_of_SBF(set = list(range(10))) 55 test_bloom_filters(filter)
計算布隆過濾器構建、測試代碼(Python 面向過程版) 1 import math 2 import random 3 import time 4 5 """ 6 結構沒有設置好,按下寫: 7 0. 封裝函數 8 1. 哈希函數:計算哈希值 9 2. 生成哈希隨機參數函數 10 3. 插入函數:被調用 11 4. 刪除函數:被調用 12 5. 查詢函數:測試函數調用 13 6. 測試函數:測試插入和刪除 14 15 """ 16 17 18 def hash_function(params, item, tlen): 19 return (params[0] * item ** 2 + params[1] * item + params[2]) % tlen 20 21 22 def deletion_counting_bloom_filter(cbfilter = None, item = None): 23 if (cbfilter is None) or (item is None): 24 return False 25 for params in cbfilter[2]: 26 cbfilter[0][hash_function(params, item, len(cbfilter[0]))] -= 1 27 return True 28 29 30 def insertion_counting_bloom_filter(item = None, cbfilter = None): 31 if (item == None) or (cbfilter == None): 32 return False 33 for params in cbfilter[2]: 34 cbfilter[0][hash_function(params, item, len(cbfilter[0]))] += 1 35 return True 36 37 38 def query_counting_bloom_filter(item = None, cbfilter = None): 39 for params in cbfilter[2]: 40 if(cbfilter[0][hash_function(params, item, len(cbfilter[0]))]) is 0: 41 return False 42 return True 43 44 45 def construction_counting_bloom_filter(filterSet = None, filterArray = None): 46 if (filterSet is None) or (filterArray is None): 47 return None 48 # 最佳的哈希函數數量 49 hashNum = int(math.log(2, math.e) * (len(filterArray) / len(filterSet))) 50 hashParam = [] 51 random.seed(time.time()) 52 # 隨機生成哈希參數 53 for i in range(hashNum): 54 a = random.randint(1, 9999) 55 b = random.randint(1, 9999) 56 c = random.randint(1, 9999) 57 hashParam.append((a, b, c)) 58 59 # 將初始集合元素映射到過濾器數組中 60 for item in filterSet: 61 for params in hashParam: 62 filterArray[hash_function(params, item, len(filterArray))] += 1 63 64 # 返回過濾器數組、過濾器集合、過濾器哈希參數 65 return (filterArray, filterSet, hashParam) 66 67 68 def test_counting_bloom_filters(cbfilter = None): 69 if cbfilter is None: 70 return None 71 testSet = cbfilter[1][10:20] 72 73 # 先測試原有元素是否正常映射 74 for item in testSet: 75 if query_counting_bloom_filter(item, cbfilter) is True: 76 print("%d is in filter\n" % item) 77 else: 78 print("%d is not in filter\n" % item) 79 80 # 刪除後再查詢 81 if deletion_counting_bloom_filter(cbfilter, testSet[0]) is True: 82 print("delete successfully!\n") 83 else : 84 print("delete fails\n") 85 86 if query_counting_bloom_filter(testSet[0], cbfilter) is True: 87 print("%d is in filter\n" % testSet[0]) 88 else : 89 print("%d is not in filter\n" % testSet[0]) 90 91 # 插入後再測試 92 if insertion_counting_bloom_filter(testSet[0], cbfilter) is True: 93 print("insert %d successfully\n" % testSet[0]) 94 else: 95 print("insert %d fails\n") 96 97 if query_counting_bloom_filter(testSet[0], cbfilter) is True: 98 print("%d is in filter\n" % testSet[0]) 99 else : 100 print("%d is not in filter\n" % testSet[0]) 101 102 103 # 封裝後的函數 104 def counting_bloom_filters(filterSet = None, filterArray = None): 105 if (filterSet is None) or (filterArray is None): 106 return False 107 # 構造:初始集合元素的映射、哈希函數參數生成 108 cbfilter = construction_counting_bloom_filter(filterSet, filterArray) 109 110 # 測試:測試插入、刪除、查詢 111 test_counting_bloom_filters(cbfilter) 112 113 114 if __name__ == "__main__": 115 filterSet = list(range(100)) 116 filterArray = [0] * 10000 117 counting_bloom_filters(filterSet, filterArray)
標準布隆過濾器構建、測試代碼(Java 面向對象版) 1 // package BloomFilters; 2 3 import java.util.Arrays; 4 import java.util.Random; 5 import java.io.*; 6 import java.math.BigInteger; 7 import java.nio.*; 8 import java.nio.charset.StandardCharsets; 9 import java.nio.file.Path; 10 import java.util.*; 11 12 /** 13 * 實現標準布隆過濾器的類 14 */ 15 public class SBFilters { 16 // 實例字段 17 private boolean[] bitArray; //位數組 18 private int[][] hashParams; //隨機的哈希函數參數 19 20 // 方法字段 21 public SBFilters(int tLen, int[] iSet) 22 { 23 this.bitArray = new boolean[tLen]; 24 Arrays.fill(this.bitArray, Boolean.FALSE); 25 this.construction_filter(iSet); 26 } 27 28 private boolean construction_filter(int[] iSet) 29 { 30 if(iSet == null || iSet.length == 0) 31 { 32 return false; 33 } 34 var hashNum = (int)(Math.log(2) * (this.bitArray.length / iSet.length)); 35 this.construction_hashParams(hashNum); 36 for(var item: iSet) 37 { 38 for(var params: this.hashParams) 39 { 40 this.bitArray[hash_function(params, item)] = true; 41 } 42 } 43 return true; 44 } 45 46 private boolean construction_hashParams(int hashNum) 47 { 48 this.hashParams = new int[hashNum][3]; 49 var time = System.currentTimeMillis(); 50 var rd = new Random(time); 51 for(int i = 0; i < hashNum; i++) 52 { 53 this.hashParams[i][0] = rd.nextInt(9999) + 1; 54 this.hashParams[i][1] = rd.nextInt(9999) + 1; 55 this.hashParams[i][2] = rd.nextInt(9999) + 1; 56 } 57 return true; 58 } 59 60 private int hash_function(int[] params, int item) 61 { 62 return (int)((params[0] * Math.pow(item, 2.0) + 63 params[1] * item + params[2]) % bitArray.length); 64 } 65 66 public boolean query_filter(int item) 67 { 68 for(var params: this.hashParams) 69 { 70 if(this.bitArray[hash_function(params, item)] == false) 71 { 72 return false; 73 } 74 } 75 return true; 76 } 77 78 } 79 80 81 82 // package BloomFilters; 83 84 85 86 87 /** 88 * 用來測試實現的布隆過濾器是否正常工做 89 */ 90 public class FiltersTest 91 { 92 public static void main(final String[] args) 93 { 94 test_counting_bloom_filters(); 95 } 96 97 98 private static void test_counting_bloom_filters() 99 { 100 var iSet = new int[10000]; 101 for(int i = 0; i < 10000; iSet[i] = i++); 102 SBFilters sbFilter = new SBFilters(999999, iSet); 103 104 for(var item: new int[]{1, 3, 5, 78, 99, 100, 101, 9999, 10000, 3534}) 105 { 106 var isIn = sbFilter.query_filter(item); 107 if(isIn == false) 108 { 109 System.out.printf("%d is not in the filter\n", item); 110 } 111 else 112 { 113 System.out.printf("%d is in the filter\n", item); 114 } 115 } 116 } 117 118 119 } |