当前位置:首页 > 技术 > 正文内容

将Hive/Spark中的RoaringBitmap数据写入Clickhouse的Bitmap类型

访客 技术 2026年6月15日 1
为了实现将Hive或Spark中的RoaringBitmap数据同步到Clickhouse的Bitmap类型,本文深入分析了Clickhouse中Bitmap类型的底层结构以及与Hive/Spark的兼容性问题,并提供了解决方案。

1. Clickhouse的Bitmap结构解析

在Clickhouse中,Bitmap类型通常通过`groupBitmap`聚合函数生成。例如:
SELECT series_id, groupBitmapState(toUInt32(dvid)) AS bitmap_column FROM dms_pds_flow_interest_dvid_city_day_all GROUP BY series_id;
上述SQL的核心在于`groupBitmapState`函数,其底层由C++实现,具体位于`AggregateFunctionGroupBitmap.cpp`文件中。核心逻辑通过`createAggregateFunctionBitmap`创建了一个名为`AggregateFunctionGroupBitmapData`的类实例。 `AggregateFunctionGroupBitmapData`的内部结构如下: - **高16位和低16位存储模型**:Clickhouse使用`roaring_array_t`结构体来管理Bitmap数据。每个Bitmap被划分为多个桶(bucket),每个桶对应一个高16位值,而低16位则存储在对应的容器中。 Bitmap结构图

2. Hive/Spark中的RoaringBitmap实现

Hive中的Bitmap生成主要依赖自定义UDAF(User Defined Aggregation Function)。关键方法包括: - `terminatePartial`:返回部分聚合结果。 - `merge`:合并两个部分结果。 - `terminate`:输出最终结果。 以Hive为例,其Bitmap最终以Java二进制数组形式返回。因此,要实现Hive与Clickhouse的Bitmap兼容,需解决如何将Hive的二进制数组有效转换为Clickhouse支持的格式。

3. Clickhouse的Bitmap存储机制

Clickhouse中的Bitmap数据存储分为两种模式: - **SmallSet模式**:当基数小于等于32时,直接存储原始数据。 - **RoaringBitmap模式**:当基数超过32时,转换为压缩格式存储。 以下是关键代码片段:
void add(T value) { if (isSmall()) { if (!small.full()) { small.insert(value); } else { toLarge(); rb->add(static_cast(value)); } } else { rb->add(static_cast(value)); } }
写入序列化数据时,遵循以下格式: 1. 写入标识符(`UInt8`类型),`0`表示SmallSet,`1`表示RoaringBitmap。 2. 若为RoaringBitmap,先写入序列化字节大小(`VarInt`编码)。 3. 写入实际的字节数组。

4. Java实现Bitmap序列化

以下是基于Java的Bitmap序列化示例代码:
import org.roaringbitmap.RoaringBitmap; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.nio.ByteBuffer; import java.util.Base64; public class BitmapSerializer { public static String serialize(RoaringBitmap bitmap) { if (bitmap.getCardinality() <= 32) { ByteBuffer buffer = ByteBuffer.allocate(4 * bitmap.getCardinality() + 2); buffer.put((byte) 0); // SmallSet标识 buffer.put((byte) bitmap.getCardinality()); for (int value : bitmap.toArray()) { buffer.putInt(value); } return Base64.getEncoder().encodeToString(buffer.array()); } else { ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); try (DataOutputStream dataStream = new DataOutputStream(byteArrayStream)) { bitmap.serialize(dataStream); byte[] serializedBitmap = byteArrayStream.toByteArray(); ByteBuffer buffer = ByteBuffer.allocate(serializedBitmap.length + 5); buffer.put((byte) 1); // RoaringBitmap标识 writeVarInt(serializedBitmap.length, buffer); buffer.put(serializedBitmap); return Base64.getEncoder().encodeToString(buffer.array()); } catch (Exception e) { throw new RuntimeException("Serialization failed", e); } } } private static void writeVarInt(int value, ByteBuffer buffer) { while ((value & ~0x7F) != 0) { buffer.put((byte) ((value & 0x7F) | 0x80)); value >>>= 7; } buffer.put((byte) value); } }

5. Spark批量写入Clickhouse

通过Spark SQL可批量处理RoaringBitmap数据并写入Clickhouse。具体步骤如下: 1. 使用自定义UDF对Bitmap数据进行序列化。 2. 将序列化后的字符串插入Clickhouse表。 3. 利用Clickhouse的物化视图功能自动解码并存储为Bitmap类型。 示例代码参考:[https://github.com/niutaofan/spark_bitmap.git](https://github.com/niutaofan/spark_bitmap.git)

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。