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

资讯详情

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

StarRocks PERCENTILE_APPROX_WEIGHTED 函数详解:带权重的固定内存近似分位数计算

StarRocks PERCENTILE_APPROX_WEIGHTED 函数详解:带权重的固定内存近似分位数计算 StarRocks PERCENTILE_APPROX_WEIGHTED 函数详解带权重的固定内存近似分位数计算【免费下载链接】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本文围绕 StarRocks 聚合函数PERCENTILE_APPROX_WEIGHTED展开先完整讲解该函数的语法、参数约束与典型用法常量权重、列权重、压缩系数、多分位数数组再结合后端聚合函数实现源码TDigest 有符号加权累加、压缩系数惰性初始化、短路径短路格式说明其固定大小内存 权重加权的底层原理帮助你在 tp99/tp95 等高基数统计场景中正确、高效地使用这个函数。函数定位为什么需要带权重的近似分位数PERCENTILE_APPROX_WEIGHTED是PERCENTILE_APPROX的加权版本对每个输入值用户可以指定一个权重常量或数值列再返回指定分位点 p 的近似值。p 的取值范围是 0 到 1可以是单个 DOUBLE 值也可以是ARRAYDOUBLE分位数数组。官方文档对它的两个关键特性给出了明确说明见 percentile_approx_weight.md固定大小内存该函数基于固定内存的摘要结构实现因此在高基数列上计算分位数时内存占用可控典型用途计算 tp99、tp95 等尾延迟/尾分位统计量。需要留意文档标题与函数名的差异文档页标题为percentile_approx_weight但 SQL 中实际可用的函数名是percentile_approx_weighted——这与前端函数注册表 FunctionSet.java 中的常量定义PERCENTILE_APPROX_WEIGHTED percentile_approx_weighted一致。语法与参数说明DOUBLE PERCENTILE_APPROX_WEIGHT(expr, BIGINT weight, DOUBLE|ARRAYDOUBLE p[, DOUBLE compression])参数说明expr要计算分位数的列p分位数值必须是 [0, 1] 范围内的 DOUBLE或是每个元素都在 [0, 1] 范围内的ARRAYDOUBLE。例如 0.99 表示第 99 分位weight权重列必须是正的常量数值或数值列compression可选压缩系数取值范围 [2048, 10000]。值越大精度越高但内存消耗越大、计算耗时越长不指定或超出范围时使用默认值10000前端注册了 4 个内置签名见 FunctionSet.java覆盖了 p 为标量/数组、带/不带 compression 的组合(DOUBLE, BIGINT, DOUBLE) - DOUBLE(DOUBLE, BIGINT, DOUBLE, DOUBLE) - DOUBLE(DOUBLE, BIGINT, ARRAYDOUBLE) - ARRAYDOUBLE(DOUBLE, BIGINT, ARRAYDOUBLE, DOUBLE) - ARRAYDOUBLE对 p 的取值范围前端在计划校验阶段就会报错。AggregateTest.java 中的testPercentileApproxWeightedValidation验证了这一点select percentile_approx_weighted(v1, v2, 1.5) from t0会抛出percentile parameter must be between 0 and 1 in percentile_approx_weighted, but got: 1.5负数同理而weight传常量1、p 传边界值0.0或1.0都是合法用法。使用示例以下示例完整继承自官方文档可直接复现。先建表并插入 5 万行测试数据CREATE TABLE t1 ( c1 int, c2 double, c3 tinyint, c4 int, c5 bigint, c6 largeint, c7 string, c8 double, c9 date, c10 datetime, c11 arrayint, c12 mapdouble, double, c13 structa bigint, b double ) DUPLICATE KEY(c1) DISTRIBUTED BY HASH(c1) BUCKETS 1 PROPERTIES (replication_num 1); insert into t1 select generate_series, generate_series, 11, 111, 1111, 11111, 111111, 1.1, 2024-09-01, 2024-09-01 18:00:00, [1, 2, 3], map(1, 5.5), row(100, 100) from table(generate_series(1, 50000, 3));1. 使用常量值作为权重mysql select percentile_approx_weighted(c1, 1, 0.9) from t1; ---------------------------------------- | percentile_approx_weighted(c1, 1, 0.9) | ---------------------------------------- | 45000.3984375 | ---------------------------------------- 1 row in set (0.07 sec)权重为常量 1 时结果等价于普通PERCENTILE_APPROX的 90 分位可用来做结果对照。2. 使用数值列作为权重mysql select percentile_approx_weighted(c2, c1, 0.5) from t1; ----------------------------------------- | percentile_approx_weighted(c2, c1, 0.5) | ----------------------------------------- | 35355.97265625 | ----------------------------------------- 1 row in set (0.07 sec)3. 显式指定压缩系数mysql select percentile_approx_weighted(c2, c1, 0.5, 10000) from t1; ------------------------------------------------ | percentile_approx_weighted(c2, c1, 0.5, 10000) | ------------------------------------------------ | 35355.97265625 | ------------------------------------------------ 1 row in set (0.09 sec)4. 传入分位数数组一次返回多个分位点mysql select percentile_approx_weighted(c2, c1, [0.1, 0.5, 0.9], 10000) from t1; ------------------------------------------------------------ | percentile_approx_weighted(c2, c1, [0.1, 0.5, 0.9], 10000) | ------------------------------------------------------------ | [15811.6708984375,35355.97265625,47435.01171875] | ------------------------------------------------------------ 1 row in set (0.03 sec)数组模式返回ARRAYDOUBLE元素与输入分位数一一对应0.1、0.5、0.9 分位适合在一条查询中同时拿到 tp50/tp90/tp99 等指标。后端实现权重如何进入 TDigest后端聚合函数实现在 percentile_approx.h。PercentileApproxWeightedAggregateFunction标量 p 版本与PercentileApproxWeightedArrayAggregateFunction数组 p 版本共同继承自PercentileApproxAggregateFunctionBase状态类型为PercentileApproxState内部持有一个PercentileValue摘要对象。1. 权重是 int64逐行加权累加在update主路径中percentile_approx.h权重参数按常量或 int64 列两种形态处理// argument 1: weight can be const or int64 column size_t real_row_num columns[1]-is_constant() ? 0 : row_num; int64_t weight columns[1]-get(real_row_num).get_int64(); ... // add value with weight if (LIKELY(weight ! 0)) { data(state).percentile-add(implicit_castfloat(column_value), weight); }注意两个细节权重为 0 的行会被直接跳过不进入摘要数值在累加前会转换为 float 精度。调用链一路下沉到 TDigestPercentileValue::add(value, weight)中执行_tdigest.add(value, static_castfloat(weight))见 percentile_value.h最终由 tdigest.h 中声明的add(Value x, Weight w)将值 权重作为带权质心合并进摘要结构。这正是加权分位数的数学基础分位数是按权重总和而非行数累积分布计算的。2. 压缩系数的取值与边界基类定义了三组常量percentile_approx.hstatic constexpr double MIN_COMPRESSION 2048.0; static constexpr double MAX_COMPRESSION 10000.0; static constexpr double DEFAULT_COMPRESSION_FACTOR 10000.0;这与文档中compression 范围 [2048, 10000]越界则回退到 10000的说明完全对应。实现上还有一处值得注意的设计get_compression_factorpercentile_approx.h会从最后一个常量参数中解析压缩系数注释明确说明这是为了适配优化器的SplitAggregateRule——该规则会把常量参数下传给 merge 阶段的聚合器因此解析逻辑必须容忍权重为列、p 为常量的参数排布。压缩系数本身采用惰性初始化首次update/merge时才通过reinit_with_compression重建内部的PercentileValue并对超界值记录 WARNING 后回退默认值。3. 函数签名注册后端聚合工厂中注册了 BIGINT 与 DOUBLE 两种expr类型、标量 p 与数组 p 两种形态共 4 条映射见 aggregate_resolver_others.cpp与前端FunctionSet中的 4 个签名一一对应。数组 p 版本采用新的序列化格式[count(4 bytes), q1...qn(8*n bytes), TDigest_data]在分阶段聚合的中间结果中携带完整分位数列表percentile_approx.h保证merge阶段跨实例合并后仍能恢复出全部目标分位点。与 PERCENTILE_APPROX 的对比与使用建议可以结合 percentile_approx 文档 与 percentile_approx.h 中的非加权实现做对比维度PERCENTILE_APPROXPERCENTILE_APPROX_WEIGHTED每行贡献计 1按weightint64正数加权0 权重的行不参与权重参数无第二参数为 BIGINT 常量或列底层摘要同为 TDigest 摘要PercentileValue同左走add(value, weight)带权路径压缩系数默认 10000范围 [2048, 10000]同左内存特征固定大小内存固定大小内存使用建议权重列务必是非负数值列BIGINT 语义负权重虽然能通过类型检查但从源码的加权累加逻辑看其统计含义并不被设计支持权重全为 0 时摘要为空结果无意义在数据量极大的高基数列上计算 tp99 时compression 适当调小如 2048可以显著降低内存与耗时代价是精度下降对精度敏感的场景保持默认 10000 即可需要多个分位点时优先使用ARRAYDOUBLE形式一次算完避免多次扫描近似分位数的结果是近似值文档示例中 45000.3984375 这类非整数值即体现了摘要插值的特性不要把它当作精确分位数做等值断言。小结PERCENTILE_APPROX_WEIGHTED(expr, weight, p[, compression])让 StarRocks 在固定大小内存的前提下支持带权重的近似分位数统计权重可以是常量也可以是列p 支持标量与ARRAYDOUBLE两种形态compression 在 [2048, 10000] 内调节精度与资源的权衡。其实现链路为前端在 FunctionSet.java 注册签名并校验 p 范围后端在 percentile_approx.h 中逐行执行PercentileValue::add(value, weight)最终落到 tdigest.h 的带权质心合并。理解这条调用链后你可以按需选择权重来源、分位点集合与压缩系数在延迟指标等真实业务查询中安全地使用该函数。【免费下载链接】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),仅供参考
返回列表