RoaringBitMap处理海量数据内存diff

news2024/11/24 0:53:26

一、背景

  假设mysql库中有一张近千万的客户信息表(未分表),其中有客户性别,等级(10个等级),参与某某活动等字段
 1、如果要通过等级+性别+其他条件(离散度也低)筛选出客户,如何处理查询?
 2、参与活动是记录活动ID,客户每参与一个活动,就要记录客户和该活动id的关联,活动记录字段如何存储?
使用mysql存储,对应上方场景,可能会面临以下问题
 1、查询条件关联字段虽然建立了索引,但是由于字段值离散度较低,导致索引失效,直接变成全表扫描
 2、活动记录字段,由于要存储多值,只能设计存活动ID的json串或者符号分隔存储,直接导致该字段无法建立有效的索引
  可以发现,传统的关系型数据库,面对以上场景,暂时没办法设计出合理的索引,所以会导致无法查询的情况。
  为了解决以上问题,一开始方向也是使用mongoDB或者ES去进行数据异构存储,借助NoSql的结构,存储频繁变更的数据,比如,活动id字段可以直接存储为数组,也可以建立索引。
但是,由于时间、资源等关系,进行数据异构存储成本较大,所以只能寻找替代方案。

  在存储方式还是使用Mysql的情况下,如何进行数据检索呢,基于上面的场景,很明显直接使用mysql查询已经走不通了,需要使用标签操作数据,在内存中进行数据的交并集操作。

  所以问题就转变成了,什么样的数据结构,可以以较低的内存占用,存储海量数据,还支持交差并集等逻辑操作呢?

位图结构,完美适合标签场景,位图是过bit数组来存储数据的数据结构,是一串连续的二进制数组(0和1),可以通过偏移量(offset)定位元素。通过最小的单位bit来进行0|1的设置,表示某个元素的值或者状态,时间复杂度为O(1)。

二、技术选型

接上背景,既然选择了位图作为标签场景下的查询方案,那么应该选取哪种Bitmap实现呢?

java原生的BitSet,guava的EWAHCompressedBitmap,第三方的RoaingBitmap  

  注:由于标签可能每日全量更新,需要考虑内存操作且能够持久化,redis的Bitmap,在一亿数据量情况下,不拆分(取余,hash等),size为12M,推算5千万数据量size为6M,属于大key( >5M ),且大数据量Bitmap初始化,可能造成redis阻塞延迟,故暂时不考虑。

巧用RoaringBitMap处理海量数据内存diff问题 - 知乎

这里借用上方引文的测试结果:

内存占用测试:往Bitmap中添加1、N+1、2N+1.....5000000数据,其中N为数据的步长(稀疏度) 来计算各个Bitmap在不同稀疏度下(N)的内存占用情况。通过下图可以看出,除了在稀疏度为1时,EWAHCompressedBitmap内存占用最低以外,其余稀疏度下的内存占用:RoaingBitmap<EWAHCompressedBitmap<BitSet。

CPU耗时测试:往各个Bitmap中添加1、N+1、2N+1.....5000000数据,其中N为数据的步长(稀疏度),然后与有5000000满数据的Bitmap分别求2000次差集并取2000次中的最大耗时,得到在每个稀疏度下每种Bitmap的耗时情况。通过下图可以看出,各个稀疏度下的cpu耗时:RoaingBitmap≈EWAHCompressedBitmap<BitSet.

基于上方的测试数据,从内存占用,CPU耗时等方面,RoaingBitmap均要优于其他类型的位图,所以,选择RoaingBitmap作为新方案的Bitmap实现。

持久化存储:Bitmap、BitSet、RoaringBitmap持久化存储_bitset持久化-CSDN博客

api文档:RoaringBitmap 1.0.1 javadoc (org.roaringbitmap)

三、RoaingBitmap简单介绍及原理

如果你只是简单使用,那么记住:RoaringBitmap是高效压缩位图。其实就够了。

  RoaringBitmap的核心思想是将整数集合按照高位划分成不同的容器,每个容器内部再使用不同的存储策略。具体而言,它将一个32位的整数分成两部分:

1、高16位作为容器的索引(container index)。
2、低16位则存储在相应的容器中。
RoaringBitmap支持两种类型的容器:

