Flink datastream join 示例

Flink datastream join 示例

环境

socket 输入数据,flink加工成两个流,两个流join,输出数据

组件版本
scala2.12
netcat*
flink1.13.3

解析

测试数据
/**测试数据**/
stu,1001,张三
stu,1002,李四
project,10001,1001,语文,90
project,10002,1002,语文,99
project,10003,1001,数学,79
project,10004,1002,数学,120
netcat 服务端,命令
nc -lk 9999
创建环境、获取输入
val env = StreamExecutionEnvironment.getExecutionEnvironment
val inputStream = env.socketTextStream("server120", 9999)
对输入流进行加工,根据输入数据的第一个值进行分流
val resultStream = inputStream.filter(x => {
      x != null && !"".equals(x)
    })//filter算子,过滤为空数据
      .map(x => x)//map算子,未进行任何处理
      .process(new ProcessFunction[String, String]() {//[String,String] 表示输入输出均为String
        override def processElement(value: String, ctx: ProcessFunction[String, String]#Context, out: Collector[String]): Unit = {
          val strs = value.split(",") //根据逗号分割输入字符串
          strs(0) match {//匹配第一个值
            case "stu" => { //如果是stu,走这个逻辑
              //output侧输出流 不用遵循函数头定义的输出类型,可以是任意类型
              //定义侧输出流,类型为(Int,String)元组,id为stu,值为(Integer.parseInt(strs(1)), strs(2))
              ctx.output(new OutputTag[(Int, String)]("stu"), (Integer.parseInt(strs(1)), strs(2)))
            }
            case "project" => {//如果是project,走这个逻辑
              //output侧输出流 不用遵循函数头定义的输出类型,可以是任意类型
              //定义侧输出流,类型为(Int, Int, String, Int)元组,id为project,值为(Integer.parseInt(strs(1)), Integer.parseInt(strs(2)
              ctx.output(new OutputTag[(Int, Int, String, Int)]("project"), (Integer.parseInt(strs(1)), Integer.parseInt(strs(2)), strs(3), Integer.parseInt(strs(4))))
            }
          }
        }
      })
从主流里获取侧输出流
//从流里获取侧输出流
    val stu = resultStream.getSideOutput(new OutputTag[(Int, String)]("stu"))
    val project = resultStream.getSideOutput(new OutputTag[(Int, Int, String, Int)]("project"))
两个侧输出流关联、输出结果到控制台
//两个流关联
    stu.join(project)
      .where(col => col._1)//第一个流的第一个值
      .equalTo(col => col._2)//等于第二个流的第二个值
      .window(TumblingProcessingTimeWindows.of(Time.seconds(15)))//滚动窗口,处理时间,15秒一个窗口
      //关联上以后执行的操作,[输入A,输入B,输出]
      .apply(new JoinFunction[(Int, String), (Int, Int, String, Int), (Int, Int, String, String, Int)] {
        override def join(first: (Int, String), second: (Int, Int, String, Int)): (Int, Int, String, String, Int) = {
          (first._1, second._1, first._2, second._3, second._4)//最终返回值
        }
      }).print()//打印
阻塞进程,等待数据输入
   //保持阻塞进程,等待数据输入
    env.execute()

完整代码

package com.z.join

import org.apache.flink.api.common.functions.JoinFunction
import org.apache.flink.streaming.api.functions.ProcessFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.util.Collector

/**
 * @Author wenz.ma
 * @Date 2021/10/29 14:31
 * @Desc socket 输入数据,flink加工成两个流,两个流join,输出数据
 */
object SocketJoinDemo {
  def main(args: Array[String]): Unit = {
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    val inputStream = env.socketTextStream("server120", 9999)

    /**
     * 测试数据
     * stu,1001,张三
     * stu,1002,李四
     * project,10001,1001,语文,90
     * project,10002,1002,语文,99
     * project,10003,1001,数学,79
     * project,10004,1002,数学,120
     *
     */
    val resultStream = inputStream.filter(x => {
      x != null && !"".equals(x)
    })//filter算子,过滤为空数据
      .map(x => x)//map算子,未进行任何处理
      .process(new ProcessFunction[String, String]() {//[String,String] 表示输入输出均为String
        override def processElement(value: String, ctx: ProcessFunction[String, String]#Context, out: Collector[String]): Unit = {
          val strs = value.split(",") //根据逗号分割输入字符串
          strs(0) match {//匹配第一个值
            case "stu" => { //如果是stu,走这个逻辑
              //output侧输出流 不用遵循函数头定义的输出类型,可以是任意类型
              //定义侧输出流,类型为(Int,String)元组,id为stu,值为(Integer.parseInt(strs(1)), strs(2))
              ctx.output(new OutputTag[(Int, String)]("stu"), (Integer.parseInt(strs(1)), strs(2)))
            }
            case "project" => {//如果是project,走这个逻辑
              //output侧输出流 不用遵循函数头定义的输出类型,可以是任意类型
              //定义侧输出流,类型为(Int, Int, String, Int)元组,id为project,值为(Integer.parseInt(strs(1)), Integer.parseInt(strs(2)
              ctx.output(new OutputTag[(Int, Int, String, Int)]("project"), (Integer.parseInt(strs(1)), Integer.parseInt(strs(2)), strs(3), Integer.parseInt(strs(4))))
            }
          }
        }
      })
    //从流里获取侧输出流
    val stu = resultStream.getSideOutput(new OutputTag[(Int, String)]("stu"))
    val project = resultStream.getSideOutput(new OutputTag[(Int, Int, String, Int)]("project"))
    //两个流关联
    stu.join(project)
      .where(col => col._1)//第一个流的第一个值
      .equalTo(col => col._2)//等于第二个流的第二个值
      .window(TumblingProcessingTimeWindows.of(Time.seconds(15)))//滚动窗口,处理时间,15秒一个窗口
      //关联上以后执行的操作,[输入A,输入B,输出]
      .apply(new JoinFunction[(Int, String), (Int, Int, String, Int), (Int, Int, String, String, Int)] {
        override def join(first: (Int, String), second: (Int, Int, String, Int)): (Int, Int, String, String, Int) = {
          (first._1, second._1, first._2, second._3, second._4)//最终返回值
        }
      }).print()//打印


    //保持阻塞进程,等待数据输入
    env.execute()
  }
}

