FLINK 合流

在Apache Flink中,合流(Co-streaming)是指将两条或多条数据流合并成一条数据流的操作。这种操作在实际应用中非常普遍,特别是在需要联合处理来自不同源头的数据时。Flink提供了多种合流方式,以满足不同的数据处理需求。以下是对Flink合流的详细介绍:

1. 联合(Union)

  • 定义:直接将多条数据类型相同的数据流合在一起,合并后的新流会包括所有流中的元素,数据类型不变。
  • 操作:基于DataStream直接调用.union()方法,传入其他DataStream作为参数。
  • 示例:stream1.union(stream2, stream3, ...)。
  • 注意事项:联合操作要求流中的数据类型必须相同。合并后的流中,每个数据项都保留了其原始来源流的属性,但数据类型保持不变。此外,多流合并时处理的时效性是以最慢的那个流为准的。

2. 连接(Connect)

  • 定义:将两条数据流像接线一样对接起来,允许流的数据类型不同。连接得到的不是DataStream,而是一个"连接流"(ConnectedStreams)。
  • 操作:使用.connect()方法将两条流连接起来。
  • 特点:连接流可以看成是两条流形式上的"统一",被放在了一个同一个流中,但内部仍保持各自的数据形式不变,彼此之间是相互独立的。连接操作允许在两条流的处理逻辑之间共享状态。
  • 后续处理:连接后,可以使用.map()、.flatMap()、.process()等算子对连接流进行处理,但各处理各的,不会直接合并成一条流。

3. 基于时间的合流(Join)

  • 定义:根据时间戳和键(key)将两条数据流中的相关事件进行匹配和合并。
  • 类型
    • 窗口Join :要求落在同一个时间窗口范围内的数据才能匹配。根据keyBy的key来进行关联匹配,只能拿到匹配上的数据,类似有固定时间范围的inner join。
      • 窗口联结使用方式:
        • 使用join()方法将两个数据流连接起来。
        • 使用where()和equalTo()方法指定连接条件,即基于哪个键进行匹配。
        • 使用window()方法指定时间窗口的类型和大小。
        • 使用apply()方法传入一个JoinFunction来处理匹配的数据对。
    • 间隔联结(Interval Join) :每一条数据自身都开辟一个区间,在对方的区间内进行查找。支持事件时间,并指定上界和下界的边界。只能处理join上的数据,对于迟到数据(即当前数据的事件时间小于当前的watermark)会放入侧输出流。
      • 间隔联结使用方式:
        • 先使用keyBy()方法对两个数据流进行键分区。
        • 使用intervalJoin()方法将两个数据流连接起来,并指定时间间隔的上下界。
        • 使用process()方法传入一个ProcessJoinFunction来处理匹配的数据对。
  • 注意事项:基于时间的合流要求数据流具有时间戳和watermark,以便进行准确的时间匹配。

4. CoGroup

  • 定义:一种更通用的合流方式,允许对两条数据流中的元素进行分组和聚合处理。
  • 操作:使用.coGroup()方法,并指定一个CoGroupFunction来实现自定义的分组和聚合逻辑。
  • 使用方式
    在Flink中,可以使用DataStream API提供的coGroup方法来实现CoGroup操作。具体使用方式如下:
    1. 准备数据流:首先,需要准备两个要合并的数据流。这两个数据流可以来自不同的数据源,也可以是对同一个数据源进行不同处理后的结果。
    2. 指定键:使用where和equalTo方法指定用于分组的键。这两个方法分别用于指定第一个数据流和第二个数据流中的键。
    3. 窗口化(可选):为了进行基于时间的分组处理,可以使用window方法指定一个时间窗口。这样,只有落在同一个时间窗口内的元素才会被分组到一起。
    4. 应用CoGroupFunction:最后,使用apply方法传入一个CoGroupFunction来处理分组后的数据。CoGroupFunction是一个抽象类,需要实现其coGroup方法来定义如何处理分组后的数据。

示例

联合(Union)

java 复制代码
import org.apache.flink.api.common.functions.MapFunction;  
import org.apache.flink.streaming.api.datastream.DataStream;  
import org.apache.flink.streaming.api.datastream.DataStreamSource;  
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;  
  
