news 2026/9/19 6:35:51

StarRocks hll_empty 函数详解:为 HLL 列生成空值以补齐导入/插入默认值

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
StarRocks hll_empty 函数详解:为 HLL 列生成空值以补齐导入/插入默认值

StarRocks hll_empty 函数详解:为 HLL 列生成空值以补齐导入/插入默认值

【免费下载链接】starrocksThe world's 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

hll_empty()是 StarRocks 内置的 HLL(HyperLogLog)标量函数,用于生成一个空的 HLL 值,在向包含 HLL 类型列的表中执行INSERT或数据导入(Stream Load 等)时,为无法直接从源数据生成的 HLL 列补齐默认值。本文将结合官方函数文档 hll_empty.md 与 BE 端源码实现,完整讲解其语法、语义、两种典型用法、底层实现原理与配套的 HLL 聚合函数生态,帮助你在 UV 类近似去重场景中正确、高效地使用这一函数。

一、为什么需要 hll_empty

StarRocks 的 HLL 类型列基于 HyperLogLog 算法存储中间结果,只能作为表的 value 列使用,常用于替代COUNT DISTINCT快速计算 UV。HLL 列本身不能由普通数据直接写入,而是通过hll_hash等函数由导入数据或表内其他列转换生成。

但在实际写入中会遇到一种情况:目标表的某列是 HLL 类型,而本次插入或导入的数据中并没有能够用于生成该 HLL 列的源字段。此时就需要用hll_empty()生成一个空的 HLL 值来"占位"补齐,保证写入语句能够完整覆盖表的所有列。这正是该函数在设计上的核心用途——文档将其描述为"Generates an empty HLL column to supplement the default values when inserting or loading data"(生成空的 HLL 列,用于在插入或加载数据时补充默认值)。

在 HLL 数据类型文档 中,hll_empty被列入 HLL 相关函数清单,并明确其用途是"generates empty HLL column and is used to fill in default values during inserts or imports"

二、语法与返回值

hll_empty的语法非常简单,它是一个无参数的标量函数:

HLL_EMPTY()
项目说明
参数
返回值一个空的 HLL 类型值(empty HLL)

返回值可以赋给表中的 HLL 类型列,也可以出现在INSERT ... VALUESINSERT INTO ... SELECT的投影列,以及 Stream Load / Broker Load 等导入任务的columns映射表达式中。

从函数注册信息看,gensrc/script/functions.py 第 829 行将其注册为:

[80030, 'hll_empty', True, False, 'HLL', [], 'HyperloglogFunctions::hll_empty'],

其中参数列表为空[],返回类型为HLL,对应的 BE 端实现入口为HyperloglogFunctions::hll_empty,这与文档中"无参数、返回空 HLL"的描述完全一致。

三、使用场景与完整示例

3.1 场景一:INSERT 时补齐默认值

当执行INSERT语句且表结构包含 HLL 列时,如果源数据中没有可用于生成 HLL 的字段,可用hll_empty()补齐:

insert into hllDemo(k1,v1) values(10,hll_empty());

其中v1为 HLL 类型列,hll_empty()为该列写入一个空 HLL 值。该写法可类比于普通类型的DEFAULT占位,是官方文档给出的标准示例。

3.2 场景二:Stream Load 导入时补齐默认值

数据导入场景更为常见。以下 Stream Load 示例中,源文件的列通过columns参数进行映射:temp1temp2为源文件列,col1hll_hash(temp1)生成,col2则直接用hll_empty()填一个空 HLL:

curl --location-trusted -u <username>:<password> \ -H "columns: temp1, temp2, col1=hll_hash(temp1), col2=hll_empty()" \ -T example7.csv -XPUT \ http://<fe_host>:<fe_http_port>/api/test_db/table7/_stream_load

要点说明:

  • -H "columns: ..."指定源文件列与目标表列的映射关系,列名顺序与源文件 CSV 列一一对应;
  • col1=hll_hash(temp1)表示目标表col1列由源数据temp1通过 HLL 哈希生成;
  • col2=hll_empty()表示目标表col2列(HLL 类型)直接写入空 HLL,无需依赖源文件任何字段;
  • -T example7.csv指定待导入的本地文件;<fe_host>:<fe_http_port>为 FE 的 HTTP 端口地址。

