当前位置: 首页 > article >正文

【布隆过滤器】

简介

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

bitmap 实现布隆过滤器

在这里插入图片描述
在这里插入图片描述

@Api(tags = "客户Customer接口+布隆过滤器讲解")
@RestController
@Slf4j
public class CustomerController
{
    @Resource private CustomerSerivce customerSerivce;

    @ApiOperation("数据库初始化2条Customer记录插入")
    @RequestMapping(value = "/customer/add",method = RequestMethod.POST)
    public void addCustomer()
    {
        for (int i = 0; i < 2; i++) {
            Customer customer = new Customer();

            customer.setCname("customer"+i);
            customer.setAge(new Random().nextInt(30)+1);
            customer.setPhone("1381111XXXX");
            customer.setSex((byte) new Random().nextInt(2));
            customer.setBirth(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()));

            customerSerivce.addCustomer(customer);
        }
    }


    @ApiOperation("单个customer查询操作,按照customerid查询")
    @RequestMapping(value = "/customer/{id}",method = RequestMethod.GET)
    public Customer findCustomerById(@PathVariable Integer id)
    {
        return customerSerivce.findCustomerById(id);
    }

    @ApiOperation("BloomFilter,按照customerid查询")
    @RequestMapping(value = "/customerbloomfilter/{id}",method = RequestMethod.GET)
    public Customer findCustomerByIdWithBloomFilter(@PathVariable int id)
    {
        return customerSerivce.findCustomerByIdWithBloomFilter(id);
    }
}
@Service
@Slf4j
public class CustomerSerivce {
    public static final String CACHA_KEY_CUSTOMER = "customer:";

    @Resource
    private CustomerMapper customerMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private CheckUtils checkUtils;

    /**
     * 写操作
     *
     * @param customer
     */
    public void addCustomer(Customer customer) {
        int i = customerMapper.insertSelective(customer);

        if (i > 0) {
            //mysql插入成功,需要重新查询一次将数据捞出来,写进redis
            Customer result = customerMapper.selectByPrimaryKey(customer.getId());
            //redis缓存key
            String key = CACHA_KEY_CUSTOMER + customer.getId();
            //捞出来的数据写进redis
            redisTemplate.opsForValue().set(key, result);
        }
    }

    public Customer findCustomerById(Integer customreId) {
        Customer customer = null;
        //缓存redis的key名称
        String key = CACHA_KEY_CUSTOMER + customreId;
        //1 先去redis查询
        customer = (Customer) redisTemplate.opsForValue().get(key);

        //2 redis有直接返回,没有再进去查询mysql
        if (customer == null) {
            // 3 再去查询我们的mysql
            customer = customerMapper.selectByPrimaryKey(customreId);
            // 3.1 mysql有,redis无
            if (customer != null) {
                //3.2 把mysq查询出来的数据回写redis,保持一致性
                redisTemplate.opsForValue().set(key, customer);
            }
        }
        return customer;
    }

    /**
     * BloomFilter → redis → mysql
     * 白名单:whitelistCustomer
     *
     * @param customerId
     * @return
     */
    public Customer findCustomerByIdWithBloomFilter(Integer customerId) {
        Customer customer = null;
        //缓存key的名称
        String key = CACHA_KEY_CUSTOMER + customerId;

        //布隆过滤器check,无是绝对无,有是可能有
        //===============================================
        if (!checkUtils.checkWithBloomFilter("whitelistCustomer", key)) {
            log.info("白名单无此顾客,不可以访问: " + key);
            return null;
        }
        //===============================================

        //1 查询redis
        customer = (Customer) redisTemplate.opsForValue().get(key);
        //redis无,进一步查询mysql
        if (customer == null) {
            //2 从mysql查出来customer
            customer = customerMapper.selectByPrimaryKey(customerId);
            // mysql有,redis无
            if (customer != null) {
                //3 把mysql捞到的数据写入redis,方便下次查询能redis命中。
                redisTemplate.opsForValue().set(key, customer);
            }
        }
        return customer;
    }

}
@Component
@Slf4j
public class CheckUtils {
    @Resource
    private RedisTemplate redisTemplate;

