Flink--连接(Join)

本文详细介绍了Apache Flink中的五种连接操作:Window Join、Tumbling Window Join、Sliding Window Join、Session Window Join以及Interval Join。通过实例解析了各种连接方式的工作原理,包括窗口定义、数据匹配条件以及连接函数的使用。重点阐述了每种连接类型的特点和适用场景,如滚动窗口的内连接特性,滑动窗口的数据对齐,会话窗口的动态窗口定义,以及间隔连接的时间范围约束。
摘要由CSDN通过智能技术生成

Window Join(窗口连接)
窗口连接是指将同一个窗口中的两个流数据通过同一个key连接起来。这些窗口可以使用Window Assigner定义,并根据两个流中的数据进行计算。
连接两边的数据被传给一个用户定义好的JoinFunction或者FlatJoinFunction,将满足条件的结果数据输出来。
通用用法总结如下:

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

语法上的一些注意点:

  • 两个流元素的成对组合的创建就像是内连接,这意味着如果一个流中的元素没有来自另一个流的相应元素要连接,则不会输出它们。
  • 那些连接上的数据会将窗口的最大时间戳作为他们的时间戳。例如一个[5, 10)的窗口,将会导致连接上的数据将9作为他们的时间戳。
    接下来的部分我们将通过例子大概介绍一下不同的join类型是如何工作的。

Tumbling Window Join(滚动窗口连接)
当使用滚动窗口连接时,同一个滚动窗口内的相同join key的数据会被连接成对并且传递给一个JoinFunction或者FlatJoinFunction。因为这就像内连接,因此滚动窗口内一个流的数据在另一个流中没有相对应的数据时将不会被输出。
在这里插入图片描述
就像图中所描述的,我们定义一个2毫秒的滚动窗口,形成的窗口诸如[0,1], [2,3] …。该图显示了每个窗口中所有数据的联队组合,这些数据将传递给JoinFunction。注意在滚动窗口[6,7],什么都不会输出,因为在绿色的窗口中没有数据可以和橙色的窗口中的数据连接。

import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
 
...

DataStream<Integer> orangeStream = ...
DataStream<Integer> greenStream = ...

orangeStream.join(greenStream)
    .where(<KeySelector>)
    .equalTo(<KeySelector>)
    .window(TumblingEventTimeWindows.of(Time.milliseconds(2)))
    .apply (new JoinFunction<Integer, Integer, String> (){
        @Override
        public String join(Integer first, Integer second) {
            return first + "," + second;
        }
    });

Sliding Window Join(滑动窗口)
当使用滑动窗口连接时,同一个滚动窗口内的相同join key的数据会被连接成对并且传递给一个JoinFunction或者FlatJoinFunction。当前滑动窗口中,在一个窗口总存在而在另一个窗口中不存在的数据将不会被输出。注意一些数据可能在一个滑动窗口中可以被连接上,但是在另一个窗口却连接不上。
在这里插入图片描述
在这个例子中,我们使用一个每毫秒滑动一次的2毫秒窗口,会生成诸如[-1, 0],[0,1],[1,2],[2,3]…的窗口。X轴下面的数据是会在每个滑动窗口内被传递给JoinFunction的。这里你也可以看到,比如,在窗口[2,3]橙色的2是如何跟绿色的3连接的,然而在窗口[1,2]中2却没有连接上。

import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

...

DataStream<Integer> orangeStream = ...
DataStream<Integer> greenStream = ...

orangeStream.join(greenStream)
    .where(<KeySelector>)
    .equalTo(<KeySelector>)
    .window(SlidingEventTimeWindows.of(Time.milliseconds(2) /* size */, Time.milliseconds(1) /* slide */))
    .apply (new JoinFunction<Integer, Integer, String> (){
        @Override
        public String join(Integer first, Integer second) {
            return first + "," + second;
        }
    });

Session Window Join(会话窗口连接)
当使用会话窗口连接时,如果连接满足会话条件,则所有的相同join key的数据被成对连接并传递给了JoinFunction和FlatJoinFunction。这次又是一个内连接,因此如果只有一个会话窗口包含数据而另一个不包含,就不会有输出。
在这里插入图片描述
这里我们定义一个每个会话被至少1ms的gap分割的会话窗口连接。这里有三个会话,头两个会话中两个流中的连接数据被传递给了JoinFunction。在第三个会话中,在绿色的流中没有数据,因此8和9不会被连接。
``
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.windowing.assigners.EventTimeSessionWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

DataStream<Integer> orangeStream = ...
DataStream<Integer> greenStream = ...

orangeStream.join(greenStream)
    .where(<KeySelector>)
    .equalTo(<KeySelector>)
    .window(EventTimeSessionWindows.withGap(Time.milliseconds(1)))
    .apply (new JoinFunction<Integer, Integer, String> (){
        @Override
        public String join(Integer first, Integer second) {
            return first + "," + second;
        }
    });

Interval Join(间隔连接)
间隔连接通过一个共同的key连接两个流(A&B)中的数据,流 B 的数据具有时间戳位于流 A 中元素的相对时间间隔中。
这也可以更正式地表达成 b.timestamp ∈ [a.timestamp + lowerBound; a.timestamp + upperBound] 或者 a.timestamp + lowerBound <= b.timestamp <= a.timestamp + upperBound
a和b是A,B流中有共同key的数据。只要满足下界(lowerBound)小于等于上界(upperBound),下界和上界都是可以是正数或者负数。间隔连接目前只支持内连接。
当一对数据被传递给了ProcessJoinFunction,他们会被指定为两个数据中更大的时间戳(可以通过ProcessJoinFunction.Context访问)。
间隔连接目前只支持事件时间。
在这里插入图片描述
在上面的例子中,我们连接两个‘绿色’和‘橙色’的数据流,下界是-2ms,上界是1ms。默认情况下,这些界限是包含在内的,但是可以通过使用lowerBoundExclusive() 或者upperBoundExclusive()函数修改。
再次使用更正式的形式,可以将图中的三角形表示为:
orangeElem.ts + lowerBound <= greenElem.ts <= orangeElem.ts + upperBound

import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.functions.co.ProcessJoinFunction;
import org.apache.flink.streaming.api.windowing.time.Time;

...

DataStream<Integer> orangeStream = ...
DataStream<Integer> greenStream = ...

orangeStream
    .keyBy(<KeySelector>)
    .intervalJoin(greenStream.keyBy(<KeySelector>))
    .between(Time.milliseconds(-2), Time.milliseconds(1))
    .process (new ProcessJoinFunction<Integer, Integer, String(){

        @Override
        public void processElement(Integer left, Integer right, Context ctx, Collector<String> out) {
            out.collect(first + "," + second);
        }
    });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值