这种"一部分列由源字段哈希生成、一部分列用空 HLL 补齐"的写法,是处理源数据字段与目标表 HLL 列不对等时的标准姿势,可有效避免因 HLL 列无值而导致的导入失败或类型不匹配问题。

3.3 与 hll_hash 的分工

hll_empty与 hll_hash 是 HLL 导入链路中相互配合的两个标量函数:

  • hll_hash(column_name):将某列的值转换为 HLL 类型,映射源数据字段到 HLL 列(hll_hash.md);
  • hll_empty():不依赖任何输入,直接生成一个空 HLL 用于占位。

简单记忆:有源数据可哈希时用hll_hash,没有源数据时用hll_empty

四、底层实现:源码视角看 hll_empty

4.1 BE 端函数实现

hll_empty的向量化实现在 be/src/exprs/hyperloglog_functions.cpp 中,与hll_hashhll_cardinality等函数同属HyperloglogFunctions类(声明见 hyperloglog_functions.h):

// hll_empty StatusOr<ColumnPtr> HyperloglogFunctions::hll_empty(FunctionContext* context, const Columns& columns) { auto p = HyperLogLogColumn::create(); p->append_default(); return ConstColumn::create(std::move(p), 1); }

实现要点:

  • 创建一个HyperLogLogColumn(HLL 类型的对象列容器);
  • 调用append_default()向列中追加一个默认构造的空HyperLogLog对象
  • 将单元素列包装为ConstColumn(常量列),size 为 1。由于结果是常量列,在向量化执行时可以被 StarRocks 高效广播到目标行的所有位置,几乎不产生额外计算开销。

对比同文件中的hll_hash实现可以看到,hll_hash需要对每行调用murmur_hash64A哈希并hll.update(hash),而hll_empty无任何哈希计算,这也是它作为"占位默认值"在性能上的天然优势。

4.2 空 HLL 在存储层的表示

空 HLL 在存储层对应HLL_DATA_EMPTY编码。在 be/src/types/hll.h 中,HyperLogLog的值类型枚举为:

enum HllDataType { HLL_DATA_EMPTY = 0, HLL_DATA_EXPLICIT = 1, HLL_DATA_SPARSE = 2, HLL_DATA_FULL = 3, };

源码注释明确指出:一个 HLL 值会沿着empty -> explicit -> sparse -> full的顺序演进,且不允许回退;这些枚举值会被持久化到存储设备,因此不允许变更已有枚举值。也就是说,由hll_empty()产生的空 HLL 是"最初始、最省空间"的状态,后续只有通过hll_hash/merge等操作写入哈希值后才会升级到HLL_DATA_EXPLICIT等更高形态。

4.3 单测验证

BE 端单元测试 be/test/exprs/hyperloglog_functions_test.cpp 的hllEmptyTest对上述行为做了直接验证:

