Flink中流式的各种聚合

11.1 MiniBatch 聚合

针对无界聚合算子,说简单点就是把一组输入的数据放到缓存里,减少吞吐的开销 默认情况下,对于无界聚合算子来说,mini-batch 优化是被禁用的。开启这项优化,需要设置选项

复制代码
TableConfig configuration = tEnv.getConfig();
configuration.set("table.exec.mini-batch.enabled", "true"); //开启小批量优化
configuration.set("table.exec.mini-batch.allow-latency", "5 s"); //缓存5秒的输入记录 
configuration.set("table.exec.mini-batch.size", "5000"); // 每个聚合运算符任务可以缓冲的最大记录数

11.2 Local-Global 聚合

Local-Global 聚合是为解决数据倾斜问题提出的,通过将一组聚合分为两个阶段,首先在上游进行本地聚合,然后在下游进行全局聚合,类似于 MapReduce 中的 Combine + Reduce 模式。简单来说就是map端聚合之后reduce处理map端聚合的数据。

复制代码
Configuration configuration = tEnv.getConfig().getConfiguration(); 
configuration.setString("table.exec.mini-batch.enabled", "true"); //本地-全局聚合取决于是否启用了mini-batch 
configuration.setString("table.exec.mini-batch.allow-latency", "5 s"); 
configuration.setString("table.exec.mini-batch.size", "5000"); 
configuration.setString("table.optimizer.agg-phase-strategy", "TWO_PHASE"); //启用两阶段聚合,即local-global聚合

11.3 拆分 distinct 聚合

**使用场景:**Local-Global 优化可有效消除常规聚合的数据倾斜,例如 SUM、COUNT、MAX、MIN、AVG。但是在处理 distinct 聚合时,其性能并不令人满意。

如果 distinct key (即 user_id)的值分布稀疏,则 COUNT DISTINCT 不适合减少数据。即使启用了 local-global 优化也没有太大帮助。因为累加器仍然包含几乎所有原始记录,并且全局聚合将成为瓶颈(大多数繁重的累加器由一个任务处理,即同一天)。

这个优化的想法是将不同的聚合(例如 COUNT(DISTINCT col))分为两个级别。第一次聚合由 group key 和额外的 bucket key 进行 shuffle。bucket key 是使用 HASH_CODE(distinct_key) % BUCKET_NUM 计算的。BUCKET_NUM 默认为1024,可以通过 table.optimizer.distinct-agg.split.bucket-num 选项进行配置。第二次聚合是由原始 group key 进行 shuffle,并使用 SUM 聚合来自不同 buckets 的 COUNT DISTINCT 值。由于相同的 distinct key 将仅在同一 bucket 中计算,因此转换是等效的。bucket key 充当附加 group key 的角色,以分担 group key 中热点的负担。bucket key 使 job 具有可伸缩性来解决不同聚合中的数据倾斜/热点。

类比离线中处理数据倾斜时。将key打散成很多份之后再聚合。

如何开启:

复制代码
tEnv.getConfig() .set("table.optimizer.distinct-agg.split.enabled", "true"); // enable distinct agg split

11.4 在 distinct 聚合上使用 FILTER 修饰符

在某些情况下,用户可能需要从不同维度计算 UV(独立访客)的数量,例如来自 Android 的 UV、iPhone 的 UV、Web 的 UV 和总 UV。很多人会选择 CASE WHEN,例如:

复制代码
SELECT day, 
COUNT(DISTINCT user_id) AS total_uv, 
COUNT(DISTINCT CASE WHEN flag IN ('android', 'iphone') THEN user_id ELSE NULL END) AS app_uv, 
COUNT(DISTINCT CASE WHEN flag IN ('wap', 'other') THEN user_id ELSE NULL END) AS web_uv 
FROM T GROUP BY day

但是,在这种情况下,建议使用 FILTER 语法而不是 CASE WHEN。因为 FILTER 更符合 SQL 标准,并且能获得更多的性能提升。FILTER 是用于聚合函数的修饰符,用于限制聚合中使用的值。将上面的示例替换为 FILTER 修饰符,如下所示:

复制代码
SELECT day, 
COUNT(DISTINCT user_id) AS total_uv, 
COUNT(DISTINCT user_id) FILTER (WHERE flag IN ('android', 'iphone')) AS app_uv, 
COUNT(DISTINCT user_id) FILTER (WHERE flag IN ('wap', 'other')) AS web_uv 
FROM T GROUP BY day

Flink SQL 优化器可以识别相同的 distinct key 上的不同过滤器参数。例如,在上面的示例中,三个 COUNT DISTINCT 都在 user_id 一列上。Flink 可以只使用一个共享状态实例,而不是三个状态实例,以减少状态访问和状态大小。在某些工作负载下,可以获得显著的性能提升。

相关推荐
We་ct几秒前
深度剖析浏览器跨域问题
开发语言·前端·浏览器·跨域·cors·同源·浏览器跨域
skywalk81639 分钟前
在考虑双轨制,即在中文语法的基础上,加上数学公式的支持,这样像很多计算将更加简单方便,就像现在的小学数学课本里面一样,比如:定x=2*x + 1
开发语言
小书房12 分钟前
Kotlin的by
android·开发语言·kotlin·委托·by
就叫飞六吧28 分钟前
QT写一个桌面程序exe并动态打包基本流程(c++)
开发语言·c++
threelab38 分钟前
Three.js 代码云效果 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能
Java小生不才38 分钟前
Spring AI文生音
java·人工智能·spring
V搜xhliang02461 小时前
OpenClaw科研全场景用法:从文献到实验室的完整自动化方案
运维·开发语言·人工智能·python·算法·microsoft·自动化
kaikaile19951 小时前
风、浪、流环境模型的船舶三自由度(纵荡、横荡、艏摇)运动仿真MATLAB
开发语言·人工智能·matlab
fish_xk1 小时前
map和set
java·开发语言
李崧正1 小时前
Java技术分享:Lambda表达式与函数式编程
java·开发语言·python