依赖

flink 、scala 依赖

 <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-clients_${scala.version}</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-scala_${scala.version}</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-streaming-scala_${scala.version}</artifactId>
            <version>${flink.version}</version>
        </dependency>

源码下载

https://download.csdn.net/download/sinat_25528181/44038825
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Flink 的双流 Join 可以使用 `JoinFunction` 来实现。代码示例如下: ``` DataStream<Tuple2<String, Integer>> left = ...; DataStream<Tuple2<String, Integer>> right = ...; DataStream<Tuple2<String, Integer>> joined = left.join(right) .where(t -> t.f0) .equalTo(t -> t.f0) .window(TumblingEventTimeWindows.of(Time.seconds(30))) .apply(new JoinFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, Tuple2<String, Integer>>() { @Override public Tuple2<String, Integer> join(Tuple2<String, Integer> first, Tuple2<String, Integer> second) throws Exception { return new Tuple2<>(first.f0, first.f1 + second.f1); } }); ``` 在代码中,左右两个数据流通过调用 `join` 方法进行 Join 操作。使用 `where` 和 `equalTo` 方法来指定 Join 条件,在本示例中,Join 条件是两个元组的第一个字段相等。使用 `window` 方法来指定 Join 操作的窗口,在本示例中,使用的是滚动窗口,窗口大小为 30 秒。最后,使用 `apply` 方法来指定 Join 的具体操作,在本示例中,Join 后的结果是两个元组的第二个字段相加。 ### 回答2: Flink双流join是指在Flink流处理框架中,将两个不同的流数据根据某些条件进行连接操作。下面是一个简单的Flink双流join代码示例: ```java // 导入必要的Flink库 import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction; import org.apache.flink.util.Collector; // 创建流处理环境 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // 定义第一个流,如DataStream<String> DataStream<String> stream1 = env.fromElements("Apple", "Banana", "Orange", "Mango"); // 定义第二个流,如DataStream<Integer> DataStream<Integer> stream2 = env.fromElements(1, 2, 3, 4); // 使用connect方法将两个流连接起来 // 通过CoFlatMapFunction对连接的流进行处理 DataStream<String> result = stream1.connect(stream2) .flatMap(new CoFlatMapFunction<String, Integer, String>() { @Override public void flatMap1(String value, Collector<String> out) { // 对第一个流进行处理,这里示例是将流1中的元素转为大写 out.collect(value.toUpperCase()); } @Override public void flatMap2(Integer value, Collector<String> out) { // 对第二个流进行处理,这里示例是将流2中的元素乘以2后输出 out.collect(String.valueOf(value * 2)); } }); // 输出结果 result.print(); // 执行流处理任务 env.execute(); ``` 上述代码首先创建了一个流处理环境,并定义了两个不同的流`stream1`和`stream2`。然后通过`connect`方法将两个流进行连接,并使用`CoFlatMapFunction`对连接的流进行处理。`CoFlatMapFunction`中的`flatMap1`方法对第一个流进行处理,`flatMap2`方法对第二个流进行处理。最后通过`print()`方法打印处理结果,并调用`execute()`方法执行流处理任务。 ### 回答3: Flink双流join是一种实时数据处理技术,适用于将两个输入流根据指定条件进行连接操作的场景。下面是一个示例代码: ``` import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.functions.co.ProcessJoinFunction; import org.apache.flink.util.Collector; public class StreamJoinExample { public static void main(String[] args) throws Exception { // 创建执行环境 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // 创建第一个流 DataStream<Tuple2<String, Integer>> stream1 = env.fromElements( new Tuple2<>("A", 1), new Tuple2<>("B", 2), new Tuple2<>("C", 3) ); // 创建第二个流 DataStream<Tuple2<String, Double>> stream2 = env.fromElements( new Tuple2<>("A", 1.0), new Tuple2<>("B", 2.0), new Tuple2<>("D", 4.0) ); // 将两个流连接起来,并定义连接条件 DataStream<String> result = stream1 .keyBy(0) .intervalJoin(stream2.keyBy(0)) .between(Time.seconds(-5), Time.seconds(5)) .process(new ProcessJoinFunction<Tuple2<String, Integer>, Tuple2<String, Double>, String>() { @Override public void processElement(Tuple2<String, Integer> left, Tuple2<String, Double> right, Context ctx, Collector<String> out) throws Exception { out.collect(left.f0 + " -> " + right.f1); } }); // 打印结果 result.print(); // 执行程序 env.execute("Stream Join Example"); } } ``` 上述代码中,我们首先创建了两个输入流stream1和stream2,并添加了一些元素作为测试数据。然后,我们使用`keyBy`方法根据指定的key对两个流进行分区。在连接操作中,我们使用了`between`方法定义了时间窗口,在5秒的时间窗口内进行连接操作。最后,我们使用`process`方法将连接后的结果输出到一个新的流中,并使用`print`方法打印输出结果。最后,我们使用`env.execute`方法执行程序。 通过上述代码,我们可以在Flink中实现双流join操作,并根据自定义的条件将两个输入流连接起来,得到我们所需的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值