1、ArrayContainer:当一个容器内的元素数量较少(通常少于4096个)时,使用一个简单的数组来存储这些元素。这种容器适合存储稀疏的数据。
2、BitmapContainer:当容器内元素数量较多时,使用位图存储。位图是一个长数组,每个位代表一个低16位的整数是否存在。这适合存储密集型数据。

传送门:RoaringBitmap的原理与应用,看这个就够了-CSDN博客

四、存储设计

  使用Mysql的longtext类型存储持久化后的RoaingBitmap。

注意:

1、Mysql字段类型:text 字段类型的字节限制为 65535 字节, 约为0.06MB;longtext 字段类型的字节限制为 2147483647 字节,约为2047MB;mediumtext 字段类型的字节限制为 16777215 字节,约为16MB。

2、mysql单次最大传输数据量限制约为16M

3、RoatingBitMap 5千万全量数据,持久化存储需要 6259385 字节,约 6M;

持久化关联Java代码,以及RoaringBitMap的逻辑i操作:

    /**
     * roaringBitmap 转 string
     *
     * @param roaringBitmap 入参
     * @return str
     */
    public static String roaringBitMapToString(RoaringBitmap roaringBitmap) {
        // RoaringBitMap 转为byte数组
        byte[] array = new byte[roaringBitmap.serializedSizeInBytes()];
        roaringBitmap.serialize(ByteBuffer.wrap(array));
        // byte转为字符串
        return new String(array, StandardCharsets.ISO_8859_1);
    }

    /**
     * string 转 roaringBitmap
     *
     * @param bitMapStr bitmap序列化字符串
     * @return RoaringBitmap
     */
    public static RoaringBitmap stringToRoaringBitMap(String bitMapStr) {
        RoaringBitmap roaringBitmap = new RoaringBitmap();
        try {
            // str 转为 byte数组
            byte[] redisArray = bitMapStr.getBytes(StandardCharsets.ISO_8859_1);
            roaringBitmap.deserialize(ByteBuffer.wrap(redisArray));
        } catch (IOException e) {
            log.error("stringToRoaringBitMap {} Error", bitMapStr.length(), e);
        }
        return roaringBitmap;
    }

    /**
     * bitMap操作
     *
     * @param oldBitMap    bitMap_1
     * @param newSubBitMap bitMap_2
     * @param operate      操作符
     * @return RoaringBitmap
     */
    public static RoaringBitmap roaringBitMapOperate(
            RoaringBitmap oldBitMap, RoaringBitmap newSubBitMap, String operate) {
        switch (operate) {
            case "add":
            case "or":
                oldBitMap.or(newSubBitMap);
                break;
            case "remove":
                oldBitMap.andNot(newSubBitMap);
                break;
            case "replace":
                oldBitMap = newSubBitMap;
                break;
            case "and":
                oldBitMap.and(newSubBitMap);
                break;
            default:
                throw new IllegalArgumentException("operate 异常" + operate);
        }
        return oldBitMap;
    }

五、压测数据准备

目标数据量 五千万 客户,10个标签,总数据量在一亿两千万左右,存储空间53MB

六、本地环境(4核8G机器)测试结果

5千万客户,标签覆盖率约为 50%,40%,30% ,20%,10%五个批次;客户随机离散分布在10个标签, 单标签平均客户量一千二百万左右,测试随机取交,并集耗时。

jmeter单线程循环调用

参与筛选标签数据

交/并集

取样次数

响应耗时中位数

平均数

响应耗时90%

响应耗时95%

响应耗时99%

最小

最大

2个50277276286289303263303
2个50273276286288308262308
2个随机50282283299302307265307
5个50702712746755792664792
5个50701710727733761667761
5个随机50685690715729742665742
8个随机501145114011751187120210751202
10个随机501379138714331450148113361481

jmeter多线程循环调用 开发环境单副本 5个线程循环20次

参与筛选标签数据

交/并集

取样次数

响应耗时中位数

平均数

响应耗时90%

响应耗时95%

响应耗时99%

最小

最大

2个随机100526525601609623299658
5个随机100140914481685172318168711897
8个随机1002210221924332468260516502760
10个随机1002789281530943125330821943440

