RoaringBitMap处理海量数据内存diff

一、背景

  假设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.mzph.cn/pingmian/29642.shtml

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

相关文章

了解Nest.js

一直做前端开发&#xff0c;都会有成为全栈工程师的想法&#xff0c;而 Nest 就是一个很好的途径&#xff0c;它是 Node 最流行的企业级开发框架&#xff0c;提供了 IOC、AOP、微服务等架构特性。接下来就让我们一起来学习Nest.js Nest.js官网地址 一&#xff0c;了解Nest Cli …

充电学习—6、电量计FuelGauge

电量计功能&#xff1a; 检测电池 计量电量 电量计首要工作&#xff1a; 计算电池的剩余容量、充满时容量、电量百分比 电量百分比 剩余容量 / 充满时容量 * 100% SOC RM / FCC * 100% 典型的一个电池包框架&#xff1a; 包含电芯、电量计IC、保护IC、充放电MOSFET、保险丝…

栈帧浅析,堆栈漏洞概述——【太原理工大学软件安全期末补充】

在上一篇文章中我说实验一不重要&#xff0c;确实没必要完全按照实验内容逐字逐句理解&#xff0c;但是这里我们补充一个知识点 栈帧&#xff08;Stack Frame&#xff09;是计算机程序执行过程中&#xff0c;调用栈&#xff08;Call Stack&#xff09;中的一个单元&#xff0c;…

hugging face:大模型时代的github介绍

1. Hugging Face是什么&#xff1a; Hugging Face大模型时代的“github”&#xff0c;很多人有个这样的认知&#xff0c;但是我觉得不完全准确&#xff0c;他们相似的地方在于资源丰富&#xff0c;github有各种各样的软件代码和示例&#xff0c;但是它不是系统的&#xff0c;没…

Linux-DNS域名解析服务01

BIND 域名服务基础 1、DNS&#xff08;Domain Name System&#xff09;系统的作用及类型 整个 Internet 大家庭中连接了数以亿计的服务器、个人主机&#xff0c;其中大部分的网站、邮件等服务器都使用了域名形式的地址&#xff0c;如 www.google.com、mail.163.com 等。很显然…

探索C嘎嘎的奇妙世界:第十四关---STL(string的模拟实现)

1. string类的模拟实现 1.1 经典的string类问题 上一关已经对string类进行了简单的介绍&#xff0c;大家只要能够正常使用即可。在面试中&#xff0c;面试官总喜欢让学生自己来模拟实现string类&#xff0c;最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数…

MacOS - command not found: brew

问题描述 command not found: brew 原因分析 没有安装 Homebrew&#xff0c;安装后即可使用~ 解决方案 打开终端&#xff0c;输入&#xff1a;/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"&#xff0c;点击回车 在弹出…

小程序的登录+发布流程

今天我们来将一下小程序的登录和发布流程&#xff01;&#xff01;&#xff01; 小程序的登录流程 流程图 首先登录流程还是看官网说的&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 这是官网发布的一个流程图 认识cod…

2 图片的分割处理和亚像素精度处理(c++和python)

本文的图片处理分为图片分割、图像的亚像素坐标处理。亚像素处理的原理可以看论文一种基于多项式插值改进的亚像素细分算法&#xff0c;该论文的详解及c的代码实现可以看博文基于多项式插值的亚像素边缘定位算法_基于多项式插值的亚像素算法-CSDN博客。下面的内容很多来自以上博…

【论文阅读】-- 时间空间化:用于深度分类器训练的可扩展且可靠的时间旅行可视化

Temporality Spatialization: A Scalable and Faithful Time-Travelling Visualization for Deep Classifier Training 摘要1 引言2 动机3 问题定义4 方法论4.1 时空复合体4.2 复数约简 5 实验6 相关工作7 结论参考文献 摘要 时间旅行可视化回答了深度分类器的预测是如何在训练…

MATLAB画图时添加标注显示有效数字的位数,可以编辑此函数

本来系统有个函数&#xff0c;在图像窗口选择标注工具&#xff0c;再在图像窗口右击鼠标&#xff0c;选择"编辑文本更新函数..."&#xff0c;即打开系统的设置函数&#xff0c;可以修改最后一行&#xff1a; formattedValue [valueFormat num2str(value,4) removeV…

QT-day3

1、思维导图 2、升级优化自己应用程序的登录界面。 要求&#xff1a; 1. qss实现 2. 需要有图层的叠加 &#xff08;QFrame&#xff09; 3. 设置纯净窗口后&#xff0c;有关闭等窗口功能。 4. 如果账号密码正确&#xff0c;则实现登录界面关闭&#xff0c;另一个应用界面显示。…

C#标志位的使用

C#作为一种功能强大的编程语言&#xff0c;是在.NET框架中广泛使用的语言之一。在实际应用中&#xff0c;C#的标志位在各种系统设计和编程实践中会涉及到。这篇文章将讨论如何使用C#的标志位来跟踪报警声音的播放状态。 报警系统是一种广泛应用的系统&#xff0c;它可以在关键时…

本地部署Ollama+qwen本地大语言模型Web交互界面

什么是 Ollama WebUI&#xff1f; Ollama WebUI 已经更名为 Open WebUI. Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 WebUI&#xff0c;旨在完全离线操作。它支持各种 LLM 运行程序&#xff0c;包括 Ollama 和 OpenAI 兼容的 API。 Ollama WebUI 是一个革命性的 L…

深度学习(九)——神经网络:最大池化的作用

一、 torch.nn中Pool layers的介绍 官网链接&#xff1a; https://pytorch.org/docs/stable/nn.html#pooling-layers 1. nn.MaxPool2d介绍 nn.MaxPool2d是在进行图像处理时&#xff0c;Pool layers最常用的函数 官方文档&#xff1a;MaxPool2d — PyTorch 2.0 documentation &…

微信小程序毕业设计-小区疫情防控系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

ChatGPT的问题与回复的内容导出(Chorme)

我给出两种方式&#xff0c;第一种方式无使用要求&#xff0c;第二种方式必须安装Chorme 个人更推荐第二种方式 第一种方式&#xff1a;使用chatgpt自带的数据导出 缺点&#xff1a;会将当前未归档的所有聊天记录导出&#xff0c;发送到你的电子邮箱中 第二种方式&#xff1a…

STM32 proteus + STM32Cubemx仿真教程(第五课ADC光敏电阻采样教程)

文章目录 前言一、ADC概念二、光敏电阻的概念1. 光敏电阻的工作原理2. 光敏电阻的特性3. 光敏电阻的应用4. 光敏电阻的电路设计5. 实际使用中的注意事项总结 三、STM32Cubemx创建工程四、proteus仿真电路图五、代码编写1. HAL_ADC_Start 函数原型参数返回值功能描述示例 2. HAL…

Java每日作业day6.18

ok了家人们今天我们继续学习方法的更多使用&#xff0c;闲话少叙&#xff0c;我们来看今天学了什么 1.重载 在同一个类中&#xff0c;可不可以存在同名的方法&#xff1f;重载:在同一个类中&#xff0c;定义了多个同名的方法&#xff0c;但每个方法具有不同的参数类型或参数个…

网络编程4----网络原理(面试及期末必备)

1 应用层 应用层是与程序员关系最密切的一层&#xff0c;在应用层这里了&#xff0c;很多时候&#xff0c;都是使用程序员自定义的协议&#xff0c;当然&#xff0c;也有很多现成的协议供我们使用。 “自定义协议”&#xff1a; 自定义一个协议&#xff0c;也就是自己做一个…