深入淺出聊布隆過濾器(Bloom Filter)

之前在網上看到過這么一段話👇

Data structures are nothing different. They are like the bookshelves of your application where you can organize your data. Different data structures will give you different facility and benefits. To properly use the power and accessibility of the data structures you need to know the trade-offs of using one.

這段話的大意就是:數據結構沒有什么不同,在應用程序中他們就像是可以組織數據的書架,不同的數據結構將為您提供不同的便利和好處,你需要仔細權衡自己的需求之后妥善的使用它們。布隆過濾器就是踐行這句話的代表,那么今天就和大家深入淺出的聊聊布隆過濾器(Bloom Filter)。

布隆過濾器(Bloom Filter)

還是老規矩,學習一個新知識之前,我們需要了解他的基本概念👇

布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實際上是一個很長的二進制向量和一系列隨機映射函數。布隆過濾器可以用于檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都比一般的算法要好的多,缺點是有一定的誤識別率和刪除困難。

我們在布隆過濾器的基本概念中可以看到這么一句話,布隆過濾器可以用于檢索一個元素是否在一個集合中。有些小伙伴可能會問:我們直接用 HashMap 去檢索元素不就行了嗎,為什么還要用布隆過濾器呢?HashMap 確實可以幫助我們實現這個功能,而且 HashMap 通過一次運算就能確定某個元素的位置,也就可以幫助我們檢查某個元素是否在一個集合中。那么我們接下來再思考一個問題:如果這個元素集合中有十億個隨機數,那我們怎樣來判斷某個數是否存在呢?

如果元素集合中包含了十億個隨機數的話,那么首先就會給我們帶來空間上的問題,按一個隨機數占4個子節計算的話,這十億個隨機數就要占用將近4G的存儲空間,空間消耗就非常大,這時候就需要用到布隆過濾器(Bloom Filter)來幫助我們解決這個問題了。

🍓🍓布隆過濾器的基本思想🍓🍓

上面我們提到了元素集合中包含了十億個隨機數,如果直接存儲這十億個元素的話就需要占用很大的空間,所以我們肯定不能直接存儲元素。那么我們該怎樣存儲呢?存儲方式也是十分巧妙的,可以采用位數組的方式,不直接存儲元素,而是存儲元素是否存在的狀態,這樣就可以節約大量的存儲空間~(也不知道大神們是怎么想到這么巧妙的辦法的😂)

下面我們就一起看看布隆過濾器是怎么判斷一個元素是否在一個集合中的👇

🥝 ① 🥝 現在有一個集合和一個初始狀態都為0的位數組

🥝 ② 🥝 集合中的元素經過N個散列函數計算出元素在數組當中的位置,并且將數組中對應位置的0改成1

🥝 ③ 🥝 如果此時需要判斷元素X是否存在,那么元素X也會經過這N個散列函數的運算而得到數組中的若干個位置,如果得到的若干個位置中的值均為1,那么則證明元素X很可能存在與集合當中,反之則證明元素X一定不存在于集合當中。如下圖所示,此時元素X經過N個散列元素計算出的位置上所存儲的值不都是1,那么就證明元素X不存在集合中。

🍓🍓布隆過濾器的特性🍓🍓

在上面我們講到了布隆過濾器的思想,在第③點中有這樣一句話:如果得到的若干個位置中的值均為1,那么則證明元素X 很可能 存在與集合當中。為什么說全都是1的情況是很可能存在,而不是一定存在呢?這就和哈希函數的特點有關系了...

我們都知道哈希函數是可以將任意大小的輸入數據轉換成特定大小的輸出數據的函數(轉換后的數據稱為哈希值),哈希函數還有以下兩個特點:

  • 如果根據同一個哈希函數得到的哈希值不同,那么這兩個哈希值的原始輸入值肯定不同。
  • 如果根據同一個哈希函數得到的兩個哈希值相等,兩個哈希值的原始輸入值有可能相等,有可能不相等。

這就類似于 Java 中兩個對象的 HashCode 相等,但是對象本身不一定相等的道理。說白了,通過散列函數計算后得到位數組上映射點的值全都是1,不一定是要查詢的這個變量之前存進來時設置的,也有可能是其他元素映射的點。這也就引出了布隆過濾器的一個特性:存在一定的誤判

