基於redis 實現布隆過濾器
阿新 • • 發佈:2018-11-10
簡介
Redis中有一個數據結構叫做Bitmap(下方有官網詳解),它提供一個最大長度為512MB(2^32)的位陣列。我們可以把它提供給布隆過濾器做位陣列。
根據《數學之美》中給出的資料,在使用8個雜湊函式的情況下,512MB大小的位陣列在誤報率萬分之五的情況下可以對約兩億的url去重。而若單純的使用set()去重的話,以一個url64個位元組記,兩億url約需要128GB的記憶體空間,不敢想象。
我使用的策略是使用雜湊函式算出的雜湊值對2^32取模,填入bitmap中。
本文主要是介紹這種思想和用法,具體業務使用過程中,需要具體實現,下面貼出程式碼 演示最簡單的一種使用方法:
/* * 模擬專案啟動時候 從"資料庫"或者其他地方獲取到的過濾器集合的資料 */ static List<String> l = new ArrayList<String>(); // 模擬生成的訂單號/使用者/商品ID static { l.add("201810120001"); l.add("201810120002"); l.add("201810120003"); l.add("201810120004"); } /** * 單機版測試 */ @Test public void TestRedis() { Jedis jedis = new Jedis("192.168.1.118", 6379); // 獲取redis支援的最大長度作為取模的基數 double size = Math.pow(2, 32); // 迴圈l 取出裡面的資料,放入到redis中 l.forEach(orderId -> { long index = Math.abs((long) (orderId.hashCode() % size)); jedis.setbit("orderId", index, true); }); // 判斷指定值是否在過濾器裡面 String orderId = l.get(0); //String orderId = "201810120005"; long index = Math.abs((long) (orderId.hashCode() % size)); boolean contain = jedis.getbit("orderId", index); // 為true 說明在裡面 if (contain) { System.out.println("包含這個值."); // 否則不在 } else { System.out.println("不包含這個值."); } jedis.close(); }
執行結果 orderId如果在l集合裡面 就顯示包含,否則就不包含