目录java
1、概述git
2、详解github
3、实现redis
4、适用业务场景算法
简单讲布隆过滤器就是判断一个列表中是否存在某个元素。通常在JAVA判断是否存在,咱们能够Map,Set等容器。可是当数据量特别大的时候,用Map和Set会占用过多的内存。这个时候就会考虑用布隆过滤器了。数组
要建立一个布隆过滤器首选须要在内存中声明一个Bit数组,假设数组的长度为L,初始值所有为0。缓存
当put一个key到布隆过滤器的时候,会对key进行N次hash,而后对hash值 % L 取模,获得N个位置下标。而后将Bit数组中对应位置的值所有设置为1。其中的L和N取决于key的预估总数和错误率,由于bloomfilter不能保证100%的准确,这个后面会说。数据结构
当判断一个key是否存在的时候也是对key进行N次hash取模,若是全部bit数组中全部位置的值都为1,则认为这个key有可能存在,注意这里说是有可能。测试
过程以下图:(这里假设L为10, N为3)this
假设:
"zhangsan":3次hash取模的结果为:0,2,4。
"lisi":3次hash取模的结果为:4,6,8。
"wangwu":3次hash取模的结果为:2,4,6。
若是已经存在"zhangsan"和"lisi"这俩个key,那么即便"wangwu"这个key实际不存在,可是算法返回的结果是存在,由于2,4,6这个三个位置已经被“zhangsan”和“lisi”占用了。
综上所述发现bloomfiter有一些特色:
那么怎么提高算法的准确度呢?
package com.ikuboo.bloomfilter; import java.util.BitSet; /** * 布隆过滤器 */ public class MyBloomFilter { private int length; /** * bitset */ private BitSet bitSet; public MyBloomFilter(int length) { this.length = length; this.bitSet = new BitSet(length); } /** * 写入数据 */ public void put(String key) { int first = hashcode_1(key); int second = hashcode_2(key); int third = hashcode_3(key); bitSet.set(first % length); bitSet.set(second % length); bitSet.set(third % length); } /** * 判断数据是否存在 * * @param key * @return true:存在,false:不存在 */ public boolean exist(String key) { int first = hashcode_1(key); int second = hashcode_2(key); int third = hashcode_3(key); boolean firstIndex = bitSet.get(first % length); if (!firstIndex) { return false; } boolean secondIndex = bitSet.get(second % length); if (!secondIndex) { return false; } boolean thirdIndex = bitSet.get(third % length); if (!thirdIndex) { return false; } return true; } /** * hash 算法1 */ private int hashcode_1(String key) { int hash = 0; int i; for (i = 0; i < key.length(); ++i) { hash = 33 * hash + key.charAt(i); } return Math.abs(hash); } /** * hash 算法2 */ private int hashcode_2(String data) { final int p = 16777619; int hash = (int) 2166136261L; for (int i = 0; i < data.length(); i++) { hash = (hash ^ data.charAt(i)) * p; } hash += hash << 13; hash ^= hash >> 7; hash += hash << 3; hash ^= hash >> 17; hash += hash << 5; return Math.abs(hash); } /** * hash 算法3 */ private int hashcode_3(String key) { int hash, i; for (hash = 0, i = 0; i < key.length(); ++i) { hash += key.charAt(i); hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return Math.abs(hash); } }
测试代码
public class TestMyBloomFilter { public static void main(String[] args) { int capacity = 10000000; MyBloomFilter bloomFilters = new MyBloomFilter(capacity); bloomFilters.put("key1"); System.out.println("key1是否存在:" + bloomFilters.exist("key1")); System.out.println("key2是否存在:" + bloomFilters.exist("key2")); } }
import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import java.nio.charset.Charset; public class TestGuavaBloomFilter { public static void main(String[] args) { //预估的容量 int capacity = 10000000; //指望的错误率 double fpp = 0.01; BloomFilter<String> bloomFilters = BloomFilter.create( Funnels.stringFunnel(Charset.forName("UTF-8")), capacity, fpp); bloomFilters.put("key1"); System.out.println("key1是否存在:" + bloomFilters.mightContain("key1")); System.out.println("key2是否存在:" + bloomFilters.mightContain("key2")); } }