7.4Redis高级数据类型

HyperLogLog
(1)采用一种基数算法,用于完成独立总数的统计。
(2)占据空间小,无论统计多少个数据,只占12k的内存空间。
(3)不精确的统计算法,标准误差为0.81%。
Bitmap
(1)不是一种独立的数据结构,实际上就是字符串。
(2)支持按位存取数据,可以将其看成是byte数组。
(3)适合存储索大量的连续的数据的布尔值。


    // 统计20万个重复数据的独立总数.
    @Test
    public void testHyperLogLog() {
        String redisKey = "test:hll:01";  //HyperLogLog

        //往数据中存10万个不重复的数据
        for (int i = 1; i <= 100000; i++) {
            redisTemplate.opsForHyperLogLog().add(redisKey, i);
        }

        //往数据中存10万个有重复的数据 random->重复
        for (int i = 1; i <= 100000; i++) {
            int r = (int) (Math.random() * 100000 + 1);
            redisTemplate.opsForHyperLogLog().add(redisKey, r);
        }
        //这样就存了20万行数据,有重复的,那么,去重复之后应该是10万个独立的数据
        long size = redisTemplate.opsForHyperLogLog().size(redisKey);
        //统计结果:99553,误差差不多0.8%左右
        System.out.println(size);
    }

    //比如统计一周7天的uv,合并数据
    // 将3组数据合并, 再统计合并后的重复数据的独立总数.
    //多组数据可能有重复的,这个统计的是合并之后的重复数据之中,独立的数据总数
    @Test
    public void testHyperLogLogUnion() {
        String redisKey2 = "test:hll:02";
        //10000条非重复的数据
        for (int i = 1; i <= 10000; i++) {
            redisTemplate.opsForHyperLogLog().add(redisKey2, i);
        }

        String redisKey3 = "test:hll:03";
        //10000条非重复的数据
        for (int i = 5001; i <= 15000; i++) {
            redisTemplate.opsForHyperLogLog().add(redisKey3, i);
        }

        String redisKey4 = "test:hll:04";
        //10000条非重复的数据
        for (int i = 10001; i <= 20000; i++) {
            redisTemplate.opsForHyperLogLog().add(redisKey4, i);
        }

        //那么合并之后,一共有30000条数据,它们之间是有交叉重复的,但是独立的数据(也就是去重后)理论上有20000条
        //合并之后产生新的数据"test:hll:union"
        String unionKey = "test:hll:union";
        redisTemplate.opsForHyperLogLog().union(unionKey, redisKey2, redisKey3, redisKey4);

        long size = redisTemplate.opsForHyperLogLog().size(unionKey);
        //结果19833,误差还行。理论20000条
        System.out.println(size);
    }

    //bitmap:本质上是string,只不过是特殊的操作,按位存
    // 统计一组数据的布尔值
    @Test
    public void testBitMap() {
        String redisKey = "test:bm:01";

        // 记录
        redisTemplate.opsForValue().setBit(redisKey, 1, true);
        redisTemplate.opsForValue().setBit(redisKey, 4, true);
        redisTemplate.opsForValue().setBit(redisKey, 7, true);

        // 查询
        //默认是false
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 0));
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 1));
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 2));

        // 统计
        //执行redis命令,做匿名的实现
        Object obj = redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                //按位统计,会帮我们统计这组byte中true的个数
                return connection.bitCount(redisKey.getBytes());
            }
        });

        //结果:3个,没错!
        System.out.println(obj);
    }

    // 统计3组数据的布尔值, 并对这3组数据做OR(与或非)运算.
    @Test
    public void testBitMapOperation() {
        String redisKey2 = "test:bm:02";
        //其他的位置就默认是false
        redisTemplate.opsForValue().setBit(redisKey2, 0, true);
        redisTemplate.opsForValue().setBit(redisKey2, 1, true);
        redisTemplate.opsForValue().setBit(redisKey2, 2, true);

        String redisKey3 = "test:bm:03";
        redisTemplate.opsForValue().setBit(redisKey3, 2, true);
        redisTemplate.opsForValue().setBit(redisKey3, 3, true);
        redisTemplate.opsForValue().setBit(redisKey3, 4, true);

        String redisKey4 = "test:bm:04";
        redisTemplate.opsForValue().setBit(redisKey4, 4, true);
        redisTemplate.opsForValue().setBit(redisKey4, 5, true);
        redisTemplate.opsForValue().setBit(redisKey4, 6, true);

        
        //做 or 运算
        String redisKey = "test:bm:or";
        //得到结果
        Object obj = redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                //做运算 bitOp:bitOperation
                connection.bitOp(RedisStringCommands.BitOperation.OR,/*运算符*/
                        redisKey.getBytes()/*结果存到这里面*/,
                        /*要运算的数据*/
                        redisKey2.getBytes(), redisKey3.getBytes(), redisKey4.getBytes());
                return connection.bitCount(redisKey.getBytes());
            }
        });

        //做or运算false true -> true
        System.out.println(obj);

        //right
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 0));
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 1));
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 2));
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 3));
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 4));
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 5));
        System.out.println(redisTemplate.opsForValue().getBit(redisKey, 6));
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值