1、任意2个标签取交、并集耗时, 各采样50次

并集测试结果

2、任意5个标签取交、并集耗时, 各采样50次

交集测试结果

3、任意8个标签随机交、并集耗时, 采样50次

4、任意10个标签随机取交、并集耗时, 各采样50次

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

科凡定制首倡轻高定突围的蓝海战术是明星代言?

4月19日&#xff0c;科凡家居再度重磅发声&#xff0c;正式宣布国际女星舒淇为全球代言人。 纵观定制家居几大一线品牌&#xff0c;欧派代言人胡歌&#xff0c;索菲亚代言人倪妮。尚品宅配代言人赵丽颖&#xff0c;维意定制代言人黄轩&#xff0c;志邦家居代言人周杰伦......大…

31.加载配置文件中的游戏到辅助列表

上一个内容&#xff1a;30.保存游戏配置到文件 以 30.保存游戏配置到文件 它的代码为基础进行修改 效果图&#xff1a; 加载配置文件到列表的函数&#xff1a; void CWndINJ::LoadGame() {int count GetPrivateProfileInt(L"main", L"count", 0, GameI…

sourceTree 解决remote: HTTP Basic: Access denied报错mac

解决sourceTree中remote: HTTP Basic: Access denied报错 mac sourcetree报错报错原因解决方案 mac sourcetree报错 warning: invalid credential line: xxx.com remote: HTTP Basic: Access denied fatal参考链接&#xff1a;https://developer.aliyun.com/article/1304149 …

经典文献阅读之--OrienterNet(自动驾驶中基于网格的交通场景感知)

dia 0. 简介 使用神经网络来匹配2D公开地图的做法是一个很有趣的方法&#xff0c;人们可以使用简单的2D地图在3D环境中指明自己所处的位置&#xff0c;而大部分视觉定位算法则依赖于昂贵的、难以构建和维护的3D点云地图。为了弥合这一差距《OrienterNet: Visual Localization…

全球首个开源类Sora模型大升级,16秒720p画质电影感爆棚!代码和权重全面开源!

目录 01 视频界开源战士 02 深度解码技术 03 打破闭环&#xff0c;开源赋能 潞晨Open-Sora团队刚刚在720p高清文生视频质量和生成时长上实现了突破性进展&#xff01; 全新升级的Open-Sora不仅支持无缝生成任意风格的高质量短片&#xff0c;更令人惊喜的是&#xff0c;团队选…

关于办公软件的使用

第一部分&#xff1a; 常用函数的使用 在使用的地方&#xff0c;输入SUM(B2:F2)回车 第二部分&#xff1a; 自定义函数的使用 1、打开 宏编辑 2、 自定义函数方法 3、自定义函数的使用和常用函数一样&#xff1a; 在使用的地方&#xff0c;输入计算面积(A3&#xff0c;B3)…

算法设计与分析期末复习题

一&#xff1a;程序阅读分析题&#xff08;共40分&#xff09; 1.&#xff08;8分&#xff09;阅读“算法1”&#xff0c;分析算法1的功能、时间复杂度。 答案&#xff1a;经典的汉诺塔问题&#xff0c;其目标是将 n 个不同大小的盘子从柱子 A 移动到柱子 C&#xff0c;借助柱…

PDM 测试

文章目录 硬件拓扑AP 生成 PDM输出数据路径AP 输入时域数据频域数据逻辑分析与抓包硬件拓扑 如果使用 AP 需要注意公地 AP 生成 PDM输出 AP 的 output 选择 PDM,MCU 提供 Bit clock,AP 生成 PDM 数据,AP 配置如下 数据路径 AP sin data -> PDM -> codec -> RA…

Git的下载安装及可视化工具小乌龟

一、 Git 的下载 第1步&#xff1a;下载Git&#xff0c;下载地址&#xff1a;Git for Windows 这个就需要去 Git 官网下载对应系统的软件了&#xff0c;下载地址为 git-scm.com或者gitforwindows.org&#xff0c;或者阿里镜像&#xff08;感谢评论区的星悸迷航同学&#…

el-pagination分页组件导致发送两次请求

