• 【翻译】Flink Joining


    本文来自官网翻译: Joining

    Window Join

    窗口join 连接两个共享公共key 并位于同一窗口中的流的元素。可以使用窗口分配器定义这些窗口,两个流的元素都会触发。

    然后将来自双方的元素传递给用户定义的 JoinFunction或者FlatJoinFunction,用户可以发出满足连接条件的结果。

    一般用法可归纳如下:

    stream.join(otherStream)
        .where(<KeySelector>)
        .equalTo(<KeySelector>)
        .window(<WindowAssigner>)
        .apply(<JoinFunction>)

    关于语义的一些注释:

    • 两个流的元素的成对组合的表现像内连接,意味着如果它们没有来自要连接的另一个流的对应元素,则不会发出来当前流的元素。
    • 那些加入的元素将在其时间戳包含于相应窗口中的最大时间戳中。例如,[5, 10)具有其边界的窗口将导致连接的元素具有9作为其时间戳。

    在下一节中,我们将使用一些示例性场景概述不同类型的窗口连接的行为。

    Tumbling Window Join

    当执行翻滚窗口join时,具有相同key和相同翻滚窗口的所有元素作为成对组合被连接并传递给JoinFunctionFlatJoinFunction因为它的行为类似于内连接,所以一个流的元素在其翻滚窗口中没有来自另一个流的元素是不会发出的。

    如图所示,我们定义了一个大小为2毫秒的翻滚窗口,这导致了窗体的窗口[0,1], [2,3], ... 图像显示了每个窗口中所有元素的成对组合,这些元素将被传递给JoinFunction请注意,在翻滚窗口中[6,7]没有任何物体被发出,因为绿色流中不存在与橙色元素⑥和⑦连接的元素。

    import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows;
    import org.apache.flink.streaming.api.windowing.time.Time;
    
    ...
    
    val orangeStream: DataStream[Integer] = ...
    val greenStream: DataStream[Integer] = ...
    
    orangeStream.join(greenStream)
        .where(elem => /* select key */)
        .equalTo(elem => /* select key */)
        .window(TumblingEventTimeWindows.of(Time.milliseconds(2)))
        .apply { (e1, e2) => e1 + "," + e2 }

    Sliding Window Join

     执行滑动窗口连接时,具有相同key和相同滑动窗口的所有元素将作为成对组合连接并传递给JoinFunctionFlatJoinFunction当前滑动窗口中没有来自对应流的元素时,流元素不会发出!请注意,某些元素可能在一个滑动窗口中连接而在另一个滑块窗口中不连接。

     

    在这个例子中,我们使用大小为2毫秒的滑动窗口并将它们滑动一毫秒,从而产生滑动窗口[-1, 0],[0,1],[1,2],[2,3], …x轴下方的连接元素是传递给JoinFunction每个滑动窗口的元素在这里,您还可以看到橙色②与窗口中的绿色③  在窗口[2,3]连接,但未与任何内容在窗口[1,2] 连接

    import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows;
    import org.apache.flink.streaming.api.windowing.time.Time;
    
    ...
    
    val orangeStream: DataStream[Integer] = ...
    val greenStream: DataStream[Integer] = ...
    
    orangeStream.join(greenStream)
        .where(elem => /* select key */)
        .equalTo(elem => /* select key */)
        .window(SlidingEventTimeWindows.of(Time.milliseconds(2) /* size */, Time.milliseconds(1) /* slide */))
        .apply { (e1, e2) => e1 + "," + e2 }

    Session Window Join

    在执行会话窗口连接时,具有相同键的所有元素“组合”满足会话条件时以成对组合方式连接并传递给JoinFunctionFlatJoinFunction同样,这会执行内连接,因此如果存在仅包含来自一个流的元素的会话窗口,则不会发出任何输出!

     

    这里我们定义一个会话窗口连接,其中每个会话除以至少1ms的间隙。有三个会话,在前两个会话中,两个流的连接元素都传递给JoinFunction在第三阶段,绿色流中没有元素,所以⑧和⑨没有连接!

    import org.apache.flink.streaming.api.windowing.assigners.EventTimeSessionWindows;
    import org.apache.flink.streaming.api.windowing.time.Time;
     
    ...
    
    val orangeStream: DataStream[Integer] = ...
    val greenStream: DataStream[Integer] = ...
    
    orangeStream.join(greenStream)
        .where(elem => /* select key */)
        .equalTo(elem => /* select key */)
        .window(EventTimeSessionWindows.withGap(Time.milliseconds(1)))
        .apply { (e1, e2) => e1 + "," + e2 }

    Interval Join

    (时间)间隔连接使用公共密钥连接两个流的元素(我们现在称它们为A和B),并且流B的元素具有时间戳,该时间戳位于流A中元素的时间戳的相对时间间隔中。

    这也可以更正式地表达为 

    b.timestamp ∈ [a.timestamp + lowerBound; a.timestamp + upperBound]
    或 
    a.timestamp + lowerBound <= b.timestamp <= a.timestamp + upperBound

    其中a和b是共享相同key 的A和B的元素。只要下限总是小于或等于上限,下限和上限都可以是负数或正数。间隔连接当前仅支持内连接。

    当一对元素传递给ProcessJoinFunction它们时,它们将被赋予ProcessJoinFunction.Context两个元素较大的时间戳(可以通过它访问)。

    注意:时间间隔连接当前仅支持事件时间。

    在上面的例子中,我们连接两个流'orange'和'green',下限为-2毫秒,上限为+1毫秒。缺省情况下,这些界限是包容性的(包含上下界),方法lowerBoundExclusive()和upperBoundExclusive可以改变应用行为。

    再次使用更正式的符号,这将转化为

    orangeElem.ts + lowerBound <= greenElem.ts <= orangeElem.ts + upperBound

    如上图三角形所示。

    import org.apache.flink.streaming.api.functions.co.ProcessJoinFunction;
    import org.apache.flink.streaming.api.windowing.time.Time;
    
    ...
    
    val orangeStream: DataStream[Integer] = ...
    val greenStream: DataStream[Integer] = ...
    
    orangeStream
        .keyBy(elem => /* select key */)
        .intervalJoin(greenStream.keyBy(elem => /* select key */))
        .between(Time.milliseconds(-2), Time.milliseconds(1))
        .process(new ProcessJoinFunction[Integer, Integer, String] {
            override def processElement(left: Integer, right: Integer, ctx: ProcessJoinFunction[Integer, Integer, String]#Context, out: Collector[String]): Unit = {
             out.collect(left + "," + right); 
            }
          });
        });
  • 相关阅读:
    Debug和Release版本区别
    清空模拟器中的app
    在项目中移除CocoaPods
    设置导航栏 self.navigationItem.titleView 居中
    Verify the Developer App certificate for youraccount is trusted on your device
    字典转json
    self.navigationController.navigationBar.translucent = YES航栏的属性默认 YES是透明效果并且主view不会偏移 NO是导航栏不透明 主view会向下偏移64px
    归档-对模型数组对象(存储到本地的plist文件)也数组里存放的是模型
    FMDB存储模型对象(以二进制存储)用NSKeyedArchiver archivedDataWithRootObject序列号,NSKeyedUnarchiver unarchiveObjectWithData反序列化(重点坑是sql语句@"insert into t_newsWithChannel (nwesName,newsType) values (?,?)")一定要用占位符
    根据日期计算发布时间段(NSCalendar)
  • 原文地址:https://www.cnblogs.com/Springmoon-venn/p/11131185.html
Copyright © 2020-2023  润新知