使用方式,

  1. dataStream.coGroup(otherStream)
  2. .where(0).equalTo(1)
  3. .window(TumblingEventTimeWindows.of(Time.seconds(3)))
  4. .apply (new CoGroupFunction () {...});

 

可以看到coGroup只是产生CoGroupedStreams

  1. public <T2> CoGroupedStreams<T, T2> coGroup(DataStream<T2> otherStream) {
  2. return new CoGroupedStreams<>(this, otherStream);
  3. }

 

而where, equalTo只是添加keySelector,对于两个流需要分别指定

  1. keySelector1keySelector2

 

window设置双流的窗口,很容易理解

 

apply,

  1. /**
  2. * Completes the co-group operation with the user function that is executed
  3. * for windowed groups.
  4. *
  5. * <p>Note: This method's return type does not support setting an operator-specific parallelism.
  6. * Due to binary backwards compatibility, this cannot be altered. Use the
  7. * {@link #with(CoGroupFunction, TypeInformation)} method to set an operator-specific parallelism.
  8. */
  9. public <T> DataStream<T> apply(CoGroupFunction<T1, T2, T> function, TypeInformation<T> resultType) {
  10. //clean the closure
  11. function = input1.getExecutionEnvironment().clean(function);
  12.  
  13. UnionTypeInfo<T1, T2> unionType = new UnionTypeInfo<>(input1.getType(), input2.getType());
  14. UnionKeySelector<T1, T2, KEY> unionKeySelector = new UnionKeySelector<>(keySelector1, keySelector2);
  15.  
  16. DataStream<TaggedUnion<T1, T2>> taggedInput1 = input1 //将input1封装成TaggedUnion,很简单,就是赋值到one上
  17. .map(new Input1Tagger<T1, T2>())
  18. .setParallelism(input1.getParallelism())
  19. .returns(unionType);
  20. DataStream<TaggedUnion<T1, T2>> taggedInput2 = input2 //将input2封装成TaggedUnion
  21. .map(new Input2Tagger<T1, T2>())
  22. .setParallelism(input2.getParallelism())
  23. .returns(unionType);
  24.  
  25. DataStream<TaggedUnion<T1, T2>> unionStream = taggedInput1.union(taggedInput2); //由于现在双流都是TaggedUnion类型,union成一个流,问题被简化
  26.  
  27. // we explicitly create the keyed stream to manually pass the key type information in
  28. WindowedStream<TaggedUnion<T1, T2>, KEY, W> windowOp = //创建窗口
  29. new KeyedStream<TaggedUnion<T1, T2>, KEY>(unionStream, unionKeySelector, keyType)
  30. .window(windowAssigner);
  31.  
  32. if (trigger != null) { //如果有trigger,evictor,设置上
  33. windowOp.trigger(trigger);
  34. }
  35. if (evictor != null) {
  36. windowOp.evictor(evictor);
  37. }
  38.  
  39. return windowOp.apply(new CoGroupWindowFunction<T1, T2, T, KEY, W>(function), resultType); //调用window的apply
  40. }

关键理解,他要把两个流变成一个流,这样问题域就变得很简单了

最终调用到WindowedStream的apply,apply是需要保留window里面的所有原始数据的,和reduce不一样

apply的逻辑,是CoGroupWindowFunction

 

  1. private static class CoGroupWindowFunction<T1, T2, T, KEY, W extends Window>
  2. extends WrappingFunction<CoGroupFunction<T1, T2, T>>
  3. implements WindowFunction<TaggedUnion<T1, T2>, T, KEY, W> {
  4.  
  5. private static final long serialVersionUID = 1L;
  6.  
  7. public CoGroupWindowFunction(CoGroupFunction<T1, T2, T> userFunction) {
  8. super(userFunction);
  9. }
  10.  
  11. @Override
  12. public void apply(KEY key,
  13. W window,
  14. Iterable<TaggedUnion<T1, T2>> values,
  15. Collector<T> out) throws Exception {
  16.  
  17. List<T1> oneValues = new ArrayList<>();
  18. List<T2> twoValues = new ArrayList<>();
  19.  
  20. for (TaggedUnion<T1, T2> val: values) {
  21. if (val.isOne()) {
  22. oneValues.add(val.getOne());
  23. } else {
  24. twoValues.add(val.getTwo());
  25. }
  26. }
  27. wrappedFunction.coGroup(oneValues, twoValues, out);
  28. }
  29. }
  30. }

逻辑也非常的简单,就是将该key所在window里面的value,放到oneValues, twoValues两个列表中

最终调用到用户定义的wrappedFunction.coGroup

 

DataStream.join就是用CoGroup实现的

  1. return input1.coGroup(input2)
  2. .where(keySelector1)
  3. .equalTo(keySelector2)
  4. .window(windowAssigner)
  5. .trigger(trigger)
  6. .evictor(evictor)
  7. .apply(new FlatJoinCoGroupFunction<>(function), resultType);

 

