Redis和PHP的Bitmap于二进制串的相互转换

Redis和PHP的Bitmap于二进制串的相互转换

场景

错题集的存储,需要有正确的题号id集合,错误的题号id集合,两者并集后在全量题的集合中取反就是未答题号id

选型

基于场景的数据结构设计,有试过列表等,测试结果:bitmap要比列表方式节省10倍的空间使用;列表可以FIND_IN_SET查询,但是bitmap必须整存整取后,在应用端计算。各有优缺点,最后还是选择bitmap节省空间。

原理

将id对应二进制串的位数进行存储,有该id,就将位数的值设置为1,反之为0

操作系统中的位运算,64位的,最大仅支持 0 ~63 之间的位移,但是id没有长度限制。
需要定义一个区间长度,进行拼接。如区间长度:8,id:101的存储位置,即:第 ceil(101/8) 区间的第 101%8 位,这里首位永远是 0,id从正整数开始。

实现

PHP中有实现无限整数的位运算扩展:GMP,对于平常的id使用够用了,但是超大量(id位数上千万甚至亿)的运算会比较耗内存。解决方案也是按照区域划分块,参考:PHP实现Bitmap的探索 - GMP扩展使用


class common_BitMap 
{// bit映射基数:二进制const BIT_BASE = 2;private static $cacheObj;static function inst(): self{return self::$cacheObj = self::$cacheObj ?? new self();}/*** setBit** @param int|string $num* @param int $bit* @param bool $bitVal* @return string*/public static function setBit($num, int $bit, bool $bitVal = true):string{$gmp = gmp_init($num, self::BIT_BASE);gmp_setbit($gmp, $bit, $bitVal); // index starts at 0$res = gmp_strval($gmp, self::BIT_BASE);return $res;}/*** setBits** @param array $ids* @return string*/public static function setBits(array $ids = []): string{if (empty($ids)) {return '';}$max = '1'.str_repeat(0, max($ids));$maxGmp = gmp_init($max, self::BIT_BASE);sort($ids);foreach ($ids as $id) {gmp_setbit($maxGmp, $id);}$res = gmp_strval($maxGmp, self::BIT_BASE);return $res;}/*** getArrByBitStr (这里按照字符串处理)** @param string $bitStr* @return array*/public static function getArrByBitStr(string $bitStr):array{if (empty($bitStr)) {return [];}$collect = [];$len = strlen($bitStr);$str = strrev($bitStr);for ($i = 1; $i <= $len; $i ++) {if (intval($str{$i}) == 1) {$collect[] = $i;}}return $collect;}}$num = '10010001';
$str = common_BitMap::setBit($num, 3, 1);
var_dump($str);
// string(8) "10011001"$arr = [1, 12, 23];
$str = common_BitMap::setBits($arr);
var_dump($str);
// string(24) "100000000001000000000010"$decArr = common_BitMap::getArrByBitStr($str);
var_dump($decArr);
/* 
array(3) {[0]=>int(1)[1]=>int(12)[2]=>int(23)
}
*/

由于大多数都要应用缓存,所以需要存储上兼容redis的bitmap操作,先实现id数组转换

/*** redisSetBit** @param string $key* @return string*/public static function getRedisBitStrByKey(string $key = ''){if (empty($key)) {return '';}$str = of_accy_cache_redis::inst()->get($key);  // 此处基于redis的封装类$res = '';for ($i = 0; $i < strlen($str); $i++) {// 获取每个字节的二进制表示,并去掉前缀 '0b'$byteBinary = str_pad(decbin(ord($str[$i])), 8, '0', STR_PAD_LEFT);$res .= $byteBinary;}return $res;}/*** redisSetBits** @param string $key* @param array $ids* @return string*/public static function redisSetBits(string $key = '', array $ids = []){if (empty($key) || empty($ids)) {return '';}$redis = of_accy_cache_redis::inst();foreach ($ids as $id) {$redis->setBit($key, $id, 1);}$str = $redis->get($key);$res = '';for ($i = 0; $i < strlen($str); $i++) {// 获取每个字节的二进制表示,并去掉前缀 '0b'$byteBinary = str_pad(decbin(ord($str[$i])), 8, '0', STR_PAD_LEFT);$res .= $byteBinary;}return $res;}/*** getBitArrByRedisStr** @param string $bitStr* @return array*/public static function getBitArrByRedisStr(string $bitStr = ''){if (empty($bitStr)) {return [];}$collect = [];$len = strlen($bitStr);for ($i = 1; $i <= $len; $i ++) {if (intval($bitStr{$i}) == 1) {$collect[] = $i;}}return $collect;}
$key = 'bit-test';
of_accy_cache_redis::inst()->setBit($key, 12, 1);
$rStr = common_BitMap::getRedisBitStrByKey($key);
var_dump($rStr);
// string(16) "0000000000001000"$arr = [1 ,12 ,23];
$rStr = common_BitMap::redisSetBits($key, $arr);
var_dump($rStr);
// string(24) "010000000000100000000001"$rArr = common_BitMap::getBitArrByRedisStr($rStr);
var_dump($rArr);
/*
array(3) {[0]=>int(1)[1]=>int(12)[2]=>int(23)
}
*/

对比数组转换后的二进制串差异,发现redis的结果是反序的,如此就有了转换方式。

/*** redisStr2BitStr** @param string $str* @return string*/public static function redisStr2BitStr(string $str = ''){return strrev($str);}
$key = 'bit-test';
$arr = [1 ,12 ,23];$str = common_BitMap::setBits($arr);
var_dump($str);
// string(24) "100000000001000000000010"$rStr = common_BitMap::redisSetBits($key, $arr);
var_dump($rStr);
// string(24) "010000000000100000000001"$bitStr = common_BitMap::redisStr2BitStr($rStr);
var_dump($bitStr);
// string(24) "100000000001000000000010"$bitArr = common_BitMap::getArrByBitStr($bitStr);
var_dump($bitArr);
/*
array(3) {[0]=>int(1)[1]=>int(12)[2]=>int(23)
}
*/

欢迎交流!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/369604.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle EBS PO采购订单预审批状态处理

系统版本 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题症状: 采购订单状态:预审批 采购订单流程报错如下: po.plsql.PO_DOCUMENT_ACTION_AUTH.approve:90:archive_po not successful - po.plsql.PO_DOCUMENT_ACTION_PVT.do_action:110:unexpected error in acti…

【最详细】PhotoScan(MetaShape)全流程教程

愿天下心诚士子&#xff0c;人人会PhotoScan&#xff01; 愿天下惊艳后辈&#xff0c;人人可剑开天门&#xff01; 本教程由CSDN用户CV_X.Wang撰写&#xff0c;所用数据均来自山东科技大学视觉测量研究团队&#xff0c;特此鸣谢&#xff01;盗版必究&#xff01; 一、引子 Ph…

MySQL高级-MVCC- readview介绍

文章目录 1、介绍2、ReadView中包含了四个核心字段&#xff1a;3、版本链数据的访问规则&#xff1a;4、不同的隔离级别&#xff0c;生成ReadView的时机不同&#xff1a; 1、介绍 ReadView&#xff08;读视图&#xff09;是 快照读 SQL执行时MVCC提取数据的依据&#xff0c;记录…

Vue 常用指令详细介绍

Vue 常用指令 1.Vue 常用指令介绍 内容讲解 【1】Vue 指令介绍 在vue中指令是作用在视图中的即html标签&#xff0c;可以在视图中增加一些指令来设置html标签的某些属性和文本。 指令都是以带有 v- 前缀的特殊属性。 【2】使用Vue指令 使用指令时&#xff0c;通常编写在…

【C++】 解决 C++ 语言报错:Memory Leak

文章目录 引言 内存泄漏&#xff08;Memory Leak&#xff09;是 C 编程中常见且严重的内存管理问题之一。当程序分配了内存而没有正确释放&#xff0c;导致内存无法被重新利用时&#xff0c;就会发生内存泄漏。这种错误会导致程序占用越来越多的内存&#xff0c;最终可能导致系…

vscode 生成项目目录结构 directory-tree 实用教程

1. 安装插件 directory-tree 有中文介绍&#xff0c;极其友好&#xff01; 2. 用 vscode 打开目标项目 3. 快捷键 Ctrl Shift p&#xff0c;输入 Directory Tree 后回车 会在 README.md 文件的底部生成项目目录&#xff08;若项目中没有 README.md 文件&#xff0c;则会自动创…

恢复机制-数据库系统中的故障(事务故障、系统故障、介质故障)、一致性错误、窃取但不强制的缓冲区管理策略

一、引言 数据库管理系统DBMS的事务处理技术实现的一个主要功能部分就是恢复机制&#xff0c;恢复机制完成的功能就是对发生故障后系统中事务的更新结果进行数据恢复&#xff0c;保证事务的原子性和持久性&#xff0c;从而进一步保证数据库的一致性。 数据库系统与其他计算机系…

Pytest--安装与入门

pytest是一个能够简化成测试系统构建、方便测试规模扩展的框架&#xff0c;它让测试变得更具表现力和可读性–模版代码不再是必需的。只需要几分钟的时间&#xff0c;就可以对你的应用开始一个简单的单元测试或者复杂的功能测试。 1. 安装pytest pip install -U pytest检查版…

MaxKB开源知识库问答系统发布v1.3.0版本,新增强大的工作流引擎

2024年4月12日&#xff0c;1Panel开源项目组正式发布官方开源子项目——MaxKB开源知识库问答系统&#xff08;github.com/1Panel-dev/MaxKB&#xff09;。MaxKB开源项目发布后迅速获得了社区用户的认可&#xff0c;成功登顶GitHub Trending趋势榜主榜。 截至2024年7月4日&…

【Mathematica14.0】快速从下载安装到使用

目录 1.简介 2.下载安装 下载 安装 3.一小时掌握mathematica使用 单元模式 内置函数 符号表达式 迭代器 赋值 通配符及查找替换 函数定义 匿名函数&#xff08;拉姆达表达式&#xff09; 函数映射 函数式与运算符 函数自定义选项 图形可视化 交互式界面 数值…

【ROS2】Ubuntu 24.04 源码编译安装 Jazzy Jalisco

目录 系统要求 系统设置 设置区域启用所需的存储库安装开发工具 构建 ROS 2 获取 ROS 2 代码使用 rosdep 安装依赖项安装额外的 RMW 实现&#xff08;可选&#xff09;在工作区构建代码 设置环境 尝试一些例子 下一步 备用编译器 Clang保持最新状态 故障排除 卸载 系统要求 当前…

长沙(市场调研公司)源点 企业如何决定是否需要开展市场调研?

长沙源点调研咨询认为&#xff1a;对于一个特定问题&#xff0c;管理者在面临几种解决问题的方案时&#xff0c;不应该凭直觉草率开展应用性市场调研。事实上&#xff0c;首先需要做的决策是是否需要开展调研。在下述情况下&#xff0c;最好不要做调研&#xff1a; *缺乏资源。…

查询工资级别的个数>20的个数,并且按工贷级别降序

SELECT COUNT(*), grade_level FROM employees e JOIN job_grades g ON e.salary BETWEEN g.lowest_sal AND g.highest_sal GROUP BY grade_level HAVING COUNT(*) > 20 ORDER BY grade_level DESC; 为什么需要GROUP BY而不是仅仅ORDER BY&#xff1f; 聚合数据&#xff1a…

【ARMv8/v9 GIC 系列 5.1 -- GIC GICD_CTRL Enable 1 of N Wakeup Function】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 GIC Enable 1 of N Wakeup Function基本原理工作机制配置方式应用场景小结GIC Enable 1 of N Wakeup Function 在ARM GICv3(Generic Interrupt Controller第三代)规范中,引入了一个名为"Enable 1 of N Wakeup"的功能。…

SQLyog脚本无限试用重置脚本

文章目录 引言脚本(win)必要操作、说明 引言 SQLyog 需要po jie&#xff0c;但是网上的没看到很好使的&#xff0c;直接下的官方。能处理14天试用也是很ok的。 脚本(win) echo offREM SQLyog注册表key&#xff0c;可能跟你的不一样&#xff0c;如果不一样&#xff0c;请替换…

Another Redis Desktop Manager工具自定义解析数据

自定义解析数据,支持多种程序终端输出 /Users/admin/go/src/baobao_all/ws_server/baobao/main_test/encipher_tool_redis/redis_tool {VALUE}/bin/bash -c "/Users/admin/Downloads/redis_tool {VALUE}"写个go程序解析数据 package mainimport ("encoding/jso…

鸿蒙:1.入门

概述 简介 鸿蒙操作系统&#xff08;HarmonyOS&#xff09;是华为公司发布的一款智能终端系统&#xff0c;是基于微内核的面向全场景的分布式操作系统。它致力于提供更加安全、高效、低延迟、低功耗的操作体验&#xff0c;可通过技术手段对应用程序和设备进行智能协同&#xf…

每日复盘-20240705

今日关注&#xff1a; 20240705 六日涨幅最大: ------1--------300391--------- 长药控股 五日涨幅最大: ------1--------300391--------- 长药控股 四日涨幅最大: ------1--------300391--------- 长药控股 三日涨幅最大: ------1--------300391--------- 长药控股 二日涨幅最…

Windows的管理工具

任务计划程序&#xff1a;这是一个用来安排任务自动运行的工具。你可以在这里创建新的任务&#xff0c;设定触发条件&#xff0c;并指定任务的操作。 事件查看器&#xff1a;这是一套日志记录和分析工具&#xff0c;&#xff0c;你可以了解到系统的工作状况&#xff0c;帮助诊…

React+TS 从零开始教程(4):useEffect

上一节传送门&#xff1a;ReactTS 从零开始教程&#xff08;3&#xff09;&#xff1a;useState 源码链接&#xff1a;https://pan.quark.cn/s/c6fbc31dcb02 上一节&#xff0c;我们已经学会了React的第一个Hook&#xff1a;useState。 这一节&#xff0c;我们要学习的是另一…