redis布隆过滤器的使用

1.使用场景:推荐系统给用户推荐新闻,避免重复推送。

需要考虑问题:从用户观看历史中筛选出没有看过的新闻进行推送,就需要数据库中频繁的使用exists进行查询,但是当用户量很大时,数据库很难顶住压力。

解决方法:

1.1.使用缓存?但是日子长了,会浪费很大空间,不是长久之计,不是很好的解决办法。

1.2.这时布隆过滤器就可以很好的解决这个需求了,可以节约90%以上的空间,缺点就是稍微有那么一点不准确,存在一定的误判率,但是对于这个新闻推送的可以忽略。

2.什么布隆过滤器

2.1其实布隆过滤器可以看成是一个不是很准确的set结构,只是在使用它的contains方法判断某个对象是否存在时会出现误判。但是它也不是特别的不精准,只要参数设置合理,那么它的精确度可以控制的足够精准,只会有小小的误判。

2.2当布隆过滤器说某个值存在时,那可能就不存在,如果说某个值不存在时,那肯定就是不存在了。

打个比方,当一个人说认识你时可能不认识你,当一个人说不认识你时那肯定就不认识了。当它说见过你时,可能根本没有见过面,只不过可能你的脸和它所认识人中某个人的脸相似度比较高,所以产生误判。

2.3对于上面的场景,当用户看过的新闻,肯定会被过滤掉,对于没有看多的新闻,可能会过滤极少的一部分(误判),但是绝大部分都可以准确识别。这样可以完全保证推送给用户的新闻都是无重复的。

3.centos安装redis的bloomfilter插件

https://blog.csdn.net/u013030276/article/details/88350641

4.bloomfilter使用

4.1 bf.add

语法:[bf.add  key  options]

127.0.0.1:6379> bf.add users user3

(integer) 1

4.2 bf.exists

语法:[bf.exists  key  options]

127.0.0.1:6379> bf.exists users user1

(integer) 1

127.0.0.1:6379> bf.exists users user3

(integer) 0

4.3 bf.madd

语法:[bf.add  key  ...options]

127.0.0.1:6379> bf.madd users user4 user5 user6 user7

1) (integer) 1

2) (integer) 1

3) (integer) 1

4) (integer) 1

4.4 bf.mexists

语法:[bf.add  key  ...options]

127.0.0.1:6379> bf.mexists users user4 user5 user6 user7 user8

1) (integer) 1

2) (integer) 1

3) (integer) 1

4) (integer) 1

5) (integer) 0

4.5 bf.reserve创建Filter

语法:[bf.reserve  key  error_rate initial_size]

127.0.0.1:6379> bf.reserve books 0.001 10000

OK

5.代码实现

5.1引入依赖

jedis3.0没有rebloom的相关方法,只能通过引入rebloom.jar。

https://github.com/RedisLabs/JReBloom

pom.xml引入:

<dependencies>
   <dependency>
      <groupId>com.redislabs</groupId>
      <artifactId>jrebloom</artifactId>
      <version>1.0.1</version>
   </dependency>
</dependencies>

5.2对自己见过的元素判断是否不存在

@Test
public void test3() {
    setJedisPool();
    Client client = new Client(jedisPool);
    jedisPool.getResource().del("book");
    for (int i = 0; i < 10000; i++) {
        String book = "book" + i;
        client.add("book", book);
        boolean ret = client.exists("book", book); // 判断自己见过的,没有出现误判
        if (!ret) {
            System.out.println(i);
        }
    }
    jedisPool.close();
}

5.3使用默认Filter参数(),对自己没有见过的,判断是否存在

@Test
public void test4() {
    setJedisPool();
    Client client = new Client(jedisPool);
    int count = 0;
    jedisPool.getResource().del("book");
    for (int i = 0; i < 10000; i++) {
        String book = "book" + i;
        boolean ret = client.exists("book", book); // 判断自己没见过的,误判数153个,15.3%
        if (ret) {
            count++;
            System.out.println(i + "误判数:" + count);
        }
        client.add("book", book);
    }
    jedisPool.close();
}

10000个元素,判断自己没见过的,误判数153个,1.53%

对于超过1.5%的误判率怎么办呢?

默认的Filter的initial_size=100,error_rate=0.1;

5.4创建Filter(initial_size,error_rate),对自己没有见过的,判断是否存在

