十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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

StarRocks hll_empty 函数详解:为 HLL 列生成空值以补齐导入/插入默认值 StarRocks hll_empty 函数详解为 HLL 列生成空值以补齐导入/插入默认值【免费下载链接】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/starrockshll_empty()是 StarRocks 内置的 HLLHyperLogLog标量函数用于生成一个空的 HLL 值在向包含 HLL 类型列的表中执行INSERT或数据导入Stream Load 等时为无法直接从源数据生成的 HLL 列补齐默认值。本文将结合官方函数文档 hll_empty.md 与 BE 端源码实现完整讲解其语法、语义、两种典型用法、底层实现原理与配套的 HLL 聚合函数生态帮助你在 UV 类近似去重场景中正确、高效地使用这一函数。一、为什么需要 hll_emptyStarRocks 的 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 ... VALUES、INSERT 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参数进行映射temp1、temp2为源文件列col1由hll_hash(temp1)生成col2则直接用hll_empty()填一个空 HLLcurl --location-trusted -u username:password \ -H columns: temp1, temp2, col1hll_hash(temp1), col2hll_empty() \ -T example7.csv -XPUT \ http://fe_host:fe_http_port/api/test_db/table7/_stream_load要点说明-H columns: ...指定源文件列与目标表列的映射关系列名顺序与源文件 CSV 列一一对应col1hll_hash(temp1)表示目标表col1列由源数据temp1通过 HLL 哈希生成col2hll_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.mdhll_empty()不依赖任何输入直接生成一个空 HLL 用于占位。简单记忆有源数据可哈希时用hll_hash没有源数据时用hll_empty。四、底层实现源码视角看 hll_empty4.1 BE 端函数实现hll_empty的向量化实现在 be/src/exprs/hyperloglog_functions.cpp 中与hll_hash、hll_cardinality等函数同属HyperloglogFunctions类声明见 hyperloglog_functions.h// hll_empty StatusOrColumnPtr HyperloglogFunctions::hll_empty(FunctionContext* context, const Columns columns) { auto p HyperLogLogColumn::create(); p-append_default(); return ConstColumn::create(std::move(p), 1); }实现要点创建一个HyperLogLogColumnHLL 类型的对象列容器调用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_valueTYPE_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)聚合估算满足条件的所有数据的基数总 UVhll_raw_agg(hll)聚合聚合 hll 类型字段并返回 hll 类型hll_cardinality(hll)标量估算单个 hll 列的基数典型的完整链路是导入时用hll_hash或hll_empty生成 HLL 列 → 通过 Using_HLL.md 中介绍的 Rollup、物化视图或聚合表预聚合 → 查询时用hll_union_agg/hll_cardinality获取近似 UV。在这一链路中hll_empty保证了写入端的完整性是确保整条链路顺畅运转的兜底组件。七、小结hll_empty()是一个体量极小但定位清晰的 HLL 辅助函数语法上只有一个无参调用语义上生成最省空间的空 HLLHLL_DATA_EMPTY用途上专为INSERT与各类数据导入场景补齐默认值。通过 BE 源码可以看到它在向量化执行中被实现为常量列几乎零开销通过单元测试可以确认其输出行为与存储编码完全符合预期。掌握它与hll_hash的分工再配合hll_union_agg、hll_raw_agg、hll_cardinality等聚合与查询函数即可在 StarRocks 中构建完整、健壮的近似去重UV 计算方案。【免费下载链接】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),仅供参考
返回列表