public class FlinkUnionExample {  
    public static void main(String[] args) throws Exception {  
        // 创建执行环境  
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();  
          
        // 创建两个数据流  
        DataStreamSource<Integer> stream1 = env.fromElements(1, 2, 3, 4, 5);  
        DataStreamSource<Integer> stream2 = env.fromElements(6, 7, 8, 9, 10);  
          
        // 使用union()方法将两个数据流合并成一个新的数据流  
        DataStream<Integer> unionedStream = stream1.union(stream2);  
          
        // 打印合并后的数据流  
        unionedStream.print();  
          
        // 执行程序  
        env.execute("Flink Union Example");  
    }  
}

连接(Connect)

java 复制代码
import org.apache.flink.api.common.functions.CoMapFunction;  
import org.apache.flink.streaming.api.datastream.DataStream;  
import org.apache.flink.streaming.api.datastream.DataStreamSource;  
import org.apache.flink.streaming.api.datastream.ConnectedStreams;  
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;  
import org.apache.flink.util.Collector;  
  
public class FlinkConnectExample {  
    public static void main(String[] args) throws Exception {  
        // 创建执行环境  
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();  
          
        // 创建两个数据流,数据类型不同  
        DataStreamSource<Integer> intStream = env.fromElements(1, 2, 3, 4, 5);  
        DataStreamSource<String> stringStream = env.fromElements("a", "b", "c", "d", "e");  
          
        // 使用connect()方法将两个数据流连接起来  
        ConnectedStreams<Integer, String> connectedStreams = intStream.connect(stringStream);  
          
        // 使用CoMapFunction对连接后的流进行处理  
        DataStream<String> processedStream = connectedStreams.map(new CoMapFunction<Integer, String, String>() {  
            @Override  
            public String map1(Integer value) throws Exception {  
                // 处理intStream中的数据  
                return "Integer: " + value;  
            }  
  
            @Override  
            public String map2(String value) throws Exception {  
                // 处理stringStream中的数据  
                return "String: " + value;  
            }  
        });  
          
        // 打印处理后的数据流  
        processedStream.print();  
          
        // 执行程序  
        env.execute("Flink Connect Example");  
    }  
}

基于时间的合流(Join)

  1. 窗口联结示例
java 复制代码
// 假设有两个数据流stream1和stream2,它们包含具有相同键的元素  
DataStream<Tuple2<String, Integer>> stream1 = ...; // 数据流1,包含键和值  
DataStream<Tuple3<String, Integer, Integer>> stream2 = ...; // 数据流2,包含键、值和另一个值  
  
// 使用窗口联结将两个数据流连接起来  
DataStream<String> joinedStream = stream1  
    .join(stream2)  
    .where(tuple -> tuple.f0) // 指定stream1中的键  
    .equalTo(tuple -> tuple.f0) // 指定stream2中的键  
    .window(TumblingEventTimeWindows.of(Time.seconds(10))) // 指定滚动窗口,大小为10秒  
    .apply(new JoinFunction<Tuple2<String, Integer>, Tuple3<String, Integer, Integer>, String>() {  
        @Override  
        public String join(Tuple2<String, Integer> first, Tuple3<String, Integer, Integer> second) {  
            // 处理匹配的数据对  
            return first.f0 + "<----->" + second.f0 + "," + first.f1 + "," + second.f1 + "," + second.f2;  
        }  
    });  
  
// 打印结果  
joinedStream.print();
  1. 间隔联结示例
java 复制代码
// 假设有两个数据流streamA和streamB,它们包含具有相同键的元素  
DataStream<Integer> streamA = ...; // 数据流A,包含键(此处为简化,仅使用整数表示)  
DataStream<Integer> streamB = ...; // 数据流B,包含键(此处为简化,仅使用整数表示)  
  
