Java中的布隆過濾器你真的懂了嗎
什么是布隆過濾器
布隆過濾器(Bloom Filter)是一種空間效率非常高的隨機數(shù)據(jù)結(jié)構(gòu),它利用位數(shù)組(BitSet)表示一個集合,并通過一定數(shù)量的哈希函數(shù)將元素映射為位數(shù)組中的位置,用于檢查一個元素是否屬于這個集合。
實現(xiàn)的核心思想
對于一個元素,通過多個哈希函數(shù)生成多個哈希值,將對應(yīng)的位在位數(shù)組中設(shè)為 1,若多個哈希值對應(yīng)的位都為 1,則認為該元素可能在集合中;若至少有一個哈希值對應(yīng)的位為 0,則該元素一定不在集合中。這種方法可以在較小的空間中實現(xiàn)高效的查找,但可能存在誤判率(false positive)。
怎么理解
一個典型的布隆過濾器包含三個參數(shù): 位數(shù)組的大?。创鎯υ氐膫€數(shù)); 哈希函數(shù)的個數(shù); 填充因子(即誤判率),即將元素數(shù)量與位數(shù)組大小的比值。
如上圖所示: 布隆過濾器的基本操作流程,包括初始化位數(shù)組和哈希函數(shù)、插入元素、檢查元素是否在集合中等。其中,每個元素都會被多個哈希函數(shù)映射到位數(shù)組中的多個位置,而在檢查元素是否在集合中時,需要確保所有對應(yīng)的位都被設(shè)置為 1,才會認為該元素可能在集合中。
典型應(yīng)用場景
垃圾郵件過濾: 將所有的黑名單郵件對應(yīng)的哈希值在布隆過濾器中對應(yīng)的位置設(shè)為 1,對于每一封新郵件,將其哈希值在布隆過濾器中對應(yīng)的位置檢查是否都為 1,若是,則認為該郵件是垃圾郵件,否則可能是正常郵件;
URL 去重: 將已經(jīng)抓取的 URL 對應(yīng)的哈希值在布隆過濾器中對應(yīng)的位置設(shè)為 1,對于每一條新的 URL,將其哈希值在布隆過濾器中對應(yīng)的位置檢查是否都為 1,若是,則認為該 URL 已經(jīng)抓取過,否則需要進行抓?。?/p>
緩存擊穿: 將緩存中存在的所有數(shù)據(jù)對應(yīng)的哈希值在布隆過濾器中對應(yīng)的位置設(shè)為 1,對于每一個查詢的鍵值,將其哈希值在布隆過濾器中對應(yīng)的位置檢查是否都為 1,若是,則認為該鍵值存在于緩存中,否則需要從數(shù)據(jù)庫中查詢并將其添加到緩存中。
需要注意的是,布隆過濾器的誤判率會隨著位數(shù)組大小的增加而減小,但同時也會增加內(nèi)存開銷和計算時間。 為了方便理解布隆過濾器,下面用java代碼實現(xiàn)一個簡單的布隆過濾器:
import java.util.BitSet; import java.util.Random; public class BloomFilter { ??private BitSet bitSet; ??????????// 位集,用于存儲哈希值 ??private int bitSetSize; ????????// 位集大小 ??private int numHashFunctions; ??// 哈希函數(shù)數(shù)量 ??private Random random; ?????????// 隨機數(shù)生成器 ??// 構(gòu)造函數(shù),根據(jù)期望元素數(shù)量和錯誤率計算位集大小和哈希函數(shù)數(shù)量 ??public BloomFilter(int expectedNumItems, double falsePositiveRate) { ????this.bitSetSize = optimalBitSetSize(expectedNumItems, falsePositiveRate); ????this.numHashFunctions = optimalNumHashFunctions(expectedNumItems, bitSetSize); ????this.bitSet = new BitSet(bitSetSize); ????this.random = new Random(); ??} ??// 根據(jù)期望元素數(shù)量和錯誤率計算最佳位集大小 ??private int optimalBitSetSize(int expectedNumItems, double falsePositiveRate) { ????int bitSetSize = (int) Math.ceil(expectedNumItems * (-Math.log(falsePositiveRate) / Math.pow(Math.log(2), 2))); ????return bitSetSize; ??} ??// 根據(jù)期望元素數(shù)量和位集大小計算最佳哈希函數(shù)數(shù)量 ??private int optimalNumHashFunctions(int expectedNumItems, int bitSetSize) { ????int numHashFunctions = (int) Math.ceil((bitSetSize / expectedNumItems) * Math.log(2)); ????return numHashFunctions; ??} ??// 添加元素到布隆過濾器中 ??public void add(String item) { ????// 計算哈希值 ????int[] hashes = createHashes(item.getBytes(), numHashFunctions); ????// 將哈希值對應(yīng)的位設(shè)置為 true ????for (int hash : hashes) { ??????bitSet.set(Math.abs(hash % bitSetSize), true); ????} ??} ??// 檢查元素是否存在于布隆過濾器中 ??public boolean contains(String item) { ????// 計算哈希值 ????int[] hashes = createHashes(item.getBytes(), numHashFunctions); ????// 檢查哈希值對應(yīng)的位是否都為 true ????for (int hash : hashes) { ??????if (!bitSet.get(Math.abs(hash % bitSetSize))) { ????????return false; ??????} ????} ????return true; ??} ??// 計算給定數(shù)據(jù)的哈希值 ??private int[] createHashes(byte[] data, int numHashes) { ????int[] hashes = new int[numHashes]; ????int hash1 = Math.abs(random.nextInt()); ????int hash2 = Math.abs(random.nextInt()); ????for (int i = 0; i < numHashes; i++) { ??????// 使用兩個隨機哈希函數(shù)計算哈希值 ??????hashes[i] = Math.abs((hash1 * i) + (hash2 * i) + i) % data.length; ????} ????return hashes; ??} }
以上就是Java中的布隆過濾器你真的懂了嗎的詳細內(nèi)容,更多關(guān)于Java布隆過濾器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring MVC傳遞接收參數(shù)方式小結(jié)
大家在開發(fā)中經(jīng)常會用到Spring MVC Controller來接收請求參數(shù),主要常用的接收方式就是通過實體對象以及形參等方式、有些用于GET請求,有些用于POST請求,有些用于兩者,下面介紹幾種常見的Spring MVC傳遞接收參數(shù)的方式2021-11-11詳解快速排序算法中的區(qū)間劃分法及Java實現(xiàn)示例
這篇文章主要介紹了詳解快速排序算法中的區(qū)間劃分法及Java實現(xiàn)示例,文中分別介紹了快排時兩種區(qū)間劃分的思路,需要的朋友可以參考下2016-04-04MyBatis基于pagehelper實現(xiàn)分頁原理及代碼實例
這篇文章主要介紹了MyBatis基于pagehelper實現(xiàn)分頁原理及代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06