在英雄聯盟里,你可以完全信任布隆,但是寫代碼時還是得提防著點😂

那么我們能不能刪除位數組中的元素呢?很顯然是不行的,因為在位數組上的同一個點有可能有多個輸入值映射,如果刪除了會影響布隆過濾器里其他元素的判斷結果。這也就是布隆過濾器的另一個特性:不能刪除布隆過濾器里的元素

所以我們就可以總結出布隆過濾器的優缺點👇

🍎優點🍎:在空間和時間方面,都有著巨大的優勢。因為不是存完整的數據,是一個二進制向量,能節省大量的內存空間,時間復雜度方面,由于計算時是根據散列函數計算查詢的,那么假設有N個散列函數,那么時間復雜度就是O(N);同時在存儲元素時存儲的不是元素本身,而是二進制向量,所以在一些對保密性要求嚴格的場景有一定優勢。

🍌缺點🍌:存在一定的誤判(存進布隆過濾器里的元素越多,誤判率越高);不能刪除布隆過濾器里的元素,隨著使用的時間越來越長,因為不能刪除,存進里面的元素越來越多,導致占用內存越來越多,誤判率越來越高,最后不得不重置。

🍓🍓布隆過濾器的應用🍓🍓

我們都聽說過“緩存穿透”,那我們應該如何解決緩存穿透呢?沒錯,就是通過布隆過濾器來解決這個問題💪。

緩存穿透的問題主要是因為傳進來的 Key 值在 Redis 中是不存在的,那么就會直接打在數據庫上,從而增大數據庫的壓力。針對這種情況,可以在 Redis 前加上布隆過濾器,預先把數據庫中的數據加入到布隆過濾器中,在查詢 Redis 之前先通過布隆過濾器判斷 Key 值是否存在,如果不存在就直接返回,如果 Key 值存在的話,則按照原來的流程繼續執行。

解決緩存穿透利用的就是布隆過濾器判斷結果為不存在的話就一定不存在這一個特點,但是由于布隆過濾器有一定的誤判,所以并不能說完全解決緩存穿透,但是能很大程度緩解緩存穿透的問題。

🍓🍓模擬實現布隆過濾器🍓🍓

最后貼上一段代碼,來模擬實現一下布隆過濾器👇

