Flink教程(12) 两条流关联 window窗口的 join leftJoin使用案例

一、温度数据和实体类

1. 温度数据

第一个是id,第二个温度,第三个是事件事件

1,20.5,2021-01-29 16:00:00
1,21.5,2021-01-29 16:00:10
1,22.5,2021-01-29 16:00:20
1,24.5,2021-01-29 16:00:30
1,23.5,2021-01-29 16:00:40
1,22.5,2021-01-29 16:00:50
1,41.5,2021-01-29 16:01:00

2. 实体类

public class SensorRecord {

    private String id;

    private Double record;

    private LocalDateTime time;

	//省略其它
}

3. 将字符串映射成SensorRecord对象

public class SensorRecordUtils {

    /**
     * 将字符串映射成SensorRecord对象
     */
    public static class BeanMap implements MapFunction<String, SensorRecord> {

        @Override
        public SensorRecord map(String s) throws Exception {
            if (StringUtils.isNotBlank(s)) {
                String[] split = s.split(",");
                if (split != null && split.length == 3) {
                    return new SensorRecord(
                            split[0],
                            Double.valueOf(split[1]),
                            LocalDateTime.parse(split[2], FormatterConstant.commonDtf));
                }
            }
            return null;
        }
    }
}

二、window join

1. 获取2条数据流

public class Test11_WindowJoin {

    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        env.setParallelism(1);
		
		//左流
        DataStreamSource<String> leftSource = env.socketTextStream(BaseConstant.URL, 9901);
        //右流
		DataStreamSource<String> rightSource = env.socketTextStream(BaseConstant.URL, 9902);

		//设置事件事件字段和水位线
        WatermarkStrategy<SensorRecord> strategy = WatermarkStrategy.<SensorRecord>forBoundedOutOfOrderness(Duration.ofSeconds(1))
                .withTimestampAssigner(new SerializableTimestampAssigner<SensorRecord>() {
                    @Override
                    public long extractTimestamp(SensorRecord element, long recordTimestamp) {
                        return element.getTimeEpochMilli();
                    }
                });

        DataStream<SensorRecord> leftStream = leftSource
                .map(new SensorRecordUtils.BeanMap())
                .filter(a -> a != null)
                .assignTimestampsAndWatermarks(strategy);

        DataStream<SensorRecord> rightStream = rightSource
                .map(new SensorRecordUtils.BeanMap())
                .filter(a -> a != null)
                .assignTimestampsAndWatermarks(strategy);
     }
}

2. join的代码

DataStream<SensorRecordJoin> result = leftStream
        .join(rightStream)
        .where(new MyKeySelector())
        .equalTo(new MyKeySelector())
        .window(TumblingEventTimeWindows.of(Time.seconds(30)))
        .apply(new MyJoinFunction());

3. KeySelector

    public static class MyKeySelector implements KeySelector<SensorRecord, String> {

        @Override
        public String getKey(SensorRecord value) throws Exception {
            return value.getId();
        }
    }

4. 设置join后的结果对象

public static class MyJoinFunction implements JoinFunction<SensorRecord, SensorRecord, SensorRecordJoin> {

    @Override
    public SensorRecordJoin join(SensorRecord first, SensorRecord second) throws Exception {
       return new SensorRecordJoin(first, second);
    }
}

三、window left join

1. left join主体代码

DataStream<SensorRecordJoin> result = leftStream.coGroup(rightStream)
         .where(new MyKeySelector())
         .equalTo(new MyKeySelector())
         .window(TumblingEventTimeWindows.of(Time.seconds(30)))
         .apply(new MyCoGroupFunction() {
         });

2. MyCoGroupFunction

public static class MyCoGroupFunction implements CoGroupFunction<SensorRecord, SensorRecord, SensorRecordJoin> {

       //窗口满足条件就会调用
       @Override
       public void coGroup(Iterable<SensorRecord> first, Iterable<SensorRecord> second, Collector<SensorRecordJoin> out) throws Exception {
           //当两个流窗口满足触发条件,就会调用coGroup方法

           boolean joined = false;
           for (SensorRecord firstLevel : first) {
               for (SensorRecord sensorRecord : second) {
                   joined = true;
                   out.collect(new SensorRecordJoin(firstLevel, sensorRecord));
               }
           }
           if (!joined) {
               for (SensorRecord firstLevel : first) {
                   out.collect(new SensorRecordJoin(firstLevel, new SensorRecord()));
               }
           }
       }
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
可以使用Flink的DataSet API和JDBC连接Oracle数据库来实现左连接查询两个表。具体步骤如下: 1. 在Flink使用JDBC连接Oracle数据库。可以使用Flink提供的JDBCInputFormat读取表数据,示例代码如下: ```java String driverName = "oracle.jdbc.driver.OracleDriver"; String dbURL = "jdbc:oracle:thin:@localhost:1521:ORCL"; String username = "username"; String password = "password"; JDBCInputFormat inputFormat = JDBCInputFormat.buildJDBCInputFormat() .setDrivername(driverName) .setDBUrl(dbURL) .setUsername(username) .setPassword(password) .setQuery("SELECT * FROM table1") .setRowTypeInfo(rowTypeInfo) .finish(); ``` 2. 使用DataSet API进行左连接查询。可以使用leftOuterJoin方法将两个DataSet进行左连接,示例代码如下: ```java DataSet<Tuple2<String, String>> table1 = ... DataSet<Tuple2<String, String>> table2 = ... DataSet<Tuple2<String, String>> result = table1.leftOuterJoin(table2) .where(0) // 指定table1的join字段 .equalTo(1) // 指定table2的join字段 .with(new JoinFunction<Tuple2<String, String>, Tuple2<String, String>, Tuple2<String, String>>() { @Override public Tuple2<String, String> join(Tuple2<String, String> first, Tuple2<String, String> second) throws Exception { if (second == null) { // 表示table2中没有与table1匹配的记录 return new Tuple2<>(first.f0, ""); } else { return new Tuple2<>(first.f0, second.f1); } } }); ``` 在上面的代码中,我们使用JoinFunction自定义了一个左连接函数,如果table2中没有与table1匹配的记录,我们将第二个字段设为空字符串。 3. 将查询结果输出到控制台或其他存储介质中。可以使用print或write方法输出结果,示例代码如下: ```java result.print(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑟 王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值