前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >redis的bitset实战

redis的bitset实战

作者头像
code4it
发布2018-09-17 17:29:14
发布2018-09-17 17:29:14
2K00
代码可运行
举报
文章被收录于专栏:码匠的流水账码匠的流水账
运行总次数:0
代码可运行

本文主要研究一下redis的bitset数据结构的用场

相关命令

SETBIT

时间复杂度为O(1)

代码语言:javascript
代码运行次数:0
复制
setbit login.20180906 102400000 0
setbit login.20180905 201400000 1

GETBIT

时间复杂度为O(1)

代码语言:javascript
代码运行次数:0
复制
getbit login.20180905 201400000

BITOP

时间复杂度为O(N)

代码语言:javascript
代码运行次数:0
复制
bitop or login.9m.week1or login.20180905 login.20180906
getbit login.9m.week1or 201400000

主要做bitset的and、or、xor、not操作,结果存在新的bitset中,注意时间复杂度为O(N)

BITPOS

时间复杂度为O(N)

代码语言:javascript
代码运行次数:0
复制
bitpos login.20180905 1

返回指定bitset中在指定起始位置中第一个出现指定值的offset,不传start,end默认估计是0,-1

BITCOUNT

时间复杂度为O(N)

代码语言:javascript
代码运行次数:0
复制
bitcount login.20180905

统计bitset中出现1的个数

使用场景

假设有个签到的需求,要实现的功能如下:

  • 展示当天是否已经签到,签到了不能再签到了
  • 展示最近一周的或者最近一个月的签到情况/历史(可以只不详细记录到每天的签到时间,只记录每天是否签到)
  • 判断是否连续签到,若本周连续签到,则给予抽奖机会

这里我们就可以使用redis的bitset来实现:

签到

代码语言:javascript
代码运行次数:0
复制
boolean originValue = redisTemplate.opsForValue().setBit(uidYearKey,dayIndx,true);
  • 这里的key由uid,year构成,然后offset采用day的index
  • 每个uid每个year一个key的话,如果用户数过多可能造成redis的key太多

获取签到数据

代码语言:javascript
代码运行次数:0
复制
    BitSet bitSet = fromByteArrayReverse(redisTemplate.opsForValue().get(uidYearKey).getBytes());
    public static BitSet fromByteArrayReverse(final byte[] bytes) {
        final BitSet bits = new BitSet();
        for (int i = 0; i < bytes.length * 8; i++) {
            if ((bytes[i / 8] & (1 << (7 - (i % 8)))) != 0) {
                bits.set(i);
            }
        }
        return bits;
    }
  • 这里有个注意事项,java读取bytes从小到大是从右往左读(大端),而redis存储的bytes从小到大是从左往右(小端),因而这里读取bytes转为BitSet需要逆向一下

BitSet Range

代码语言:javascript
代码运行次数:0
复制
public BitSet get(int fromIndex, int toIndex) {
    //......
}
  • BitSet有个方法,可以根据index来进行range,之后就可以用新的BitSet进行相关统计,比如BitSet的cardinality

小结

  • 对于bitset来说,其优点就是节省内存,如果直接把用户id作为offset来存储相应的值,这个相比hash来说,节省了很多空间。类似统计最近N天连续登陆的人的个数这类场景就可以使用bitset来实现。
  • 对于bitset的操作要注意,各个操作的时间复杂度,如果是getbit、setbit则都是O(1),bitop、bitcount、bitpos等都是O(N),在N比较大的时候要注意,可能是潜在的慢查询

doc

  • setbit
  • getbit
  • bitop
  • bitpos
  • bitcount
  • Efficient analytics with Redis bitmaps
  • Be Careful With your Redis BitSets and Java
  • REDIS BITMAPS – FAST, EASY, REALTIME METRICS
  • Bitmaps vs. Sets to track Monthly Active Users in Redis
  • storing-hundreds-of-millions-of-simple-keys-in-282-mb-with-redis
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 相关命令
    • SETBIT
    • GETBIT
    • BITOP
    • BITPOS
    • BITCOUNT
  • 使用场景
    • 签到
    • 获取签到数据
    • BitSet Range
  • 小结
  • doc
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档