getHandel redis_redis 使用 get 命令读取 bitmap 类型的数据
在签到统计场景中,可以使用 bitmap 数据类型高效的存储签到数据,但 getbit 命令只能获取某一位值,就无法最优的满足部分业务场景了。
比如我们按年去存储一个用户的签到情况,365 天,只需要 365 / 8 ≈ 46 Byte,1KW 用户量一年也只需要 44 MB 就足够了。
setbit sign:uid:year 0 1 #第1天
setbit sign:uid:year 1 1 #第2天
...
setbit sign:uid:year 364 1 #第365天
但如果我想获取某个用户一年的签到统计,使用 bitget 命令的话...要循环读取 365 次,这是没办法接受的。
如果能一次读取到以字符串
"1000100010100100...001"
的形式表示的位状态数据,就很好做后续的处理了。
bitmap 其实也是一种特殊的字符串数据,使用 get 命令是可以读取出来的,但是以 16 进制的流数据返回的,这里就涉及到网络编程中数据传输的打包/解包的知识,redis 使用 get 命令读取 bitmap 数据时,将二进制数据打包成了 16 进制返回给我们,所以我们要对此数据包以 16 进制解包,然后转为二进制字符串。给出转换方法:
<?php
// 第1天的签到
$redis->setBit('sign:uid:year', 0, 1);
// 第234天的签到
$redis->setBit('sign:uid:year', 233, 1);
// 第365天的签到
$redis->setBit('sign:uid:year', 364, 1);
// 使用 get 命令一次性读取用户的 bitmap 签到数据
$bitmap_str = $redis->get("sign:uid:year");
// 对数据流使用网络字节序(大端)解包拿到16进制数据的字符串形式
$hex_str = unpack("H*", $bitmap_str)[1];
// hex str 的长度
$hex_str_len = strlen($hex_str);
// 为了防止 hex to dec 时发生溢出
// 我们需要切分 hex str,使得每一份 hex str to dec 时都能落在 int 类型的范围内
// 因为 2 位 16 进制表示一个字节,所以用系统 int 类型的字节长度去分组是绝对安全的
$chunk_size = PHP_INT_SIZE;
// 对 hex str 做分组对齐,否则 str 的最后几位可能会被当作低位数据处理
// 比如 fffff 以 4 位拆分 'ffff', 'f' 后 最后一组 'f' 就被低位数据处理了
// 对齐后 fffff000 分组 'ffff', 'f000' 就能保证 'f' 的数据位了
$hex_str = str_pad($hex_str, $hex_str_len + ($chunk_size - ($hex_str_len % $chunk_size)), 0, STR_PAD_RIGHT);
// 防止 hexdec 时溢出 使用 PHP_INT_SIZE 个 16 进制字符一组做拆分
// 因 16 进制 2 位标识一个字节 所以 PHP_INT_SIZE 是绝对不会溢出的
$hex_str_arr = str_split($hex_str, $chunk_size);
// 位数据的二进制字符串
$bitmap_bin_str = '';
array_walk($hex_str_arr, function($hex_str_chunk) use (&$bitmap_bin_str, $chunk_size) {
$bitmap_bin_str .= str_pad(decbin(hexdec($hex_str_chunk)), $chunk_size * 4, 0, STR_PAD_LEFT);
});
// 一次读取redis即可拿到 bitmap O(n)次操作的数据
echo $bitmap_bin_str{0} . PHP_EOL; //第1天
echo $bitmap_bin_str{233} . PHP_EOL;//第234天
echo $bitmap_bin_str{364} . PHP_EOL;//第365天
注释较多,业务代码不多,多多理解~
getHandel redis_redis 使用 get 命令读取 bitmap 类型的数据相关推荐
- Apache POI和EasyExcel 第五集:Apache POI的Excel读取不同类型的数据
Apache POI和EasyExcel 第五集:Apache POI的Excel读取不同类型的数据 一.资源 什么是Apache POI Apache POI 不同类型的数据的表格(xls) 链接: ...
- 通过OracleDataReader来读取BLOB类型的数据 (转载)
通过OracleDataReader来读取BLOB类型的数据 在实际的应用过程中,需要把大块的二进制数据存储在数据库中.读取这些大块的数据,可以通过强制类型转换成为byte数组,但是当这个二进制数 ...
- 通过OracleDataReader来读取BLOB类型的数据
在实际的应用过程中,需要把大块的二进制数据存储在数据库中.读取这些大块的数据,可以通过强制类型转换成为byte数组,但是当这个二进制数据体够大时(几十兆或者上百兆),一次并不能获取到他的完整长度,所以 ...
- 问题:从键盘读取特定类型的数据(使用Scanner读取int类型)
import java.util.Scanner; public class ScannerIntTest{public static void main(String [] args){int nu ...
- java读取mdb类型的数据
1.总体说明 现在java读取mdb数据(也就是链接access数据库读取数据)对jdk的版本有要求,jdk1.8以前的可以直接链接access数据 库读取数据,而jdk1.8以后的都需要加载一个连接 ...
- PostgreSQL命令恢复dmp类型的数据备份
1.用管理员身份打开cmd黑窗,并进入到PostgreSQL的bin目录下 2.输入 pg_restore.恢复数据库的命令 pg_restore.exe --host "localhost ...
- waterdrop(1.5.1版本)增加bitmap类型导数的遇到的问题
1. 背景 背景是想通过最新的 jbdc 来使waterdrop 可以导入bitmap 类型的数据 2. 实施方法 a. 配置文件 adm_dmp_clickhouse_jdbc.conf spark ...
- pandas读取nlp_chinese_corpus里面的json类型的数据,一行一个字典的数据
最近在用pandas来读取json类型的数据,发现网上资料居然没查到,我这里弥补一下空缺,读取的json数据示例为: {"qid": "qid_1815059893214 ...
- Gdiplus byte *数据转换为Bitmap类型图片
最近在mfc上显示缩略图那样显示采集到的图片,这个用CimageList和CListctrl就可以了,网上有很多这里不细说,但是别忘了初始化Gdiplus: 但是我的相机采集到的就是byte类型的数据 ...
最新文章
- 论工程结构设计的重要性
- 7-19晚牛客网刷题未知点、错题 集合
- PIL应用之生成验证码图片
- 将文件内含有的特殊字符还原
- 【树莓派】树莓派(Debian)- root用户无法使用SSH登录
- jni直接转byte_JNI jbyteArray转char*
- 我们来判断一个php函数是否被定义
- php连接数据库(一)
- AppScan安装教程
- 数据结构期末考试试题及答案
- 求职软件测试工程师英文简历,软件测试工程师英文简历范文
- 2021 ICCV TIMI-Net 抠图网络论文笔记
- MySQL数据库实验(六):创建学生信息管理系统
- 网站点击流数据分析项目
- 2011年11月编程语言排行榜:Objective-C有望成为2011年年度编程语言。
- Linux笔记(更新中)
- progisp下载时报错Chip Enable Program Error 后续解决
- vue集成svg-sprite-loader
- 数据结构与算法——左程云09
- 换种思路解释自我管理
热门文章
- 解决Android 音频Xrun问题
- JAVA基础之n+=1与n=n+1的区别
- Ubuntu18.04安装BeyondCompare
- Android反射set/get系统属性(SystemProperties)
- mysql之获取自增长的ID
- Ubuntu20.04如何卸载软件
- ios 怎么判断字符串的字节数_如何用IOS判断字符串是不是纯数字
- c 连接mysql数据库_C++连接mysql数据库的两种方法
- vue3.0项目创建
- 码云克隆项目到IntelliJ IDEA中