import java.util.BitSet;/*** @description: MyBloomFilter* @author: 莊霸.liziye* @create: 2022-04-01 16:50**/
public class MyBloomFilter {/*** 一個長度為10億的比特位*/private static final int DEFAULT_SIZE = 256 << 22;/*** 為了降低錯誤率,使用加法hash算法,所以定義一個8個元素的質數數組*/private static final int[] seeds = {3, 5, 7, 11, 13, 31, 37, 61};/*** 相當于構建8個不同的hash算法*/private static HashFunction[] functions = new HashFunction[seeds.length];/*** 初始化布隆過濾器的bitmap,即位數組*/private static BitSet bitset = new BitSet(DEFAULT_SIZE);/*** 添加數據** @param value 需要加入的值*/public static void add(String value) {if (value != null) {for (HashFunction f : functions) {//計算 hash 值并修改 bitmap 中相應位置為 truebitset.set(f.hash(value), true);}}}/*** 判斷相應元素是否存在* @param value 需要判斷的元素* @return 結果*/public static boolean contains(String value) {if (value == null) {return false;}boolean ret = true;for (HashFunction f : functions) {ret = bitset.get(f.hash(value));//一個 hash 函數返回 false 則跳出循環if (!ret) {break;}}return ret;}/*** 測試*/public static void main(String[] args) {for (int i = 0; i < seeds.length; i++) {functions[i] = new HashFunction(DEFAULT_SIZE, seeds[i]);}//添加1億個元素for (int i = 0; i < 100000000; i++) {add(String.valueOf(i));}String id = "123456789";add(id);System.out.println("元素 123456789 是否存在:" + contains(id));System.out.println("元素 234567890 是否存在:" + contains("234567890"));}
}class HashFunction {private int size;private int seed;public HashFunction(int size, int seed) {this.size = size;this.seed = seed;}public int hash(String value) {int result = 0;int len = value.length();for (int i = 0; i < len; i++) {result = seed * result + value.charAt(i);}int r = (size - 1) & result;return (size - 1) & result;}
}復制代碼


作者:不肯過江東丶
鏈接:https://juejin.cn/post/7083294020323000356
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


---------------------
作者:栗少
來源:CSDN
原文:https://blog.csdn.net/weixin_38556197/article/details/124111236
版權聲明:本文為作者原創文章,轉載請附上博文鏈接!
內容解析By:CSDN,CNBLOG博客文章一鍵轉載插件

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/283862.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/283862.shtml
英文地址,請注明出處:http://en.pswp.cn/news/283862.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第五周作業

本周作業內容&#xff1a;顯示當前系統上root、fedora或user1用戶的默認shell&#xff1b;#egrep "^(root|user1|fedora)" /etc/passwd|cut -d: -f72、找出/etc/rc.d/init.d/functions文件中某單詞后面跟一組小括號的行&#xff0c;形如&#xff1a;hello()&#xff…

我為什么卸載了今日頭條

曾經的自媒體人自述。 兩三年前自媒體熱曾席卷中國互聯網&#xff0c;當時短視頻還不是很火&#xff0c;一般的自媒體人都是以撰寫文章為主&#xff0c;各種微信公眾號層出不窮&#xff0c;10W的俗稱 爆文&#xff08;豹紋&#xff09;。后來以今日頭條為領頭的短視頻自媒體出現…

appium執行iOS測試腳本并發問題

appium1.4.XiOS9.Xxcode7.X: appium1.4.xiOS9.xxcode7.x&#xff0c;這一整套的配置做移動端自動化測試是測試人員常用的測試框架。關于&#xff0c;這一套測試框架的并發問題&#xff1a;基于mac端&#xff0c;啟動多臺appium服務器會導致appium的運行出錯。這是因為多個appiu…

WinForm(五)控件和它的成員

窗體無疑是WinForm的主角&#xff0c;每個窗體都是用一個class來承載&#xff0c;那么窗體的控件&#xff0c;就是類中的私有字段了。每個窗體有三個文件&#xff0c;兩個.cs文件&#xff0c;是一個分部類&#xff0c;Designer.cs是自動生成的C#代碼&#xff0c;一般是拖拽控件…

Atitit.異常處理 嵌套??冗長的解決方案

Atitit.異常處理 嵌套 冗長的解決方案 1. 異常處理的需要改進的地方1 2. 異常設計的初衷是, 在程序中出現錯誤時, 由程序自己處理錯誤, 盡量不要以exit(0)這種粗暴的方式中止程序. 1 3. 正常流程和異常流程的分離。2 4. “是藥三分毒”&#xff0c; 任何事物有缺點&#xff0c…

一文詳解|增長那些事兒

目錄 增長的背景 1.1 增長的定義 1.2 如何判斷事物是否在增長 1.3 如何判斷事物能否持續增長 如何進行增長 2.1 尋找增長機會點&#xff08;人的能力&#xff09; 2.1.1 發散與收劍找機會點 2.1.2 實驗分析驗證 2.1.3 增長洞察提取策略 2.1.4 如何找到大機會 2.2 設…

在MVC項目中使用Ninject

項目結構圖&#xff1a; App_start文件夾中的文件是VS自己創建的&#xff0c;其中NinjectWebCommon類在創建之初并不存在。后面會再次提到&#xff01; 添加一個Home控制器。代碼如下&#xff1a; using EssentialTools.Models; using Ninject; using System; using System.Col…

linux IP、端口連通性測試

ssh -v -p 50001 root10.210.200.82轉載于:https://www.cnblogs.com/kuiyeit/p/6723508.html

緊急通知:360 網站衛士前端公共庫已停止服務

所有使用了360前端公共庫的開發者和站長們&#xff0c;請及時更換你的前端庫的鏈接&#xff08;主要是前端庫和谷歌 fonts&#xff09;&#xff0c;否則網站打開速度會極慢&#xff0c;甚至會在 Chrome 瀏覽器中崩潰。 360前端公共庫曾經提供的服務有&#xff1a; 前端公共庫&a…

一文學會Autofac的基礎操作:幾種實現注冊方式、3種注入方式、生命周期、AOP以及過濾器實現依賴注入...

前言&#xff1a;直接開干。使用Autofac進行服務注冊實踐&#xff1a;新建三個項目&#xff0c;分別是webapi項目 Wesky.Core.Autofac以及兩個類庫項目 Wesky.Core.Interface和Wesky.Core.Service。在Webapi項目下&#xff0c;引用Autofac的三個包&#xff1a;Autofac、Autofac…

解析互聯網廣告術語 CPM、CPC、CPA、CPS、CPL、CPR 是什么意思

1. CPM&#xff08;Cost per mille&#xff09;&#xff0c;每千次展現收費 這是一種最為常見的廣告模式&#xff0c;也是很多網站流量變現的一種途徑&#xff0c;這種廣告不管計算點擊&#xff0c;或者什么注冊下載之類的轉化&#xff0c;只要這個廣告在網站上被正常的展現給…

JavaScript數組迭代方法(圖解)

轉載于:https://www.cnblogs.com/seanna/p/6724032.html

Rider調試ASP.NET Core時報thread not gc-safe的解決方法

新建了一個ASP.NET Core 5.0的Web API項目&#xff0c;當使用斷點調試Host.CreateDefaultBuilder(args)時&#xff0c;進入該函數后查看中間變量的值&#xff0c;報錯Evaluation is not allowed: The thread is not at a GC-safe point。在群里問了也沒人回應&#xff0c;可能沒…

The SDK platform-tools version ((23)) is too old to check APIs compiled with API 26;

好像是更新過啥SDK之后&#xff0c;項目一直在包名的那一行顯示紅線&#xff0c;不過是不報編譯錯誤的&#xff0c;就是看著老扎心老扎心的&#xff0c;開始以為是指定的SDK版本的問題&#xff0c;修改后發現無效&#xff0c;最后找到方法解決&#xff1a; 打開SDK Manager ---…

oracle 各種日期函數格式和操作

2019獨角獸企業重金招聘Python工程師標準>>> ORACLE日期時間函數大全 TO_DATE格式(以時間:2007-11-02 13:45:25為例) Year: yy two digits 兩位年 顯示值:07 yyy three digits 三位年 顯示值:00…

火山引擎李玉光:字節跳動大規模K8s集群管理實踐

2022年5月31日&#xff0c;在CSDN云原生系列在線峰會第6期“K8s大規模應用和深度實踐峰會”&#xff0c;火山引擎資深云原生架構師李玉光分享了《字節跳動大規模K8s集群管理實踐》。 字節跳動云原生體系 字節跳動內部云原生技術的使用貫穿組織技術體系各層面&#xff0c;整體如…

(7)關于margin的一些想法2.0

這篇主要討論的就是margin負值與float的關系。 首先&#xff0c;例子。 <!doctype html> <html> <head> <meta charset"utf-8"> <title>無標題文檔</title> <style typetext/css> html,body{padding:0;margin:0;} div{wid…

解決ASP.NET Core在Task中使用IServiceProvider的問題

前言問題的起因是在幫同事解決遇到的一個問題&#xff0c;他的本意是在EF Core中為了解決避免多個線程使用同一個DbContext實例的問題。但是由于對Microsoft.Extensions.DependencyInjection體系的深度不是很了解&#xff0c;結果遇到了新的問題&#xff0c;當時整得我也有點蒙…

什么是SRE?一文詳解SRE運維體系

在任何有一定規模的企業內部&#xff0c;一旦推行起來整個SRE的運維模式&#xff0c;那么對于可觀測性系統的建設將變得尤為重要&#xff0c;而在整個可觀測性系統中。 可觀測性系統 在任何有一定規模的企業內部&#xff0c;一旦推行起來整個SRE的運維模式&#xff0c;那么對于…

python初探

python近兩年似乎已經很熱了&#xff0c;不了解一下怎么能行呢&#xff0c;似乎python最大的優點就是簡潔、易懂、優雅。目前豆瓣、知乎等后臺服務使用的也都是python語言。 python一般可以用于網站服務、小工具、數據分析等工作。它作為高級語言&#xff0c;和js一樣&#xff…