1. 程式人生 > >BloomFilter布隆過濾器的java實現

BloomFilter布隆過濾器的java實現

網上有很多的原理解釋說明,此處不再對bloom filter做過多的說明,直接上程式碼(注:程式碼參考了網上其他部落格的實現,比如布隆過濾器(Bloom Filter)Java實現

  1. /** 
  2.   * 專案名:SpiderCrawler 
  3.   * 檔名:BloomFilterTest.java 
  4.   * 作者:zhouyh 
  5.   * 時間:2014-8-29 下午02:54:56 
  6.   * 描述:TODO(用一句話描述該檔案做什麼)  
  7.   */
  8. package com.utilTest;  
  9. import java.io.BufferedReader;  
  10. import java.io.File;  
  11. import
     java.io.FileInputStream;  
  12. import java.io.IOException;  
  13. import java.io.InputStream;  
  14. import java.io.InputStreamReader;  
  15. import java.util.BitSet;  
  16. /** 
  17.  * 類名: BloomFilterTest 
  18.  * 包名: com.utilTest 
  19.  * 作者: zhouyh 
  20.  * 時間: 2014-8-29 下午02:54:56 
  21.  * 描述: 布隆過濾器,傳統的布隆過濾器不支援從集合中刪除成員 
  22.  */
  23. publicclass BloomFilterTest {  
  24.     //DEFAULT_SIZE為2的29次方,即此處的左移28位
  25.     privatestaticfinalint DEFAULT_SIZE = 2<<28;  
  26.     /* 
  27.      * 不同雜湊函式的種子,一般取質數 
  28.      * seeds陣列共有8個值,則代表採用8種不同的雜湊函式 
  29.      */
  30.     privateint[] seeds = newint[]{3571113313761};  
  31.     /* 
  32.      * 初始化一個給定大小的位集 
  33.      * BitSet實際是由“二進位制位”構成的一個Vector。 
  34.      * 假如希望高效率地儲存大量“開-關”資訊,就應使用BitSet. 
  35.      */
  36.     private
     BitSet bitSets = new BitSet(DEFAULT_SIZE);  
  37.     //構建hash函式物件
  38.     private SimpleHash[] hashFuns = new SimpleHash[seeds.length];  
  39.     //布隆過濾器配置檔案存放路徑
  40.     private String path = "";  
  41.     public BloomFilterTest(String path){  
  42.         /** 
  43.          *  給出所有的hash值,共計seeds.length個hash值。共8位。 
  44.          *  通過呼叫SimpleHash.hash(),可以得到根據8種hash函式計算得出hash值。   
  45.          *  傳入DEFAULT_SIZE(最終字串的長度),seeds[i](一個指定的質數)即可得到需要的那個hash值的位置。         
  46.          */
  47.         for(int i=0; i<seeds.length; i++){  
  48.             hashFuns[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);  
  49.         }  
  50.         //配置檔案路徑地址
  51.         this.path = path;  
  52.     }  
  53.     /** 
  54.      *  
  55.      * 方法名:add 
  56.      * 作者:zhouyh 
  57.      * 建立時間:2014-8-30 下午02:07:35 
  58.      * 描述:將給定的字串標記到bitSets中,即設定字串的8個函式值的位置為1 
  59.      * @param value 
  60.      */
  61.     publicsynchronizedvoid add(String value){  
  62.         for(SimpleHash hashFun : hashFuns){  
  63.             bitSets.set(hashFun.hash(value), true);  
  64.         }  
  65.     }  
  66.     /** 
  67.      *  
  68.      * 方法名:isExit 
  69.      * 作者:zhouyh 
  70.      * 建立時間:2014-8-30 下午02:12:30 
  71.      * 描述:判斷給定的字串是否已經存在在bloofilter中,如果存在返回true,不存在返回false 
  72.      * @param value 
  73.      * @return 
  74.      */
  75.     publicsynchronizedboolean isExit(String value){  
  76.         //判斷傳入的值是否為null
  77.         if(null == value){  
  78.             returnfalse;  
  79.         }  
  80.         for(SimpleHash hashFun : hashFuns){  
  81.             if(!bitSets.get(hashFun.hash(value))){  
  82.                 //如果判斷8個hash函式值中有一個位置不存在即可判斷為不存在Bloofilter中
  83.                 returnfalse;  
  84.             }  
  85.         }  
  86.         returntrue;  
  87.     }  
  88.     /** 
  89.      *  
  90.      * 方法名:init 
  91.      * 作者:zhouyh 
  92.      * 建立時間:2014-8-30 下午02:28:49 
  93.      * 描述:讀取配置檔案 
  94.      */
  95.     publicvoid init(){  
  96.         File file = new File(path);  
  97.         FileInputStream in = null;  
  98.         try {  
  99.             in = new FileInputStream(file);  
  100.             long lt = System.currentTimeMillis();  
  101.             read(in);  
  102.             System.out.println(System.currentTimeMillis()-lt);  
  103.             System.out.println(Runtime.getRuntime().totalMemory());  
  104.         }catch(Exception e){  
  105.             e.printStackTrace();  
  106.         }finally{  
  107.             try {  
  108.                 if(in!=null){  
  109.                     in.close();  
  110.                     in = null;  
  111.                 }             
  112.             } catch (IOException e) {  
  113.                 // TODO Auto-generated catch block
  114.                 e.printStackTrace();  
  115.             }  
  116.         }  
  117.     }  
  118.     /** 
  119.      *  
  120.      * 方法名:read 
  121.      * 作者:zhouyh 
  122.      * 建立時間:2014-8-30 下午02:26:59 
  123.      * 描述:根據傳入的流,初始化bloomfilter 
  124.      * @param in 
  125.      */
  126.     privatevoid read(InputStream in){  
  127.         if(null == in){ //如果in為null,則返回
  128.             return;  
  129.         }  
  130.         int i = 0;  
  131.         InputStreamReader reader = null;  
  132.         try {  
  133.             //建立輸入流
  134.             reader = new InputStreamReader(in, "UTF-8");  
  135.             BufferedReader buffReader = new BufferedReader(reader, 512);  
  136.             String theWord = null;            
  137.             do {  
  138.                 i++;              
  139.                 theWord = buffReader.readLine();  
  140.                 //如果theWord不為null和空,則加入Bloomfilter中
  141.                 if(theWord!=null && !theWord.trim().equals("")){  
  142.                     add(theWord);  
  143.                 }  
  144.                 if(i%10000 == 0){  
  145.                     System.out.println(i);  
  146.                 }  
  147.             } while (theWord != null);  
  148.         } catch (IOException e){  
  149.             e.printStackTrace();  
  150.         } finally{  
  151.             //關閉流
  152.             try {  
  153.                 if(reader != null){  
  154.                     reader.close();  
  155.                     reader = null;  
  156.                 }                 
  157.                 if(in != null){  
  158.                     in.close();  
  159.                     in = null;  
  160.                 }  
  161.             } catch (IOException e) {  
  162.                 // TODO: handle exception
  163.                 e.printStackTrace();  
  164.             }  
  165.         }  
  166.     }  
  167.     /** 
  168.      * 方法名:main 
  169.      * 作者:zhouyh 
  170.      * 建立時間:2014-8-29 下午02:54:56 
  171.      * 描述:TODO(這裡用一句話描述這個方法的作用) 
  172.      * @param args 
  173.      */
  174.     publicstaticvoid main(String[] args) {  
  175.         // TODO Auto-generated method stub
  176.         BloomFilterTest bloomFilterTest = new BloomFilterTest("f:/fetchedurls.txt");  
  177.         bloomFilterTest.init();  
  178.         System.out.println(bloomFilterTest.isExit("http://www.plating.org/news_info.asp?pid=28&id=2857"));  
  179.     }  
  180.     publicstaticclass SimpleHash {  
  181.         /* 
  182.          * cap為DEFAULT_SIZE,即用於結果的最大字串的值 
  183.          * seed為計算hash值的一個key值,具體對應上文中的seeds陣列 
  184.          */
  185.         privateint cap;  
  186.         privateint seed;  
  187.         /** 
  188.          *  
  189.          * 建構函式 
  190.          * 作者:zhouyh 
  191.          * @param cap 
  192.          * @param seed 
  193.          */
  194.         public SimpleHash(int cap, int seed){  
  195.             this.cap = cap;  
  196.             this.seed = seed;  
  197.         }  
  198.         /** 
  199.          *  
  200.          * 方法名:hash 
  201.          * 作者:zhouyh 
  202.          * 建立時間:2014-8-30 下午01:47:10 
  203.          * 描述:計算hash的函式,使用者可以選擇其他更好的hash函式 
  204.          * @param value 
  205.          * @return 
  206.          */
  207.         publicint hash(String value){  
  208.             int result = 0;  
  209.             int length = value.length();  
  210.             for(int i=0; i<length; i++){  
  211.                 result = seed*result + value.charAt(i);  
  212.             }  
  213.             return (cap-1) & result;  
  214.         }  
  215.     }  
  216. }  
實際使用中,效果還不錯,主要用在了爬蟲(crawler)對網址的判重上