尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

StarRocks bitmap_union_count 函数:BITMAP 并集基数统计的原理与实战

StarRocks bitmap_union_count 函数:BITMAP 并集基数统计的原理与实战 StarRocks bitmap_union_count 函数BITMAP 并集基数统计的原理与实战【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocksbitmap_union_count是 StarRocks 内置的聚合函数用于对一组 BITMAP 值执行按位或并集合并并返回合并后 BITMAP 的基数cardinality即去重后的元素个数。它常与to_bitmap配合用于网站 UV独立访客、活跃用户数等海量精确去重统计场景从 v2.3 版本开始支持。读完本文你将掌握该函数的语法、参数与返回值约定、与count(distinct)的等价关系、在聚合与窗口分析中的使用方式以及它在 BE 端的底层实现原理。函数概览语法与语义bitmap_union_count属于 BITMAP 系列的聚合函数其语义是先对输入的一组 BITMAP 做并集union再返回并集的基数。这一过程天然去重同一个元素即使出现在多个 BITMAP 中最终也只被计数一次。语法BIGINT bitmap_union_count(BITMAP value)参数说明项目说明value一组 BITMAP 值数据类型必须为 BITMAP。通常由to_bitmap(expr)或bitmap_hash(expr)将普通列转换得到返回值BIGINT 类型表示所有输入 BITMAP 并集后包含的不重复元素个数版本支持从 StarRocks v2.3 开始支持与 count(distinct) 的等价关系当原始列为 INT 等整数类型时先通过to_bitmap将其转换为 BITMAP再用bitmap_union_count聚合其结果与count(distinct col)完全一致但底层采用 BITMAP 按位运算在海量数据与超大体量去重场景下性能显著更优。实战示例基于 BITMAP 的网页 UV 统计沿用官方文档示例假设有一张网页访问表test其中page_id为页面 IDuser_id为访问用户 IDmysql select * from test ------------------ | page_id | user_id | ------------------ | 1 | 1 | | 1 | 2 | | 2 | 1 | ------------------方法一使用 count(distinct) 精确去重mysql select page_id,count(distinct user_id) from test group by page_id; ---------------------------------- | page_id | count(DISTINCT user_id) | ---------------------------------- | 1 | 2 | | 2 | 1 | ----------------------------------方法二使用 bitmap_union_count to_bitmap结果等价mysql select page_id,bitmap_union_count(to_bitmap(user_id)) from test group by page_id; ------------------------------------------------- | page_id | bitmap_union_count(to_bitmap(user_id)) | ------------------------------------------------- | 1 | 2 | | 2 | 1 | -------------------------------------------------两种写法输出一致page 1 有用户 1、2 访问去重后为 2page 2 只有用户 1 访问去重后为 1。区别在于底层实现——后者先将每个user_id编码进 BITMAP再对组内 BITMAP 取并集并计算基数这正是 BITMAP 精确去重precise count distinct的标准写法。典型应用UV / 活跃用户数统计实际业务中最常见的组合是SELECT bitmap_union_count(to_bitmap(user_id)) AS uv FROM user_visit_log WHERE dt 2024-01-01;在多天聚合、多维度分组如按省份、按渠道时同样只需替换GROUP BY维度即可获得任意粒度的精确去重计数。与相邻 BITMAP 函数的搭配使用bitmap_union_count是整个 BITMAP 函数家族中的聚合入口之一与以下函数协同工作构成完整的能力矩阵to_bitmap(expr)将整数等类型列转换为 BITMAP是bitmap_union_count最常用的上游转换函数bitmap_hash(expr)/bitmap_hash64(expr)将字符串等非整数类型散列为 BITMAPbitmap_union对一组 BITMAP 做并集合并但返回的是 BITMAP 本身而非基数是bitmap_union_count的底层版bitmap_count/bitmap_cardinality对单个 BITMAP 求基数bitmap_intersect、bitmap_xor分别实现交集与异或语义的聚合用于留存、差分等分析bitmap_union_int直接对整数列聚合去重的变体。在 FE 侧函数注册表 FunctionSet.java 中BITMAP_UNION_COUNT、TO_BITMAP、BITMAP_UNION、BITMAP_COUNT、BITMAP_UNION_INT、INTERSECT_COUNT等一并注册说明它们在 SQL 分析器中作为一个整体被识别与校验。在窗口函数分析函数中使用由于 BE 端实现中专门提供了update_batch_single_state_with_frame方法见下文源码剖析bitmap_union_count同样可作为窗口函数在滑动/累计窗口内使用例如计算截至当前日的累计 UVSELECT dt, bitmap_union_count(to_bitmap(user_id)) OVER (ORDER BY dt ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cum_uv FROM daily_uv;FE 端的 FunctionAnalyzer.java 对bitmap_union_count等函数在分析场景下的语义做了专门校验确保窗口语义正确。空值与 NULL 语义bitmap_union_count是一个基数统计函数即使输入存在 NULL 或窗口帧为空返回值也恒为 0 而非 NULL。这一行为在 BE 与 FE 两端均有明确声明BE 端实现中is_result_non_nullable()返回true见 bitmap_union_count.h源码注释明确指出bitmap_union_count 是基数统计即使输入可空或窗口帧为空也返回 0绝不返回 NULLFE 端 FunctionSet.java 的alwaysReturnNonNullableFunctions集合中显式列出了BITMAP_UNION_COUNT与 BE 端声明保持一致。因此将bitmap_union_count与普通聚合函数混用时无需额外处理 NULL 兼容问题。源码剖析BE 端如何实现并集与计数bitmap_union_count的核心实现在 BE 端 bitmap_union_count.h 的BitmapUnionCountAggregateFunction类中其设计要点如下聚合状态继承AggregateFunctionBatchHelperBitmapValue, ...即以BitmapValue作为中间聚合状态随行数增长动态合并不保存原始明细数据并集合并update / merge核心逻辑只有一行——this-data(state) | *(col-get_object(row_num))即对当前聚合状态的 BITMAP 与输入 BITMAP 执行按位或OR运算这就是union语义的底层实现。update用于普通聚合单分片内累加merge用于多分片/多节点结果合并两者共用同一 OR 逻辑保证分布式场景下结果一致输出计数finalize / get_values通过value.cardinality()返回 BITMAP 中置位set bit的数量即去重元素个数并写入Int64ColumnBIGINT 输出。get_values变体用于窗口函数批量输出窗口帧支持update_batch_single_state_with_frame按frame_start到frame_end遍历窗口帧内元素逐一 OR 合并这是bitmap_union_count可作为分析函数使用的关键序列化serialize_to_column将中间态 BITMAP 以 BITMAP 类型BitmapColumn随数据流动跨节点传输时仍是 BITMAP 形态最终在合并端统一求基数。在函数注册层aggregate_resolver_minmaxany.cpp 通过以下映射将 SQL 函数名绑定到该实现add_aggregate_mappingTYPE_OBJECT, TYPE_BIGINT, BitmapValue( bitmap_union_count, true, AggregateFactory::MakeBitmapUnionCountAggregateFunction());其中TYPE_OBJECT表示输入为 BITMAP 类型存储为BitmapValueTYPE_BIGINT表示输出类型true表示该聚合支持is_agg_state序列化允许并行聚合与两阶段执行。同一文件中还注册了bitmap_union、bitmap_agg、bitmap_intersect等兄弟函数共享 BITMAP 基础设施。从实现可以看到bitmap_union_count相比count(distinct)的优势本质它把去重计数转化为 BITMAP 的位运算与基数查询空间占用紧凑每一位代表一个元素且 OR 运算天然可并行、可合并非常适合大规模精确去重场景。使用建议与注意事项类型要求入参必须是 BITMAP 类型。若原列为整数类型先用to_bitmap转换若为字符串等类型需先用bitmap_hash/bitmap_hash64散列注意散列函数存在理论上的碰撞概率精确场景建议优先使用整数列 to_bitmap。结果语义返回值是并集的基数即去重后的不重复元素个数若需要并集后的 BITMAP 本身如供后续bitmap_intersect继续处理应改用bitmap_union。NULL 处理结果恒非 NULL空输入返回 0无需额外判空。性能场景相比count(distinct)BITMAP 方案在数据量巨大、去重基数高时内存占用与计算开销更可控同时可与 物化视图/预聚合 等机制结合实现 UV 指标的预计算加速。参考实现与测试入口官方函数文档bitmap_union_count.mdBE 端核心实现bitmap_union_count.hBE 端函数注册aggregate_resolver_minmaxany.cppFE 端函数常量与可空性声明FunctionSet.javaalwaysReturnNonNullableFunctions见同文件第 772-801 行FE 端分析器校验FunctionAnalyzer.java【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表