TEST_F(HyperLogLogFunctionsTest, hllEmptyTest) { { Columns c; auto column = HyperloglogFunctions::hll_empty(ctx, c).value(); ASSERT_TRUE(column->is_constant()); // 结果是常量列 auto* hll = ColumnHelper::get_const_value<TYPE_HLL>(column); ASSERT_EQ(1, hll->empty().size()); // 空 HLL 的序列化大小为 1 字节(类型标识) } }

测试断言hll_empty返回常量列,且其中 HLL 值的empty()序列化大小为 1——这与 hll.h 中HLL_DATA_EMPTY仅需 1 字节记录类型标识的实现一致。

五、存储成本与使用建议

由 HLL 数据类型文档 可知,HLL 的存储空间由哈希值中的去重数量决定,分为三档:

HLL 状态存储成本
空 HLL(无任何值插入)最低,约 80 字节
去重哈希值 ≤ 160最高 1360 字节(80 + 160 × 8)
去重哈希值 > 160固定 16,464 字节(80 + 16 × 1024)

这也再次印证了hll_empty()生成的空 HLL 是所有形态中最省空间的,适合作为默认占位值。在业务使用 HLL 时还应关注以下因素(同样来自 HLL 数据类型文档):

  • 数据量:HLL 返回近似值,数据量越大结果越准确,数据量小则偏差较大;
  • 数据分布:数据量大且 GROUP BY 维列基数很高时,计算会消耗更多内存,此时不推荐使用 HLL;建议用于无 GROUP BY 的去重计数,或对低基数维列做 GROUP BY 的场景;
  • 查询粒度:若查询粒度较大,建议使用聚合表(Aggregate table)或物化视图预聚合,以减小数据量、提升查询速度。

六、与 hll_empty 配套的 HLL 函数族

hll_empty通常不是孤立使用的,它与 HLL 函数族共同构成完整的"写入—聚合—查询"链路:

函数类型作用
hll_hash(column)标量将值转换为 HLL 类型,用于导入映射
hll_empty()标量生成空 HLL,用于插入/导入时补齐默认值
hll_union_agg(hll)聚合估算满足条件的所有数据的基数(总 UV)
hll_raw_agg(hll)聚合聚合 hll 类型字段并返回 hll 类型
hll_cardinality(hll)标量估算单个 hll 列的基数

典型的完整链路是:导入时用hll_hashhll_empty生成 HLL 列 → 通过 Using_HLL.md 中介绍的 Rollup、物化视图或聚合表预聚合 → 查询时用hll_union_agg/hll_cardinality获取近似 UV。在这一链路中,hll_empty保证了"写入端"的完整性,是确保整条链路顺畅运转的兜底组件。

七、小结

hll_empty()是一个体量极小但定位清晰的 HLL 辅助函数:语法上只有一个无参调用,语义上生成最省空间的空 HLL(HLL_DATA_EMPTY),用途上专为INSERT与各类数据导入场景补齐默认值。通过 BE 源码可以看到它在向量化执行中被实现为常量列,几乎零开销;通过单元测试可以确认其输出行为与存储编码完全符合预期。掌握它与hll_hash的分工,再配合hll_union_agghll_raw_agghll_cardinality等聚合与查询函数,即可在 StarRocks 中构建完整、健壮的近似去重(UV 计算)方案。

【免费下载链接】starrocksThe world's 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 6:35:38

SpringBoot+Vue构建个人网盘系统全解析

1. 项目概述这个基于SpringBootVue的个人网盘管理系统&#xff0c;是我在指导计算机专业学生毕业设计时经常遇到的一个经典选题。它本质上是一个轻量级的私有云存储解决方案&#xff0c;能够实现文件上传、下载、分享、分类管理等核心功能。相比市面上的公有云盘服务&#xff0…

作者头像 李华
网站建设 2026/9/19 6:34:31

嵌入式固件下载全解析:从JTAG到OTA的烧录指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 6:34:31

pywinauto实战:同花顺客户端自动化与验证码弹窗处理详解

做桌面端自动化的朋友应该都有同感&#xff1a;Windows 原生应用的自动化跟网页自动化完全不是一回事。我最早接触 pywinauto 这个库&#xff0c;是因为想把同花顺客户端里每天重复的几组固定操作串起来跑。原本以为无非就是“定位控件、发送点击、输入文本”&#xff0c;结果真…

作者头像 李华
网站建设 2026/9/19 6:33:38

Worktrunk:用Git Worktree管理多AI Agent并行开发的CLI实践

过去三周我把自己项目的开发方式彻底改成多 AI Agent 并行工作流之后&#xff0c;几乎每天都在和 Git Worktree 打交道。单个代理时代这个问题根本不存在——一台机器一个工作目录&#xff0c;一个 CLI 工具只要管好眼前的分支就够了&#xff1b;可一旦同时跑三个、五个代理会话…

作者头像 李华
网站建设 2026/9/19 6:32:54

悬置系统设计硬约束:模态规划、刚度曲线与载荷工况解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华