美文网首页
节衣缩食 —— 位图

节衣缩食 —— 位图

作者: DreamsonMa | 来源:发表于2019-03-21 20:29 被阅读0次

在我们平时开发过程中,会有一些 bool 型数据需要存取,比如用户一年的签到记录,签了是 1,没签是 0,要记录 365 天。如果使用普通的 key/value,每个用户要记录 365 个,当用户上亿的时候,需要的存储空间是惊人的。

为了解决这个问题,Redis 提供了位图数据结构,这样每天的签到记录只占据一个位,365 天就是 365 个位,46 个字节 (一个稍长一点的字符串) 就可以完全容纳下,这就大大节约了存储空间。

位图数据结构

Redis 的位数组是自动扩展,如果设置了某个偏移位置超出了现有的内容范围,就会自动将位数组进行零扩充。

Bit实例

下面实现一个签到的例子:
考虑到每月初需要重置连续签到次数,最简单的方式是按用户每月存一条签到数据(也可以每年存一条数据)。Key的格式为u:sign:uid:yyyyMM,Value则采用长度为4个字节(32位)的位图(最大月份只有31天)。位图的每一位代表一天的签到,1表示已签,0表示未签。例如u:sign:1000:201902表示ID=1000的用户在2019年2月的签到记录。

        DateTime y2 = DateUtil.parse("2019-02-01");
        String key = buildSignKey(1000, y2.toJdkDate());

        // 偏移量是从0开始,所以要把17减1
        jedis.setbit(key, 16, true); // 用户2月17号签到
        jedis.setbit(key, 27, true); // 用户2月28号签到
        Assert.assertTrue(jedis.getbit(key, 16)); // 检查2月17号是否签到
        Assert.assertEquals(2,jedis.bitcount(key).longValue()); // 统计2月份的签到次数
        // u8,一个8位的无符号整数,i16是一个16位的有符号整数
        List<Long> list = jedis.bitfield(key, "GET", "u28", "0");// 获取2月份前28天的签到数据
        Map<String, Boolean> signMap = new HashMap(DateUtil.dayOfMonth(y2.toJdkDate()));
        if (list != null && list.size() > 0) {
            // 由低位到高位,为0表示未签,为1表示已签
            long v = list.get(0) == null ? 0 : list.get(0);
            for (int i = 28; i > 0; i--) {
                final DateTime dateTime = DateUtil.offsetDay(y2.toJdkDate(), i-1);
                signMap.put(DateUtil.format(dateTime, "yyyy-MM-dd"), v >> 1 << 1 != v);
                v >>= 1;
            }
        }
        Console.log(JSONUtil.toJsonPrettyStr(signMap));
        Assert.assertEquals(16, jedis.bitpos(key, true).longValue()); // 获取当月首次签到日期

打印信息如下:

{
    "2019-02-09": false,
    "2019-02-08": false,
    "2019-02-07": false,
    "2019-02-28": true,
    "2019-02-06": false,
    "2019-02-27": false,
    "2019-02-05": false,
    "2019-02-26": false,
    "2019-02-04": false,
    "2019-02-25": false,
    "2019-02-03": false,
    "2019-02-24": false,
    "2019-02-02": false,
    "2019-02-23": false,
    "2019-02-01": false,
    "2019-02-22": false,
    "2019-02-21": false,
    "2019-02-20": false,
    "2019-02-19": false,
    "2019-02-18": false,
    "2019-02-17": true,
    "2019-02-16": false,
    "2019-02-15": false,
    "2019-02-14": false,
    "2019-02-13": false,
    "2019-02-12": false,
    "2019-02-11": false,
    "2019-02-10": false
}

本文基于《Redis深度历险:核心原理和应用实践》一文的JAVA实践。更多文章请参考:高性能缓存中间件Redis应用实战(JAVA)

相关文章

  • 节衣缩食 —— 位图

    在我们平时开发过程中,会有一些 bool 型数据需要存取,比如用户一年的签到记录,签了是 1,没签是 0,要记录 ...

  • redis003--节衣缩食(位图)

    在我们平时开发过程中,会有一些 bool 型数据需要存取,比如用户一年的签到记录,签了是 1,没签是 0,要记录 ...

  • 节衣缩食

    食:公司包吃三餐,一天三餐在公司解决后才回家。关键公司的伙食也很好,偶尔还有水果,每天都吃得饱饱的。每天回到家都7...

  • 节衣缩食

    从贫穷年代走过来的人,似乎挺享受这“节衣缩食”四个字所涵盖的无穷力量。 年少时为了生存不得已节衣缩食;如今生活丰衣...

  • 节衣缩食,消费膨胀

    节衣缩食,我有一个朋友从小因为家里条件不太好,从小就懂得节省,一直到长大工作之后对自己都很"抠",衣服鞋子都不舍得...

  • 生活有感-节衣缩食

    节衣缩食的日子来了。这几天,跑了三次浏阳,因为几个同事都开始搞装修,所以张也终于闲不住了。 看了几家全屋定制,跑了...

  • 节衣缩食攒学费

    今天真是……双十一的信用卡账单下来了,各种辅导班又要续费,感觉被这点钱压的透不过气来。其实,真正想不开的原因哪是钱...

  • 从此吃糠咽菜、节衣缩食

    一中要搬至新城区了,小儿过两年也要去上学了,老城区的房子相距甚远,儿子每天骑车上学风里来雨里去,还要上晚自习,着实...

  • 节衣缩食过日子!

    钱不好挣了。口罩事件以来,经济环境是越来越差。可能与个人能力有关,因为水平不行所以就愈发觉得生活之艰难。 为了...

  • 两个位图覆盖合成为一个位图

    /** *把两个位图覆盖合成为一个位图,以底层位图的长宽为基准 *@parambackBitmap在底部的位图 *...

网友评论

      本文标题:节衣缩食 —— 位图

      本文链接:https://www.haomeiwen.com/subject/mqmcvqtx.html