基于flink快速开发实时TopN程序
转发请注明原创地址:https://www.cnblogs.com/dongxiao-yang/p/9198977.html
TopN 是统计报表和大屏非常常见的功能,主要用来实时计算排行榜。流式的TopN可以使业务方在内存中按照某个统计指标(如出现次数)计算排名并快速出发出更新后的排行榜。
我们以统计词频为例展示一下如何快速开发一个计算TopN的flink程序。
flink支持各种各样的流数据接口作为数据的数据源,本次demo我们采用内置的socketTextStream作为数据数据源。
- StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
- env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime); //以processtime作为时间语义
- DataStream<String> text = env.socketTextStream(hostName, port); //监听指定socket端口作为输入
与离线wordcount类似,程序首先需要把输入的整句文字按照分隔符split成一个一个单词,然后按照单词为key实现累加
- DataStream<Tuple2<String, Integer>> ds = text
- .flatMap(new LineSplitter()); //将输入语句split成一个一个单词并初始化count值为1的Tuple2<String, Integer>类型
- private static final class LineSplitter implements
- FlatMapFunction<String, Tuple2<String, Integer>> {
- @Override
- public void flatMap(String value, Collector<Tuple2<String, Integer>> out) {
- // normalize and split the line
- String[] tokens = value.toLowerCase().split("\\W+");
- // emit the pairs
- for (String token : tokens) {
- if (token.length() > 0) {
- out.collect(new Tuple2<String, Integer>(token, 1));
- }
- }
- }
- }
- DataStream<Tuple2<String, Integer>> wcount = ds
- .keyBy(0) //按照Tuple2<String, Integer>的第一个元素为key,也就是单词
- .window(SlidingProcessingTimeWindows.of(Time.seconds(600),Time.seconds(20)))
- //key之后的元素进入一个总时间长度为600s,每20s向后滑动一次的滑动窗口
- .sum(1);// 将相同的key的元素第二个count值相加
全局TopN
数据流经过前面的处理后会每20s计算一次各个单词的count值并发送到下游窗口
- DataStream<Tuple2<String, Integer>> ret = wcount
- .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(20)))
- //所有key元素进入一个20s长的窗口(选20秒是因为上游窗口每20s计算一轮数据,topN窗口一次计算只统计一个窗口时间内的变化)
- .process(new TopNAllFunction(5));//计算该窗口TopN
windowAll是一个全局并发为1的特殊操作,也就是所有元素都会进入到一个窗口内进行计算。
- private static class TopNAllFunction
- extends
- ProcessAllWindowFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, TimeWindow> {
- private int topSize = 10;
- public TopNAllFunction(int topSize) {
- // TODO Auto-generated constructor stub
- this.topSize = topSize;
- }
- @Override
- public void process(
- ProcessAllWindowFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, TimeWindow>.Context arg0,
- Iterable<Tuple2<String, Integer>> input,
- Collector<Tuple2<String, Integer>> out) throws Exception {
- // TODO Auto-generated method stub
- TreeMap<Integer, Tuple2<String, Integer>> treemap = new TreeMap<Integer, Tuple2<String, Integer>>(
- new Comparator<Integer>() {
- @Override
- public int compare(Integer y, Integer x) {
- // TODO Auto-generated method stub
- return (x < y) ? -1 : 1;
- }
- }); //treemap按照key降序排列,相同count值不覆盖
- for (Tuple2<String, Integer> element : input) {
- treemap.put(element.f1, element);
- if (treemap.size() > topSize) { //只保留前面TopN个元素
- treemap.pollLastEntry();
- }
- }
- for (Entry<Integer, Tuple2<String, Integer>> entry : treemap
- .entrySet()) {
- out.collect(entry.getValue());
- }
- }
- }
分组TopN
在部分场景下,用户希望根据不同的分组进行排序,计算出每个分组的一个排行榜。
- wcount.keyBy(new TupleKeySelectorByStart()) // 按照首字母分组
- .window(TumblingProcessingTimeWindows.of(Time.seconds(20))) //20s窗口统计上游数据
- .process(new TopNFunction(5)) //分组TopN统计
- private static class TupleKeySelectorByStart implements
- KeySelector<Tuple2<String, Integer>, String> {
- @Override
- public String getKey(Tuple2<String, Integer> value) throws Exception {
- // TODO Auto-generated method stub
- return value.f0.substring(0, 1); //取首字母做key
- }
- }
- /**
- *
- *针对keyby window的TopN函数,继承自ProcessWindowFunction
- *
- */
- private static class TopNFunction
- extends
- ProcessWindowFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, String, TimeWindow> {
- private int topSize = 10;
- public TopNFunction(int topSize) {
- // TODO Auto-generated constructor stub
- this.topSize = topSize;
- }
- @Override
- public void process(
- String arg0,
- ProcessWindowFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, String, TimeWindow>.Context arg1,
- Iterable<Tuple2<String, Integer>> input,
- Collector<Tuple2<String, Integer>> out) throws Exception {
- // TODO Auto-generated method stub
- TreeMap<Integer, Tuple2<String, Integer>> treemap = new TreeMap<Integer, Tuple2<String, Integer>>(
- new Comparator<Integer>() {
- @Override
- public int compare(Integer y, Integer x) {
- // TODO Auto-generated method stub
- return (x < y) ? -1 : 1;
- }
- });
- for (Tuple2<String, Integer> element : input) {
- treemap.put(element.f1, element);
- if (treemap.size() > topSize) {
- treemap.pollLastEntry();
- }
- }
- for (Entry<Integer, Tuple2<String, Integer>> entry : treemap
- .entrySet()) {
- out.collect(entry.getValue());
- }
- }
- }
上面的代码实现了按照首字母分组,取每组元素count最高的TopN方法。
嵌套TopN
全局topN的缺陷是,由于windowall是一个全局并发为1的操作,所有的数据只能汇集到一个节点进行 TopN 的计算,那么计算能力就会受限于单台机器,容易产生数据热点问题。
解决思路就是使用嵌套 TopN,或者说两层 TopN。在原先的 TopN 前面,再加一层 TopN,用于分散热点。例如可以先加一层分组 TopN,第一层会计算出每一组的 TopN,而后在第二层中进行合并汇总,得到最终的全网TopN。第二层虽然仍是单点,但是大量的计算量由第一层分担了,而第一层是可以水平扩展的。
基于flink快速开发实时TopN程序的更多相关文章
- Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架
Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的. 历史 Bootstrap 是由 Twitter 的 ...
- 基于NSIS脚本开发的安装程序制作软件:易量安装
原文 基于NSIS脚本开发的安装程序制作软件:易量安装 前几天“萝卜”给我推荐了一款安装程序制作工具——易量安装. 易量安装是一款安装程序制作软件,基于著名的NSIS(Nullsoft Scripta ...
- 基于django快速开发一个网站(一)
基于django快速开发一个网站(一) * 创建虚拟环境.基于虚拟环境创建django==2.0.0和图片加载库和mysql数据库驱动 1. 创建目录并创建虚拟环境 ╰$ mkdir Cornuco ...
- 快速开发微信小程序
image.png 最近婷主在做微信小程序.自己的微信公众号也需要添加点料,乘着这次放假,把微信小程序研究了下.虽然没有做什么很强大的功能,不过好歹自己的公众号也有了微信小程序.够用即可. 1.需要先 ...
- Sublime插件库新成员基于APICloud快速开发跨平台App
互联网时代强调用户体验,那什么是HTML5跨平台App开发者的编程体验?“不剥夺.不替换开发者喜欢的开发工具,就是人性化的用户体验”,APICloud给出了这样的答案! 重磅发布“多开发工具支持策略” ...
- 使用Node.js的socket.io模块开发实时web程序
首发:个人博客,更新&纠错&回复 今天的思维漫游如下:从.net的windows程序开发,摸到nodejs的桌面程序开发,又熟悉了一下nodejs,对“异步”的理解有了上上周对操作系统 ...
- AAuto 快速开发win32小程序
AAuto编程语言 AAuto是专用于桌面软件快速开发的新一代混合型编程语言 - 具有动态语言轻便.灵活.快速开发的特性,而且又可以同时支持静态类型开发,象静态语言那样使用.AAuto可以直接支持原 ...
- Weshop基于Spring Cloud开发的小程序商城系统
WESHOP | 基于微服务的小程序商城系统 Weshop是基于Spring Cloud(Greenwich)开发的小程序商城系统,提供整套公共微服务服务模块,包含用户中心.商品中心.订单中心.营销中 ...
- 如何基于 PHP-X 快速开发一个 PHP 扩展
0x01 起步 PHP-X本身基于C++11开发,使用cmake进行编译配置.首先,你需要确定所有依赖项已安装好.包括: gcc-4.8 或更高版本 PHP7.0 或更高版本,需要php7-dev 开 ...
随机推荐
- 使用git bash 代替cmd
上一文章,用Node.js建HTTP服务器,然后在cmd启动,这次尝试用git bash. git bash 也是命令行工具,画面更好看,使用更方便,可以替代cmd. 下载git:https://gi ...
- 封装log4cp p
log4cpp 是参考 log4j 所写的 c++ 版本的写 log 的库.可以在这里下载 http://log4cpp.sourceforge.net/ 我的使用方法是: 1,定义了一个 _ ...
- Android进阶笔记:AIDL内部实现详解 (一)
AIDL内部实现详解 (一) AIDL的作用是实现跨进程通讯使用方法也非常的简单,他的设计模式是典型的C/S架构.使用AIDL只要在Client端和Server端的项目根目录下面创建一个aidl的文件 ...
- Python结合Shell/Hadoop实现MapReduce
基本流程为: cat data | map | sort | reduce cat devProbe | ./mapper.py | sort| ./reducer.py echo "foo ...
- 又学到一个词REPL
A read–eval–print loop (REPL), also known as an interactive toplevel or language shell 指的是 交互式解释器.
- unity pbr
https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf 参数
- 在Spring3中使用注解(@Scheduled)创建计划任务
Spring3中加强了注解的使用,其中计划任务也得到了增强,现在创建一个计划任务只需要两步就完成了: 创建一个Java类,添加一个无参无返回值的方法,在方法上用@Scheduled注解修饰一下: 在S ...
- jsp el 自定义方法 tld 说明
使用 el 的过程中,需要使用到后端代码处理逻辑,这个时候我们就需要自定义 方法. 如我们后端代码定义如下: package com.rhythmk.common; public class FncH ...
- PHP Warning exec() has been disabled for security reasons怎么办
如果是PHPNOW,还是找到php-apache2handler.ini这个文件,把禁用的函数去掉即可. 注意是这个文件夹
- 【转】Socket状态变迁图
转自:http://www.cnblogs.com/ILove/archive/2008/12/08/1350430.html 服务端,端口的状态变化 先在本机(IP地址为:192.168.1.1 ...