FlatJoinCoGroupFunction

  1. private static class FlatJoinCoGroupFunction<T1, T2, T>
  2. extends WrappingFunction<FlatJoinFunction<T1, T2, T>>
  3. implements CoGroupFunction<T1, T2, T> {
  4. private static final long serialVersionUID = 1L;
  5.  
  6. public FlatJoinCoGroupFunction(FlatJoinFunction<T1, T2, T> wrappedFunction) {
  7. super(wrappedFunction);
  8. }
  9.  
  10. @Override
  11. public void coGroup(Iterable<T1> first, Iterable<T2> second, Collector<T> out) throws Exception {
  12. for (T1 val1: first) {
  13. for (T2 val2: second) {
  14. wrappedFunction.join(val1, val2, out);
  15. }
  16. }
  17. }
  18. }

可以看出当前join是inner join,必须first和second都有的情况下,才会调到用户的join函数

Flink - CoGroup的更多相关文章

  1. Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树

    Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树 目录 Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树 0x00 摘要 0x01 背景概念 1.1 词向量基础 ...

  2. Flink学习笔记:Operators之CoGroup及Join操作

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

  3. Flink入门 - CoGroup和Join

    /* *CoGroup */ final StreamExecutionEnvironment streamExecutionEnvironment = StreamExecutionEnvironm ...

  4. Flink实例(五十): Operators(十)多流转换算子(五)coGroup 与union

    参考链接:https://mp.weixin.qq.com/s/BOCFavYgvNPSXSRpBMQzBw 需求场景分析 需求场景 需求诱诱诱来了...数据产品妹妹想要统计单个短视频粒度的「点赞,播 ...

  5. Flink Program Guide (2) -- 综述 (DataStream API编程指导 -- For Java)

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  6. Flink Program Guide (1) -- 基本API概念(Basic API Concepts -- For Java)

    false false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable {mso-style-n ...

  7. Flink从入门到放弃(入门篇3)-DataSetAPI

    戳更多文章: 1-Flink入门 2-本地环境搭建&构建第一个Flink应用 3-DataSet API 4-DataSteam API 5-集群部署 6-分布式缓存 7-重启策略 8-Fli ...

  8. Flink Java Demo(Windows)

    关于Flink相关的概念性东西就不说了,网上都有,官网也很详尽.本文主要记录一下Java使用Flink的简单例子. 首先,去官网下载Flink的zip包(链接就不提供了,你已经是个成熟的程序员了,该有 ...

  9. Flink官网文档翻译

    http://ifeve.com/flink-quick-start/ http://vinoyang.com/2016/05/02/flink-concepts/ http://wuchong.me ...

随机推荐

  1. (转)Linux服务器磁盘空间占满问题

    转自:https://www.cnblogs.com/cindy-cindy/p/6796684.html 下面我们一起来看一篇关于Linux服务器磁盘占满问题解决(/dev/sda3 满了),希望碰 ...

  2. ElasticSearch 内存那点事【转】

    “该给ES分配多少内存?” “JVM参数如何优化?““为何我的Heap占用这么高?”“为何经常有某个field的数据量超出内存限制的异常?““为何感觉上没多少数据,也会经常Out Of Memory? ...

  3. TWELP™ Vocoder

    TWELP™ Vocoder   DSP Innovations Inc. (DSPINI) announces new class of proprietary vocoders for wide ...

  4. 图像处理滤波应用(Halcon)

    1.增强对比度:halcon算子 equ_histo_image (GrayImage, ImageEquHisto) 2.空间滤波基础 滤波指接受或拒绝一定的频率分量.低通滤波器的最终效果是模糊(平 ...

  5. CSS实现响应式全屏背景图

    body { /* 加载背景图 */ background-image: url(images/background-photo.jpg); /* 背景图垂直.水平均居中 */ background- ...

  6. 第四百零一节,Django+Xadmin打造上线标准的在线教育平台—生产环境部署virtualenv虚拟环境安装,与Python虚拟环境批量安装模块

    第四百零一节,Django+Xadmin打造上线标准的在线教育平台—生产环境部署virtualenv虚拟环境安装,与Python虚拟环境批量安装模块 virtualenv简介 1.安装virtuale ...

  7. 开源项目收集:博客系统solo

    前言 一个好的项目,我不会吝啬于推荐之语.找了好久,想要一个最简单的个人博客.由于个人不怎么会写前端页面,怎么也看不到漂亮的设计.没有漂亮的前台都不知道后台需要写一些什么! 这个项目至少目前满足了我的 ...

  8. iOS中 支付宝钱包具体解释/第三方支付 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博! iOS开发人员交流QQ群: 446310206 一.在app中成功完毕支付宝支付的过程 1.申请支付宝钱包.參考网 ...

  9. IntelliJ IDEA下spring boot项目打包

    Spring Boot自带Tomcat插件,可以直接编写启动类,开启Tomcat服务 springboot适合前后端分离,打成jar进行部署更合适 application.properties配置端口 ...

  10. 12外观模式Facade

    一.什么是外观模式 Facade模式也叫外观模式,是由GoF提出的 23种设计模式中的一种.Facade模式为一组具 有类似功能的类群,比如类库,子系统等等,提供一个一致的简单的界面.这个一致的简单的 ...