场景 有一个搜索框&#xff0c;搜索显示表格内容&#xff0c;下面有分页组件&#xff0c;大概长这样&#xff1a; 当分页组件选择到别的页数&#xff08;非第一页&#xff09;&#xff0c;再进行查询&#xff0c;查询的内容会显示在第一页&#xff0c;此时会发送两次网络请求。…

TIA Portal 博途 集成自动化软件下载安装,TIA Portal 轻松驾驭复杂工业设备

在博途TIA Portal的全方位赋能下&#xff0c;用户可以轻松驾驭复杂的工业设备&#xff0c;实现设备的精准配置、高效编程、便捷调试和实时监控。 在配置方面&#xff0c;博途TIA Portal以其强大的配置功能&#xff0c;帮助用户快速定义设备的各项参数&#xff0c;使设备能够快速…

洛谷 P3379:最近公共祖先(LCA)← RMQ+欧拉序

【题目来源】https://www.luogu.com.cn/problem/P3379【题目描述】 如题&#xff0c;给定一棵有根多叉树&#xff0c;请求出指定两个点直接最近的公共祖先。【输入格式】 第一行包含三个正整数 N,M,S&#xff0c;分别表示树的结点个数、询问的个数和树根结点的序号。 接下来 N−…

MFC绘制哆啦A梦

OnPaint绘制代码 CPaintDC dc(this); // 用于绘画的设备上下文CRect rc;GetWindowRect(rc);int cxClient rc.Width();int cyClient rc.Height();// 辅助线HPEN hPen CreatePen(PS_DOT, 1, RGB(192, 192, 192));HPEN hOldPen (HPEN)SelectObject(dc, hPen);MoveToEx(dc, cxC…

论文学习_Fuzz4All: Universal Fuzzing with Large Language Models

论文名称发表时间发表期刊期刊等级研究单位Fuzz4All: Universal Fuzzing with Large Language Models2024年arXiv-伊利诺伊大学 0.摘要 研究背景模糊测试再发现各种软件系统中的错误和漏洞方面取得了巨大的成功。以编程或形式语言作为输入的被测系统&#xff08;SUT&#xff…

git\repo

常用git和repo命令_repo git-CSDN博客文章浏览阅读1.5w次&#xff0c;点赞9次&#xff0c;收藏112次。常用git和repo命令文章收集了最近使用的一些repo和git命令&#xff0c;下图是个人理解的git文件状态转换图。 相关概念 名称 意义 repo 谷歌用Python脚本写的调用git的一个脚…

Springboot集成SSE消息推送

SSE介绍 SSE&#xff08;Server-Sent Events&#xff09;的全称是服务器推送事件&#xff0c;它是一种基于 HTTP 协议的实时通信技术&#xff0c;用于在客户端和服务器之间建立持久、单向的链接&#xff0c;允许服务器向客户端发送异步消息。 了解 websocket 的小伙伴&…

257、二叉树的所有路径

给定一个二叉树&#xff0c;返回所有从根节点到叶子节点的路径。 说明: 叶子节点是指没有子节点的节点。 代码如下&#xff1a; class Solution { public:void traversal(TreeNode* cur, vector<int>& path, vector<string> &result){path.push_back(cur…

南阳理工学院(期末)算法分析练习题

一、算法阅读分析题&#xff1a; 1.分析如下算法&#xff0c;回答问题&#xff08;10分&#xff09;。 该算法的作用是什么(2分)&#xff1f;分析该算法的时间复杂度(5分)?设计算法的一个输入&#xff0c;并给出对应的算法输出结果(3分) &#xff08;1&#xff09;该算法的作…

虹软ArcSoft—真正离线免费的人脸识别SDK

虹软ArcSoft—真正离线免费的人脸识别SDK 高级功能收费 还是很好滴 人证核验功能是C/C的SDK&#xff0c;需要封装为C#&#xff0c;然后暴露为Restful API使用

2024年阿里巴巴全球数学竞赛首次向人工智能(AI)开放

大家好&#xff0c;我是微学AI&#xff0c;最近大家突然开始关注阿里巴巴全球数学竞赛了&#xff0c;在这个人工智能爆发的时代&#xff0c;2024年阿里巴巴全球数学竞赛首次向人工智能&#xff08;AI&#xff09;开放&#xff0c;要求参赛的AI模型在比赛前提交源代码&#xff0…