Bloom Filter的應用


1、布隆過濾器是什么? 

  又快又小的處理方法
  布隆過濾器(Bloom Filter):是一種空間效率極高的概率型算法和數據結構,用於判斷一個元素是否在集合中(類似Hashset)。
  它的核心一個很長的二進制向量和一系列hash函數

  數組長度以及hash函數的個數都是動態確定的。

  Hash函數:SHA1,SHA256,MD5..

 

2、應用的經典場景 

  一個像Yahoo,HotMail和Gmail那樣的公眾電子郵件提供商,
  總是需要過濾來自發送垃圾郵件的人的垃圾郵件,
  一個辦法就是記錄下那些發送垃圾郵件的email地址,
  由於那些發送者不停地再注冊新的地址,全世界少說也有五十億個發垃圾郵件的地址,
  怎么樣迅速的判斷一個郵件地址是不是垃圾郵件地址?把它存起來然后確認?

  一個郵箱平均18個字節,50億個郵箱容量多大?
  18byte x 50億 = 90億

 

3、優勢和劣勢

  優勢:
    全量存儲但是不存儲元素本身,在某些對保密要求非常嚴格的場合有優勢;
    空間高效率
    插入/查詢時間都是常數O(k),遠遠超過一般的算法

  劣勢:
    存在誤算率(False Positive),隨着存入的元素數量增加,誤算率隨之增加;
    一般情況下不能從布隆過濾器中刪除元素;
    數組長度以及hash函數個數確定過程復雜;

 

4、應用場景 

  •  Google著名的分布式數據庫Bigtable以及Hbase使用了布隆過濾器來查找不存在的行或列,以及減少磁盤查找的IO次數
  •  文檔存儲檢查系統也采用布隆過濾器來檢測先前存儲的數據
  •  Goole Chrome瀏覽器使用了布隆過濾器加速安全瀏覽服務
  •  垃圾郵件地址過濾
  •  爬蟲URL地址去重
  •  解決緩存穿透問題

 

5、Bloom Filter實戰

   使用goole guava輕松實現bloom filter
  源碼分析 bitArray,numHashFunction,funnel,Strategy,put(),
  Demo實例
    場景描述:100w字符串放入布隆過濾器,另外隨機生成1w字符串,判斷他們在100w里面是否存在
    目的,了解布隆過濾器的簡單使用;
    了解誤判率對hash函數個數以及bit數組長度的影響
    使用bloom filter解決緩存擊穿的問題

  

public class BloomFilterTest {
    
    private static final int insertions = 1000000; //100w
    
    @Test
    public void bfTest(){
        //初始化一個存儲string數據的布隆過濾器,初始化大小100w,不能設置為0
        BloomFilter<String> bf = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), insertions,0.001);
        //初始化一個存儲string數據的set,初始化大小100w
        Set<String> sets = new HashSet<>(insertions);
        //初始化一個存儲string數據的set,初始化大小100w
        List<String> lists = new ArrayList<String>(insertions);
        
        //向三個容器初始化100萬個隨機並且唯一的字符串---初始化操作
        for (int i = 0; i < insertions; i++) {
            String uuid = UUID.randomUUID().toString();
            bf.put(uuid);
            sets.add(uuid);
            lists.add(uuid);
        }
        
        int wrong = 0;//布隆過濾器錯誤判斷的次數
        int right = 0;//布隆過濾器正確判斷的次數
        for (int i = 0; i < 10000; i++) {
            String test = i%100==0?lists.get(i/100):UUID.randomUUID().toString();//按照一定比例選擇bf中肯定存在的字符串
            if(bf.mightContain(test)){
                if(sets.contains(test)){
                    right ++;
                }else{
                    wrong ++;
                }
            }
        }
        
        System.out.println("=================right====================="+right);//100
        System.out.println("=================wrong====================="+wrong);
    }
    
}

 

6、解決緩存擊穿

private BloomFilter<String> bf;

@postConstruct  ------------->初始化的方法
private void init(){
    //將唯一編碼加進來
    //初始化布隆過濾器
    bf = BloomFiler.create(Funnels.stringFunner(Charsets.UTF_8),編碼.size()*1.2);
    for(String str:ucodes){
    bf.put(str);
}
========將布隆過濾器的數據放到單個服務,和業務代碼分開
使用多線程放進去
if(bf.mightContain(usercode)){
    return null;
}

 

 本次布隆過濾器落地場景是:優化關聯查詢

優化背景:查詢訂單需要關聯預警訂單數據,由於每查詢一筆預警就要查詢一次預警表,效率低,即是判斷該訂單是否預警

可以先將預警的訂單放到布隆過濾器中存放一份,則查詢訂單的時候可以用於關聯

應用該場景的原因:大部分訂單還是正常的,所以沒不要每次去關聯

先去布隆過濾器查詢該訂單是否存在,不存在則直接返回正常,存在則去預警表查詢,允許一定的誤差率

 

 

 

 

 

 

 

 

  


免責聲明!

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



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