// 使用间隔联结将两个数据流连接起来  
DataStream<String> joinedStream = streamA  
    .keyBy(value -> value) // 对数据流A进行键分区  
    .intervalJoin(streamB.keyBy(value -> value)) // 对数据流B进行键分区,并进行间隔联结  
    .between(Time.milliseconds(-2), Time.milliseconds(1)) // 指定时间间隔,上界为当前时间+1毫秒,下界为当前时间-2毫秒  
    .process(new ProcessJoinFunction<Integer, Integer, String>() {  
        @Override  
        public void processElement(Integer left, Integer right, Context ctx, Collector<String> out) {  
            // 处理匹配的数据对  
            out.collect(left + "," + right);  
        }  
    });  
  
// 打印结果  
joinedStream.print();

CoGroup

以下是一个简单的Flink CoGroup算子示例,它展示了如何使用CoGroup算子将两个数据流合并并处理分组后的数据。

java 复制代码
// 假设有两个数据流stream1和stream2,它们包含具有相同键的元素  
DataStream<Tuple3<String, String, Integer>> stream1 = ...; // 数据流1,包含键(f0)、值(f1)和另一个值(f2)  
DataStream<Tuple3<String, String, Integer>> stream2 = ...; // 数据流2,包含相同的键(f0)、不同的值(f1和f2)  
  
// 使用CoGroup算子将两个数据流合并  
DataStream<String> mergedStream = stream1  
    .coGroup(stream2)  
    .where(new KeySelector<Tuple3<String, String, Integer>, String>() {  
        @Override  
        public String getKey(Tuple3<String, String, Integer> value) throws Exception {  
            return value.f0; // 指定用于分组的键为f0  
        }  
    })  
    .equalTo(new KeySelector<Tuple3<String, String, Integer>, String>() {  
        @Override  
        public String getKey(Tuple3<String, String, Integer> value) throws Exception {  
            return value.f0; // 指定用于分组的键为f0(与stream1相同)  
        }  
    })  
    // 可选:使用时间窗口进行分组处理  
    .window(TumblingEventTimeWindows.of(Time.seconds(10)))  
    .apply(new CoGroupFunction<Tuple3<String, String, Integer>, Tuple3<String, String, Integer>, String>() {  
        @Override  
        public void coGroup(Iterable<Tuple3<String, String, Integer>> first,  
                            Iterable<Tuple3<String, String, Integer>> second,  
                            Collector<String> out) {  
            // 处理分组后的数据  
            StringBuilder sb = new StringBuilder();  
            for (Tuple3<String, String, Integer> t1 : first) {  
                sb.append("stream1: ").append(t1.f0).append(", ").append(t1.f1).append(", ").append(t1.f2).append(";");  
            }  
            for (Tuple3<String, String, Integer> t2 : second) {  
                sb.append("stream2: ").append(t2.f0).append(", ").append(t2.f1).append(", ").append(t2.f2).append(";");  
            }  
            out.collect(sb.toString());  
        }  
    });  
  
// 打印结果  
mergedStream.print();
相关推荐
DolphinScheduler社区29 分钟前
如何实现Dolphinscheduler YARN Task状态跟踪?
大数据
carl.xu36 分钟前
QNX 7.0.0开发总结
java·大数据·开发语言
苏少朋2 小时前
Es概念理解 ▎Es索引库操作 ▎Es文档操作
大数据·elasticsearch·搜索引擎
cab52 小时前
聊一聊Elasticsearch的一些基本信息
大数据·elasticsearch·搜索引擎
Elastic 中国社区官方博客2 小时前
GraphQL 与 Elasticsearch 相遇:使用 Hasura DDN 构建可扩展、支持 AI 的应用程序
大数据·后端·elasticsearch·搜索引擎·全文检索·graphql·1024程序员节
港股研究社2 小时前
凌雄科技打造DaaS模式,IT设备产业链由内而外嬗变升级
大数据·人工智能
Mephisto.java6 小时前
【大数据学习 | kafka】kafka的shell操作
大数据·学习·kafka
mysql学习中7 小时前
hive修改表操作与array类型
大数据·数据仓库·hive·hadoop·hdfs·mapreduce
Kika写代码9 小时前
【Hadoop】hadoop的路径分不清?HDFS路径与本地文件系统路径的区别
大数据·hadoop·hdfs
MXsoft6189 小时前
监控易监测对象及指标之:东方通中间件JMX监控
大数据·数据库