布隆過濾器(Bloom Filter)-學習筆記-Java版代碼(挖坑ing)


布隆過濾器解決"面試題:

  • 如何建立一個十億級別的哈希表,限制內存空間"
  • "如何快速查詢一個10億大小的集合中的元素是否存在"

如題

布隆過濾器確實很神奇, 簡單來說就是通過多次hash將key存進一個集合中,可以灰常快速地在數億級的數據中快速查找!
實現布隆過濾器需要用bit位存儲的數組, 千萬別用int[] ,畢竟一個int整形占32位,一個int = 32 bit!
但是Java沒有bit, 那用byte吧,一個byte(8位)當做8位的bit來算吧,每一位代表一個具體的值來進行hash; 解析hash和設置hsah值的時候, 需要位運算提取出每位上的值(每位上的0或1)!
但是java的byte還需要分正負,默認一個byte的范圍為[-128,127] !

部分學習借鑒搬運的博客原文鏈接
https://www.cnblogs.com/liyulong1982/p/6013002.html
https://baike.baidu.com/item/布隆過濾器/5384697?fr=aladdin

筆記整理

算法核心

  1. 首先需要k個hash函數,每個函數可以把key散列成為1個整數
  2. 初始化時,需要一個長度為n比特的數組,每個比特位初始化為0
  3. 某個key加入集合時,用k個hash函數計算出k個散列值,並把數組中對應的比特位置為1
  4. 判斷某個key是否在集合時,用k個hash函數計算出k個散列值,並查詢數組中對應的比特位,如果所有的比特位都是1,認為在集合中。
    優點:
    不需要存儲key,使用節省空間

缺點:

  1. 算法判斷key在集合中時,有一定(通過優化算法可以降到很低)的概率key其實不在集合中
  2. 無法刪除

典型的應用場景:

  • 某些存儲系統的設計中,會存在空查詢缺陷:當查詢一個不存在的key時,需要訪問慢設備,導致效率低下。
  • 比如一個前端頁面的緩存系統,可能這樣設計:先查詢某個頁面在本地是否存在,如果存在就直接返回,如果不存在,就從后端獲取。但是當頻繁從緩存系統查詢一個頁面時,緩存系統將會頻繁請求后端,把壓力導入后端。
  • 這是只要增加一個bloom算法的服務,后端插入一個key時,在這個服務中設置一次
    需要查詢后端時,先判斷key在后端是否存在,這樣就能避免后端的壓力.
  • 最近還學到, 布隆過濾器還可以防止緩存雪崩, 原理同上.

黑客通過大量請求數據庫中不存在的key, 導致遍歷整個緩存和數據路進行查詢, 每次都無法讓前端的緩存發揮效果,緩存系統將會頻繁請求后端數據庫,很快就會造成系統雪崩.
因此可以利用布隆過濾器進行解決這個問題.

  • 解決思路: 將數據庫中的key全部建立到布隆過濾器中, 每次請求先查詢布隆過濾器; 如果存在,則放行, 畢竟布隆過濾器會有很少部分key會誤算!
  • 注意: 通過布隆過濾器的值,極大地概率存在着這個key;不通過的key, 那么一定不存在.
模擬布隆過濾器; 先挖坑,扔在這里

一個byte分為8位用,故1250萬的byte數組就可以了.
該數組大小為: .

package com.szs.test;

public class myBloomFilter {
	
	//一個boolean只占一個字節, 一個字節是八位,把每個字節拆成八位來用
	//一個byte分為8位用,故可哈希出10億個具體的數據,1.250億的byte數組就可以了,但是需要125M更多的內存.
        // 但是具體題目一般都有內存的限制(比如100M 以內), 還有其他的情況需要考慮!
	//10^9 == 10億 , 故int就夠了.( int的取值范圍為: -2^31——2^31-1,即-2147483648——2147483647 , 大概最高值為2*10^9)
	//如下數組為1.25*10^7大小.
	private static byte[] array01 = new byte[12500000];
	private static byte[] array02 = new byte[12500000];
        private static byte[] array03 = new byte[12500000];
	/** 簡單的布隆過濾器的main測試類
	 * @param args
	 */
	public static void main(String[] args) {

	}
	
	/**
	 * 查找一個key,判斷是否存在;若存在返回true,否則返回false
	 * @param x
	 */
	public static boolean findKey(long x) {
		return true;
	}
	/**
	 * 
	 * @param x
	 */
	public static void insertKey(long x) {
		
	}
	/**
	 * 刪除一個key, 暴力for循環進行刪除
	 * @param x
	 */
	public static void deleteKey(long x) {
		
	}
	/**
	 * 嘗試hash后,返回對應的hash值,
	 */
	public static void hashKeyThreeTimes(long x) {
		
	}
	/**
	 * 存儲hash值到數組中的index下標
	 * @param x
	 */
	public static void storeHashCode(long hashCode) {
		
	}

}

其他思路
  • 量子計算, 一個量子有八種狀態,其實就是八進制,兩個量子就可以枚舉64種狀態; 依次類推,十億級別數據量的時間復雜度為: log810^9= 9 .故時間復雜度為O(1).
  • 並行計算: 多處理進行處理.
  • 增加系統內存,增加JVM虛擬機的可分配內存.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM