转发请注明原创地址:https://www.cnblogs.com/dongxiao-yang/p/9198977.html

TopN 是统计报表和大屏非常常见的功能,主要用来实时计算排行榜。流式的TopN可以使业务方在内存中按照某个统计指标(如出现次数)计算排名并快速出发出更新后的排行榜。

我们以统计词频为例展示一下如何快速开发一个计算TopN的flink程序。

flink支持各种各样的流数据接口作为数据的数据源,本次demo我们采用内置的socketTextStream作为数据数据源。

  1. StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
  2.  
  3. env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime); //以processtime作为时间语义
  4.  
  5. DataStream<String> text = env.socketTextStream(hostName, port); //监听指定socket端口作为输入

与离线wordcount类似,程序首先需要把输入的整句文字按照分隔符split成一个一个单词,然后按照单词为key实现累加

  1. DataStream<Tuple2<String, Integer>> ds = text
  2. .flatMap(new LineSplitter()); //将输入语句split成一个一个单词并初始化count值为1的Tuple2<String, Integer>类型
  3.  
  4. private static final class LineSplitter implements
  5. FlatMapFunction<String, Tuple2<String, Integer>> {
  6.  
  7. @Override
  8. public void flatMap(String value, Collector<Tuple2<String, Integer>> out) {
  9. // normalize and split the line
  10. String[] tokens = value.toLowerCase().split("\\W+");
  11.  
  12. // emit the pairs
  13. for (String token : tokens) {
  14. if (token.length() > 0) {
  15. out.collect(new Tuple2<String, Integer>(token, 1));
  16. }
  17. }
  18. }
  19. }
  1. DataStream<Tuple2<String, Integer>> wcount = ds
  2. .keyBy(0) //按照Tuple2<String, Integer>的第一个元素为key,也就是单词
  3. .window(SlidingProcessingTimeWindows.of(Time.seconds(600),Time.seconds(20)))
  4. //key之后的元素进入一个总时间长度为600s,每20s向后滑动一次的滑动窗口
  5. .sum(1);// 将相同的key的元素第二个count值相加

全局TopN

数据流经过前面的处理后会每20s计算一次各个单词的count值并发送到下游窗口

  1. DataStream<Tuple2<String, Integer>> ret = wcount
  2. .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(20)))
  3. //所有key元素进入一个20s长的窗口(选20秒是因为上游窗口每20s计算一轮数据,topN窗口一次计算只统计一个窗口时间内的变化)
  4. .process(new TopNAllFunction(5));//计算该窗口TopN

windowAll是一个全局并发为1的特殊操作,也就是所有元素都会进入到一个窗口内进行计算。

  1. private static class TopNAllFunction
  2. extends
  3. ProcessAllWindowFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, TimeWindow> {
  4.  
  5. private int topSize = 10;
  6.  
  7. public TopNAllFunction(int topSize) {
  8. // TODO Auto-generated constructor stub
  9.  
  10. this.topSize = topSize;
  11. }
  12.  
  13. @Override
  14. public void process(
  15. ProcessAllWindowFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, TimeWindow>.Context arg0,
  16. Iterable<Tuple2<String, Integer>> input,
  17. Collector<Tuple2<String, Integer>> out) throws Exception {
  18. // TODO Auto-generated method stub
  19.  
  20. TreeMap<Integer, Tuple2<String, Integer>> treemap = new TreeMap<Integer, Tuple2<String, Integer>>(
  21. new Comparator<Integer>() {
  22.  
  23. @Override
  24. public int compare(Integer y, Integer x) {
  25. // TODO Auto-generated method stub
  26. return (x < y) ? -1 : 1;
  27. }
  28.  
  29. }); //treemap按照key降序排列,相同count值不覆盖
  30.  
  31. for (Tuple2<String, Integer> element : input) {
  32. treemap.put(element.f1, element);
  33. if (treemap.size() > topSize) { //只保留前面TopN个元素
  34. treemap.pollLastEntry();
  35. }
  36. }
  37.  
  38. for (Entry<Integer, Tuple2<String, Integer>> entry : treemap
  39. .entrySet()) {
  40. out.collect(entry.getValue());
  41. }
  42.  
  43. }
  44.  
  45. }

分组TopN

在部分场景下,用户希望根据不同的分组进行排序,计算出每个分组的一个排行榜。

  1. wcount.keyBy(new TupleKeySelectorByStart()) // 按照首字母分组
  2. .window(TumblingProcessingTimeWindows.of(Time.seconds(20))) //20s窗口统计上游数据
  3. .process(new TopNFunction(5)) //分组TopN统计
  1. private static class TupleKeySelectorByStart implements
  2. KeySelector<Tuple2<String, Integer>, String> {
  3.  
  4. @Override
  5. public String getKey(Tuple2<String, Integer> value) throws Exception {
  6. // TODO Auto-generated method stub
  7. return value.f0.substring(0, 1); //取首字母做key
  8. }
  9.  
  10. }
  1. /**
  2. *
  3. *针对keyby window的TopN函数,继承自ProcessWindowFunction
  4. *
  5. */
  6. private static class TopNFunction
  7. extends
  8. ProcessWindowFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, String, TimeWindow> {
  9.  
  10. private int topSize = 10;
  11.  
  12. public TopNFunction(int topSize) {
  13. // TODO Auto-generated constructor stub
  14. this.topSize = topSize;
  15. }
  16.  
  17. @Override
  18. public void process(
  19. String arg0,
  20. ProcessWindowFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, String, TimeWindow>.Context arg1,
  21. Iterable<Tuple2<String, Integer>> input,
  22. Collector<Tuple2<String, Integer>> out) throws Exception {
  23. // TODO Auto-generated method stub
  24.  
  25. TreeMap<Integer, Tuple2<String, Integer>> treemap = new TreeMap<Integer, Tuple2<String, Integer>>(
  26. new Comparator<Integer>() {
  27.  
  28. @Override
  29. public int compare(Integer y, Integer x) {
  30. // TODO Auto-generated method stub
  31. return (x < y) ? -1 : 1;
  32. }
  33.  
  34. });
  35.  
  36. for (Tuple2<String, Integer> element : input) {
  37. treemap.put(element.f1, element);
  38. if (treemap.size() > topSize) {
  39. treemap.pollLastEntry();
  40. }
  41. }
  42.  
  43. for (Entry<Integer, Tuple2<String, Integer>> entry : treemap
  44. .entrySet()) {
  45. out.collect(entry.getValue());
  46. }
  47.  
  48. }
  49.  
  50. }

上面的代码实现了按照首字母分组,取每组元素count最高的TopN方法。

嵌套TopN

全局topN的缺陷是,由于windowall是一个全局并发为1的操作,所有的数据只能汇集到一个节点进行 TopN 的计算,那么计算能力就会受限于单台机器,容易产生数据热点问题。

解决思路就是使用嵌套 TopN,或者说两层 TopN。在原先的 TopN 前面,再加一层 TopN,用于分散热点。例如可以先加一层分组 TopN,第一层会计算出每一组的 TopN,而后在第二层中进行合并汇总,得到最终的全网TopN。第二层虽然仍是单点,但是大量的计算量由第一层分担了,而第一层是可以水平扩展的。


基于flink快速开发实时TopN程序的更多相关文章

  1. Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架

    Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的. 历史 Bootstrap 是由 Twitter 的 ...

  2. 基于NSIS脚本开发的安装程序制作软件:易量安装

    原文 基于NSIS脚本开发的安装程序制作软件:易量安装 前几天“萝卜”给我推荐了一款安装程序制作工具——易量安装. 易量安装是一款安装程序制作软件,基于著名的NSIS(Nullsoft Scripta ...

  3. 基于django快速开发一个网站(一)

    基于django快速开发一个网站(一) *  创建虚拟环境.基于虚拟环境创建django==2.0.0和图片加载库和mysql数据库驱动 1. 创建目录并创建虚拟环境 ╰$ mkdir Cornuco ...

  4. 快速开发微信小程序

    image.png 最近婷主在做微信小程序.自己的微信公众号也需要添加点料,乘着这次放假,把微信小程序研究了下.虽然没有做什么很强大的功能,不过好歹自己的公众号也有了微信小程序.够用即可. 1.需要先 ...

  5. Sublime插件库新成员基于APICloud快速开发跨平台App

    互联网时代强调用户体验,那什么是HTML5跨平台App开发者的编程体验?“不剥夺.不替换开发者喜欢的开发工具,就是人性化的用户体验”,APICloud给出了这样的答案! 重磅发布“多开发工具支持策略” ...

  6. 使用Node.js的socket.io模块开发实时web程序

    首发:个人博客,更新&纠错&回复 今天的思维漫游如下:从.net的windows程序开发,摸到nodejs的桌面程序开发,又熟悉了一下nodejs,对“异步”的理解有了上上周对操作系统 ...

  7. AAuto 快速开发win32小程序

    AAuto编程语言 AAuto是专用于桌面软件快速开发的新一代混合型编程语言 -  具有动态语言轻便.灵活.快速开发的特性,而且又可以同时支持静态类型开发,象静态语言那样使用.AAuto可以直接支持原 ...

  8. Weshop基于Spring Cloud开发的小程序商城系统

    WESHOP | 基于微服务的小程序商城系统 Weshop是基于Spring Cloud(Greenwich)开发的小程序商城系统,提供整套公共微服务服务模块,包含用户中心.商品中心.订单中心.营销中 ...

  9. 如何基于 PHP-X 快速开发一个 PHP 扩展

    0x01 起步 PHP-X本身基于C++11开发,使用cmake进行编译配置.首先,你需要确定所有依赖项已安装好.包括: gcc-4.8 或更高版本 PHP7.0 或更高版本,需要php7-dev 开 ...

随机推荐

  1. 使用git bash 代替cmd

    上一文章,用Node.js建HTTP服务器,然后在cmd启动,这次尝试用git bash. git bash 也是命令行工具,画面更好看,使用更方便,可以替代cmd. 下载git:https://gi ...

  2. 封装log4cp p

    log4cpp 是参考 log4j 所写的 c++ 版本的写 log 的库.可以在这里下载   http://log4cpp.sourceforge.net/   我的使用方法是: 1,定义了一个 _ ...

  3. Android进阶笔记:AIDL内部实现详解 (一)

    AIDL内部实现详解 (一) AIDL的作用是实现跨进程通讯使用方法也非常的简单,他的设计模式是典型的C/S架构.使用AIDL只要在Client端和Server端的项目根目录下面创建一个aidl的文件 ...

  4. Python结合Shell/Hadoop实现MapReduce

    基本流程为: cat data | map | sort | reduce cat devProbe | ./mapper.py | sort| ./reducer.py echo "foo ...

  5. 又学到一个词REPL

    A read–eval–print loop (REPL), also known as an interactive toplevel or language shell 指的是 交互式解释器.

  6. unity pbr

    https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf 参数

  7. 在Spring3中使用注解(@Scheduled)创建计划任务

    Spring3中加强了注解的使用,其中计划任务也得到了增强,现在创建一个计划任务只需要两步就完成了: 创建一个Java类,添加一个无参无返回值的方法,在方法上用@Scheduled注解修饰一下: 在S ...

  8. jsp el 自定义方法 tld 说明

    使用 el 的过程中,需要使用到后端代码处理逻辑,这个时候我们就需要自定义 方法. 如我们后端代码定义如下: package com.rhythmk.common; public class FncH ...

  9. PHP Warning exec() has been disabled for security reasons怎么办

    如果是PHPNOW,还是找到php-apache2handler.ini这个文件,把禁用的函数去掉即可. 注意是这个文件夹

  10. 【转】Socket状态变迁图

    转自:http://www.cnblogs.com/ILove/archive/2008/12/08/1350430.html   服务端,端口的状态变化 先在本机(IP地址为:192.168.1.1 ...