Bitmap原理及Hive去重方式对比

1. 什么是 Bitmap?

Bitmap (位图)是一种用位(bit)来表示数据集合的数据结构。每个位代表一个元素是否存在,比如:

  • 一个长度为N的bitmap,每一位对应一个元素的状态(0或1)
  • 例如,数字集合 {1, 3, 4},用bitmap表示就是第1、3、4位为1,其余为0。

1.1 Bitmap的特点:

  • 空间利用率高:用bit表示,存储效率高。
  • 查询效率快:判断某个元素是否存在,直接定位对应bit即可。
  • 支持快速集合操作:如并集、交集、差集等,直接对bit位做位运算。

1.2 位(bit)、字节(byte)、KB(千字节)

1.2.1 位(bit)
  • 定义 :bit是计算机中最小的数据单位 ,表示二进制中的一个0或1
  • 符号 :通常用小写字母 b 表示。
  • 作用:所有数字、字符、图像、声音等信息,最终都以0和1的形式存储和处理,bit就是这些信息的最小单位。
1.2.2 字节(byte)
  • 定义 :字节是计算机存储信息的基本单位 ,通常由8个bit组成
  • 符号 :用大写字母 B 表示。
  • 作用 :一个字节可以表示256种不同的状态(2^8),通常用来表示一个字符(比如一个英文字母、数字或符号),中文占2-4个字符,udf-8占3个,udf-16大多占2个,生僻字占4个,GB2312 / GBK / GB18030大陆编码占4个。
  • 关系:1 字节 = 8 位 (bits)
1.2.3 KB(千字节)
  • 定义 :KB是存储容量的单位,表示1024个字节。
  • 符号 :用大写字母 KB 表示。
  • 注意:虽然"K"通常表示1000,但计算机存储中,1KB = 1024字节(2的10次方),这是因为计算机采用二进制计数。
  • 关系
    • 1 KB = 1024 Bytes
    • 1 Byte = 8 bits
1.2.4 总结关系
单位 含义 大小关系
1 bit (b) 最小数据单位,0或1 ---
1 Byte (B) 8 bit 1 B = 8 b
1 KB 1024 Bytes 1 KB = 1024 B = 8192 b
1.2.5 举个例子
  • 一个英文字符(如字母"A")通常占用1字节(8位)。
  • 一个文件大小为10KB,意味着它大约有10 × 1024 = 10240字节,等于 10,240 × 8 = 81,920 位。

2. Bitmap的用途

  • 去重计数(Distinct Count):统计不重复元素个数。
  • 集合操作:快速实现集合的并、交、差。
  • 布隆过滤器判断元素是否存在(可能有误判)
  • 大数据场景:处理海量数据的去重、统计。

3. Hive中如何用Bitmap去重?

Hive本身不直接支持bitmap类型,但可以通过扩展函数(UDF)或者第三方库 (如bitmap-udfRoaringBitmap等)实现。

常见做法:

  • 使用bitmap UDF构建bitmap,比如 bitmap_add(),把每个元素对应的bit位置置1。
  • 最后用 bitmap_count() 计算bitmap中1的个数,即去重后的数量。

示例伪代码:

sql 复制代码
SELECT
  bitmap_count(bitmap_union_agg(bitmap_add(user_id))) AS distinct_user_count
FROM
  user_logs;
  • bitmap_add(user_id):把user_id加入bitmap。
  • bitmap_union_agg():聚合多个bitmap做并集。
  • bitmap_count():统计bitmap中1的数量

4. 和 count(distinct)size(collect_set())对比

4.1 总结

方式 功能描述 优点 缺点
count(distinct) 统计某列中不同值的数量 简单直接,Hive原生支持 对大数据量去重性能差,容易导致内存溢出,计算慢
size(collect_set()) 先去重收集某列的所有不同值,返回集合大小 可以拿到去重后的集合,方便后续操作 集合数据会被收集到单个节点,内存压力大,数据量大时不适用
Bitmap去重 利用位图结构标记元素出现,统计不重复元素数量 - 内存占用低,适合大规模数据去重 - 计算速度快 - 支持分布式合并 - 需要额外安装bitmap UDF - 只能统计数量,不能直接拿到去重元素 - 误差(如果用压缩bitmap或近似算法)

4.2执行过程及原理

4.2.1count(distinct)
执行过程:
  • Map阶段
    • 读取数据,提取目标字段值。
    • 在Map端做局部去重(减少数据量)。
  • Shuffle阶段
    • 将局部去重后的数据发送到Reducer。
  • Reduce阶段
    • Reducer对接收到的所有值做全局去重。
    • 统计不同值数量,输出结果。
原理:
  • 使用哈希表或类似数据结构存储不同元素。
  • 需要在内存中维护distinct值集合,内存消耗与distinct数量相关。
4.2.2 size(collect_set())
执行过程:
  • Map阶段
    • 读取数据,提取字段值。
  • Shuffle阶段
    • 将数据发送到Reducer。
  • Reduce阶段
    • 聚合所有值,使用集合结构去重,形成唯一元素集合。
  • 调用size()
    • 计算集合大小。
原理:
  • collect_set()收集所有唯一元素到集合中。
  • 需要将所有去重元素集中到Reducer节点,内存压力大
4.2.3 Bitmap去重
执行过程:
  • Map阶段
    • 对每条记录,调用bitmap_add(),将元素映射到bitmap对应的bit位置,置1。
  • Shuffle阶段
    • 将bitmap数据传输到Reducer。
  • Reduce阶段
    • 对多个bitmap做位或(OR)操作,合并所有局部bitmap。
  • 调用bitmap_count()
    • 统计bitmap中置1的位数,即去重元素数量。
原理:
  • 利用bitmap的位标记特性,空间效率高。
  • 支持分布式合并内存占用低
  • 只能统计数量,不能返回具体元素
  • 需要额外安装bitmap相关UDF。

5. Bitmap去重的弊端

  • 只能统计数量,不能直接得到去重元素列表
  • 需要额外配置和安装bitmap相关的UDF或库,不是Hive原生功能。
  • 误差问题:如果使用压缩bitmap或者近似算法(比如HyperLogLog),会有一定误差,不适合对精度要求极高的场景。
  • 不适合元素非常稀疏且范围极大的场景,因为bitmap大小可能很大。

总结

需求场景 推荐方案 备注
小数据量去重 count(distinct)size(collect_set()) 简单方便,性能足够
大数据量精确去重 Bitmap去重 性能好,内存占用低,但需安装扩展
超大数据量近似去重 HyperLogLog等近似算法 牺牲精度换性能
相关推荐
starfalling102433 分钟前
【hive】一种高效增量表的实现
hive
顧棟3 小时前
【Yarn实战】Yarn 2.9.1滚动升级到3.4.1调研与实践验证
hadoop·yarn
D明明就是我5 小时前
Hive 拉链表
数据仓库·hive·hadoop
嘉禾望岗5039 小时前
hive join优化和数据倾斜处理
数据仓库·hive·hadoop
yumgpkpm9 小时前
华为鲲鹏 Aarch64 环境下多 Oracle 数据库汇聚操作指南 CMP(类 Cloudera CDP 7.3)
大数据·hive·hadoop·elasticsearch·zookeeper·big data·cloudera
忧郁火龙果10 小时前
六、Hive的基本使用
数据仓库·hive·hadoop
忧郁火龙果11 小时前
五、安装配置hive
数据仓库·hive·hadoop
chad__chang1 天前
dolphinscheduler安装过程
hive·hadoop
莫叫石榴姐1 天前
字节数开一面
大数据·数据仓库·职场和发展