最近面臨這樣的場景:布隆過濾器(bloom filter)是2023年由布隆提出的。它實際上是乙個很長的二進位制向量和一系列隨機對映函式。布隆過濾器可以用於檢索乙個元素是否在乙個集合中。它的優點是空間效率和查詢時間都比一般的演算法要好的多,缺點是有一定的誤識別率和刪除困難。deny list2億+資料需要呼叫後端服務a,業務需要1min處理完成,那麼a服務承載的tps達到驚人的300w......必須想辦法降低tps。
那麼方案來了:1、把時間視窗拉長 2、降低待處理資料量。
拉長時間業務肯定是接受不了的,但是按照以往的經驗,這部分資料並不全部需要處理,可能僅有一半真正需要呼叫a服務,所以我們可以把1億資料給過濾掉。
這裡我們維護乙個布隆過濾器來進行資料的過濾。
資料判重
預過濾核心是乙個長度為m的bit array和k個hash方法。
如下圖,我們將乙個newsid通過3個hash方法對映到長為8的陣列上。
判斷newsid是否存在,則看陣列中3個位置是否都取到1:全為1,newsid可能存在於集合中;不全為1,newsid一定不存在於集合中。
容易發現,布隆過濾器存在假陽性的情況,即將不在集合中的元素誤判為在集合中。過濾器中的元素個數越多,假陽性的可能性越大。
同時,元素可以被加入過濾器,但很難從過濾器中刪除(有可能刪除的當前元素與其他元素共享了某乙個bit,造成假陰性)。
根據假陽性率計算公式:
可知在雜湊函式的個數k一定的情況下:
// calbloomsize 計算布隆過濾器位圖大小
// elemnum 元素個數
// errorrate 誤判率
func calbloomsize(elemnum uint64, errrate float64) uint64
// calhashfuncnum 計算需要的雜湊函式數量
// elemnum 元素個數
// bloomsize 布隆過濾器位圖大小
func calhashfuncnum(elemnum, bloomsize uint64) uint64
// filter
type filter struct
// newfilter newfilter
func newfilter(elemnum, bloomsize, hashfuncnum uint64, errrate float64) *filter
}// init 初始化布隆過濾器
func (f *filter) init()
f.keys[uint32(randnum.uint64())] = true
}}// add add
func (f *filter) add(elem byte)
}// iscontain 判斷元素是否在集合裡面
func (f *filter) iscontain(elem byte) bool
}return true
}// hmacwithsha128 通過加鹽生成不同的hash值
func hmacwithsha128(seed byte, key byte) byte
測試:2億長16b的元素,失誤率0.0001,分配到過濾器需要0.4g,如果放hash表,則需要3.2 布隆過濾器速度 布隆過濾器原理及在推薦業務的應用
提到布隆過濾器總想起上大學時候學習的什麼切比雪夫濾波器之類的東西 博主是學通訊的 我發現過濾器一般都是以發明人的名字命名,布隆過濾器是一種布林型判斷器,可以非常高效的判斷乙個物品是否在某個列表裡。有人說判斷乙個item是否在乙個item列表裡,只要將所有item存在資料庫,或者做一層快取存在redi...
布隆過濾器原理及實現
如何高效判斷元素w是否存在於集合a之中?首先想到的答案是,把集合a中的元素乙個個放到雜湊表中,然後在雜湊表中查一下w即可。這樣確實可以解決小資料量場景下元素存在性判定,但如果a中元素數量巨大,甚至資料量遠遠超過機器記憶體空間,該如何解決問題呢?實現乙個基於磁碟和記憶體的雜湊索引當然可以解決這個問題。...
布隆過濾器
布隆過濾器 bloom filter 是1970年由布隆提出的。它實際上是乙個很長的二進位制向量和一系列隨機對映函式。布隆過濾器可以用於檢索乙個元素是否在乙個集合中。它的優點是空間效率和查詢時間都遠遠超過一般的演算法,缺點是有一定的誤識別率和刪除困難。如果想要判斷乙個元素是不是在乙個集合裡,一般想到...