@Test
public void test5() {
    setJedisPool();
    Client client = new Client(jedisPool);
    int count = 0;
    jedisPool.getResource().del("book");
    client.createFilter("book", 9000, 0.001);
    for (int i = 0; i < 10000; i++) {
        String book = "book" + i;
        boolean ret = client.exists("book", book); // 判断自己没见过的,10000,0.001误判数0个;9000,0.001误判1个;
        if (ret) {
            count++;
        }
        System.out.println(book + "--" + ret + "--误判数:" + count);
        client.add("book", book);
    }
    jedisPool.close();
}

设置预计放入的元素个数=10000,错误率=0.001误判数0个;

设置预计放入的元素个数=9000,错误率=0.001误判1个;

注意事项:

布隆过滤器的initial_size估计的过大,所需要的空间就越大,会浪费空间,估计的过小会影响准确率,因此在使用前一定要估算好元素数量,还需要加上一定的冗余空间以避免实际元素高出预估数量造成误差过大。

布隆过滤器的error_rate越小,所需要的空间就会越大,对于不需要过于准确的,error_rate设置的稍大一点也无所谓。

6.布隆过滤器原理

每个布隆过滤器对应到 Redis 的数据结构里面就是一个大型的位数组和几个不一样的无偏 hash 函数。所谓无偏就是能够把元素的 hash 值算得比较均匀。

向布隆过滤器中添加 key 时,会使用多个 hash 函数对 key 进行 hash 算得一个整数索引值然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就完成了 add 操作。

向布隆过滤器询问 key 是否存在时,跟 add 一样,也会把 hash 的几个位置都算出来,看看位数组中这几个位置是否都为 1,只要有一个位为 0,那么说明布隆过滤器中这个 key 不存在。如果都是 1,这并不能说明这个 key 就一定存在,只是极有可能存在,因为这些位被置为 1 可能是因为其它的 key 存在所致。如果这个位数组比较稀疏,判断正确的概率就会很大,如果这个位数组比较拥挤,判断正确的概率就会降低。

7.空间计算

 布隆计算器

展开阅读全文

Git 实用技巧

11-24
这几年越来越多的开发团队使用了Git,掌握Git的使用已经越来越重要,已经是一个开发者必备的一项技能;但很多人在刚开始学习Git的时候会遇到很多疑问,比如之前使用过SVN的开发者想不通Git提交代码为什么需要先commit然后再去push,而不是一条命令一次性搞定; 更多的开发者对Git已经入门,不过在遇到一些代码冲突、需要恢复Git代码时候就不知所措,这个时候哪些对 Git掌握得比较好的少数人,就像团队中的神一样,在队友遇到 Git 相关的问题的时候用各种流利的操作来帮助队友于水火。 我去年刚加入新团队,发现一些同事对Git的常规操作没太大问题,但对Git的理解还是比较生疏,比如说分支和分支之间的关联关系、合并代码时候的冲突解决、提交代码前未拉取新代码导致冲突问题的处理等,我在协助处理这些问题的时候也记录各种问题的解决办法,希望整理后通过教程帮助到更多对Git操作进阶的开发者。 本期教程学习方法分为“掌握基础——稳步进阶——熟悉协作”三个层次。从掌握基础的 Git的推送和拉取开始,以案例进行演示,分析每一个步骤的操作方式和原理,从理解Git 工具的操作到学会代码存储结构、演示不同场景下Git遇到问题的不同处理方案。循序渐进让同学们掌握Git工具在团队协作中的整体协作流程。 在教程中会通过大量案例进行分析,案例会模拟在工作中遇到的问题,从最基础的代码提交和拉取、代码冲突解决、代码仓库的数据维护、Git服务端搭建等。为了让同学们容易理解,对Git简单易懂,文章中详细记录了详细的操作步骤,提供大量演示截图和解析。在教程的最后部分,会从提升团队整体效率的角度对Git工具进行讲解,包括规范操作、Gitlab的搭建、钩子事件的应用等。 为了让同学们可以利用碎片化时间来灵活学习,在教程文章中大程度降低了上下文的依赖,让大家可以在工作之余进行学习与实战,并同时掌握里面涉及的Git不常见操作的相关知识,理解Git工具在工作遇到的问题解决思路和方法,相信一定会对大家的前端技能进阶大有帮助。
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值