    public boolean checkWithBloomFilter(String checkItem, String key) {
        int hashValue = Math.abs(key.hashCode());
        long index = (long) (hashValue % Math.pow(2, 32));
        boolean existOK = redisTemplate.opsForValue().getBit(checkItem, index);
        log.info("--->key:" + key + " 对应坑位下标index: " + index + " 是否存在:" + existOK);

        return existOK;
    }
}
/**
 * 布隆过滤器白名单初始化工具类,一开始就设置一部分数据为白名单所有,
 * 白名单业务默认规定:布隆过滤器有,redis是极大可能有。
 * 白名单:whitelistCustomer
 */
@Component
@Slf4j
public class BloomFilterInit
{
    @Resource
    private RedisTemplate redisTemplate;

    @PostConstruct//初始化白名单数据,暂时注释省的后台打印
    public void init()
    {
        //1 白名单客户加载到布隆过滤器
        String key = "customer:12";
        //2 计算hashValue,由于存在计算出来负数的可能,我们取绝对值
        int hashValue = Math.abs(key.hashCode());
        //3 通过hashValue和2的32次方后取余,获得对应的下标坑位
        long index = (long)(hashValue % Math.pow(2,32));
        log.info(key+" 对应的坑位index:{}",index);
        //4 设置redis里面的bitmap对应类型白名单:whitelistCustomer的坑位,将该值设置为1
        redisTemplate.opsForValue().setBit("whitelistCustomer",index,true);

    }
}

在这里插入图片描述

google布隆过滤器

    <!--guava Google 开源的 Guava 中自带的布隆过滤器-->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>
public class GuavaBloomFilterService {
    //1 定义一个常量
    public static final int _1W = 10000;
    //2 定义我们guava布隆过滤器,初始容量
    public static final int SIZE = 100 * _1W;
    //3 误判率,它越小误判的个数也就越少(思考,是否可以是无限小??没有误判岂不是更好)
    public static double fpp = 0.01;//0.01 0.000000000000001
    //4 创建guava布隆过滤器
    private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), SIZE, fpp);


    public void guavaBloomFilter() {
        //1 先让bloomFilter加入100W白名单数据
        for (int i = 1; i <= SIZE; i++) {
            bloomFilter.put(i);
        }
        //2 故意取10W个不在合法范围内的数据,来进行误判率的演示
        ArrayList<Integer> list = new ArrayList<>(10 * _1W);

        //3 验证
        for (int i = SIZE + 1; i <= SIZE + (10 * _1W); i++) {
            if (bloomFilter.mightContain(i)) {
                log.info("被误判了:{}", i);
                list.add(i);
            }
        }
        log.info("误判总数量:{}", list.size());
    }
}

http://www.kler.cn/news/354232.html

相关文章:

  • 在生产制造领域,可视化大屏的作用可以说无可替代。
  • 用Java爬虫API,轻松获取taobao商品SKU信息
  • C++_Stack和Queue的使用及其模拟实现
  • vue-vben-admin 首页加载慢优化 升级vite2到vite3
  • Qt-系统处理鼠标相关事件(57)
  • 阿里巴巴系列数据库
  • Halcon 使用二维像素分类对图像进行分割
  • Linux期末考试简答题题库
  • Ajax:原生ajax、使用FormData的细节问题,数据的载体
  • C#Process进程的使用,以及对ProcessInfo中所有的参数详细记录
  • java中,深克隆和浅克隆怎么用,有什么应用场景?-----面试题分享
  • 对比长安链、FISCO BCOS、蚂蚁链
  • [实时计算flink]作业开发上线流程及规范
  • LabVIEW离心泵振动监控与诊断系统
  • 数字后端零基础入门系列 | Innovus零基础LAB学习Day2
  • 【数据分析】数据分析的流程是怎么样的?
  • R3:LSTM-火灾温度预测
  • python 爬虫 入门 二、数据解析(正则、bs4、xpath)
  • redis--Mysql和redis数据一致性问题(延时双删)
  • OpenAI的新功能Canvas,效果还不错