Flink的ConGroup算子介绍

ConGroup是Join的底层算子,就是Join算子也是通过CoGroup算子来实现的。

CoCgoup是在同一个窗口当中对同一个key上的俩组集合进行操作,比Join算子更通用,可以实现Inner Join、LeftJoin、RightJoin的效果,CoGroup的作用基本和Join基本相同,但是有一点不一样的是,如果未能找到新来的数据与另一个流在window中存在的匹配数据,仍可将该条记录进行输出,该算子只能在window中使用,但是就Inner Join而言推荐使用Join,因为Join在策略上做了优化,更高效。

场景:获取每个用户每个时刻的浏览和点击,模拟inner、left、right、join的功能。
结论:若在window中没有能够与之匹配的数据,CoGroup也会输出结果

来一个demo:

package Flink_API;

import org.apache.flink.api.common.functions.CoGroupFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.ProcessFunction;
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer010;
import org.apache.flink.streaming.util.serialization.KeyedDeserializationSchema;
import org.apache.flink.table.shaded.org.joda.time.DateTime;
import org.apache.flink.table.shaded.org.joda.time.format.DateTimeFormat;
import org.apache.flink.table.shaded.org.joda.time.format.DateTimeFormatter;
import org.apache.flink.util.Collector;

import java.io.Serializable;
import java.util.Properties;

public class TestConectGroup {

    public static void main(String[] args) throws Exception {
        //创建运行环境
        StreamExecutionEnvironment env=StreamExecutionEnvironment.getExecutionEnvironment();
        //Flink是以数据自带的时间戳字段为准
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        //设置并行度
        env.setParallelism(1);

        //1、获取第一个流,获取用户的浏览信息
        DataStream<UserBrowseLog> browseStream = getUserBrowseDataStream(env);
        //2、获取用户的点击信息
        DataStream<UserClickLog> clickStream = getUserClickLogDataStream(env);

        //打印结果
        browseStream.print();
        clickStream.print();

        //核心:通过CoGroup来实现三个Join作用
        //browseStream(左流)关联clickStream(右流)
        browseStream.coGroup(clickStream)
                .where(new KeySelector<UserBrowseLog, String>() {
                    @Override
                    public String getKey(UserBrowseLog userBrowseLog) throws Exception {
                        return userBrowseLog.getUserID()+"_"+userBrowseLog.getEventTime();
                    }
                })
                .equalTo(new KeySelector<UserClickLog, String>() {
                    @Override
                    public String getKey(UserClickLog userClickLog) throws Exception {
                        return userClickLog.getUserID()+"_"+userClickLog.getEventTime();
                    }
                })
                .window(TumblingEventTimeWindows.of(Time.seconds(10)))//滚动窗口
                .apply(new InnerJoin());

        env.execute("TestConectGroup");
    }
    //通过CoGroup模拟Inner Join的功能:获取每个用户每个时刻的浏览和点击,即浏览和点击不为才输出。
    public static class InnerJoin implements CoGroupFunction<UserBrowseLog,UserClickLog,String> {

        @Override
        public void coGroup(Iterable<UserBrowseLog> left, Iterable<UserClickLog> right, Collector<String> collector) throws Exception {
            //俩个key相同的时候才输出
            for (UserBrowseLog userBrowseLog:left){
                        for(UserClickLog clickLog:right){
                            collector.collect(userBrowseLog+"<Inner Join>"+clickLog);
                        }
                    }
        }
    }
    //通过CoGroup模拟Left Join的功能:获取每个用户每个时刻的浏览信息,有点击顺带输出,每点击则不输出
    public static class LeftJoinFunction implements CoGroupFunction<UserBrowseLog,UserClickLog,String>{

        @Override
        public void coGroup(Iterable<UserBrowseLog> left, Iterable<UserClickLog> right, Collector<String> collector) throws Exception {
            for(UserBrowseLog userBrowseLog:left){
                boolean noElements =true;
                for(UserClickLog userClickLog:right){
                    noElements=false;
                    collector.collect(userBrowseLog+"<Left Join>"+userClickLog);
                }
                if(noElements){
                    collector.collect(userBrowseLog +"<Left Join>"+"null");
                }
            }

        }
    }
    //通过CoGroup模拟Right Join的功能:获取每个用户每个时刻的浏览信息,有点击顺带输出,每点击则不输出
    public static class RightJoinFunction implements CoGroupFunction<UserBrowseLog,UserClickLog,String>{

        @Override
        public void coGroup(Iterable<UserBrowseLog> left, Iterable<UserClickLog> right, Collector<String> collector) throws Exception {
               for(UserClickLog  userClickLog:right){
                   boolean noElement = true;
                   for(UserBrowseLog userBrowseLog:left){
                       noElement =false;
                       collector.collect(userBrowseLog+"<right Join>"+userClickLog);
                   }
                   if(noElement){
                       collector.collect("null"+"<right Join>"+userClickLog);
                   }
               }
        }
    }

    private static DataStream<UserClickLog> getUserClickLogDataStream(StreamExecutionEnvironment env) {
        Properties consumerProperties = new Properties();
        consumerProperties.setProperty("bootstrap.severs","page01:9002");
        consumerProperties.setProperty("grop.id","browsegroup");

        DataStreamSource<String> dataStreamSource=env.addSource(new FlinkKafkaConsumer010<String>("browse_topic1", (KeyedDeserializationSchema<String>) new SimpleStringSchema(),consumerProperties));

        DataStream<UserClickLog> processData=dataStreamSource.process(new ProcessFunction<String, UserClickLog>() {
            @Override
            public void processElement(String s, Context context, Collector<UserClickLog> collector) throws Exception {
                try{
                    UserClickLog browseLog = com.alibaba.fastjson.JSON.parseObject(s, UserClickLog.class);
                    if(browseLog !=null){
                        collector.collect(browseLog);
                    }
                }catch(Exception e){
                    System.out.print("解析Json——UserBrowseLog异常:"+e.getMessage());
                }
            }
        });
        //设置watermark
        return processData.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<UserClickLog>(Time.seconds(0)){
            @Override
            public long extractTimestamp(UserClickLog userBrowseLog) {
                DateTimeFormatter dateTimeFormatter= DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
                DateTime dateTime=DateTime.parse(userBrowseLog.getEventTime(),dateTimeFormatter);
                //用数字表示时间戳,单位是ms,13位
                return dateTime.getMillis();
            }
        });
    }

    private static DataStream<UserBrowseLog> getUserBrowseDataStream(StreamExecutionEnvironment env) {
        Properties consumerProperties = new Properties();
        consumerProperties.setProperty("bootstrap.severs","page01:9001");
        consumerProperties.setProperty("grop.id","browsegroup");

        DataStreamSource<String> dataStreamSource=env.addSource(new FlinkKafkaConsumer010<String>("browse_topic", (KeyedDeserializationSchema<String>) new SimpleStringSchema(),consumerProperties));

        DataStream<UserBrowseLog> processData=dataStreamSource.process(new ProcessFunction<String, UserBrowseLog>() {
            @Override
            public void processElement(String s, Context context, Collector<UserBrowseLog> collector) throws Exception {
                try{
                    UserBrowseLog browseLog = com.alibaba.fastjson.JSON.parseObject(s, UserBrowseLog.class);
                    if(browseLog !=null){
                        collector.collect(browseLog);
                    }
                }catch(Exception e){
                    System.out.print("解析Json——UserBrowseLog异常:"+e.getMessage());
                }
            }
        });
        //设置watermark
        return processData.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<UserBrowseLog>(Time.seconds(0)) {
            @Override
            public long extractTimestamp(UserBrowseLog userBrowseLog) {
                DateTimeFormatter dateTimeFormatter= DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
                DateTime dateTime=DateTime.parse(userBrowseLog.getEventTime(),dateTimeFormatter);
                //用数字表示时间戳,单位是ms,13位
                return dateTime.getMillis();
            }
        });
    }

    //浏览类
    public static class UserBrowseLog implements Serializable {
        private String userID;
        private String eventTime;
        private String eventType;
        private String productID;
        private Integer productPrice;

        public String getUserID() {
            return userID;
        }

        public void setUserID(String userID) {
            this.userID = userID;
        }

        public String getEventTime() {
            return eventTime;
        }

        public void setEventTime(String eventTime) {
            this.eventTime = eventTime;
        }

        public String getEventType() {
            return eventType;
        }

        public void setEventType(String eventType) {
            this.eventType = eventType;
        }

        public String getProductID() {
            return productID;
        }

        public void setProductID(String productID) {
            this.productID = productID;
        }

        public Integer getProductPrice() {
            return productPrice;
        }

        public void setProductPrice(Integer productPrice) {
            this.productPrice = productPrice;
        }

        @Override
        public String toString() {
            return "UserBrowseLog{" +
                    "userID='" + userID + '\'' +
                    ", eventTime='" + eventTime + '\'' +
                    ", eventType='" + eventType + '\'' +
                    ", productID='" + productID + '\'' +
                    ", productPrice=" + productPrice +
                    '}';
        }
    }
    //点击类
    public static class UserClickLog implements Serializable{
        private String userID;
        private String eventTime;
        private String eventType;
        private String pageID;

        public String getUserID() {
            return userID;
        }

        public void setUserID(String userID) {
            this.userID = userID;
        }

        public String getEventTime() {
            return eventTime;
        }

        public void setEventTime(String eventTime) {
            this.eventTime = eventTime;
        }

        public String getEventType() {
            return eventType;
        }

        public void setEventType(String eventType) {
            this.eventType = eventType;
        }

        public String getPageID() {
            return pageID;
        }

        public void setPageID(String pageID) {
            this.pageID = pageID;
        }

        @Override
        public String toString() {
            return "UserClickLog{" +
                    "userID='" + userID + '\'' +
                    ", eventTime='" + eventTime + '\'' +
                    ", eventType='" + eventType + '\'' +
                    ", pageID='" + pageID + '\'' +
                    '}';
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flink 中的算子可以分为三类:转换算子(Transformation)、数据源算子(Source)、数据汇算子(Sink)。 1. 转换算子 转换算子用于对数据进行转换和处理,常用的算子有: - map:对每条数据进行一定的处理,将其转换为另一种形式输出。 - flatMap:与 map 类似,但是可以输出多个结果。 - filter:对数据进行过滤,只保留符合条件的数据。 - keyBy:按照指定的 key 进行分组,将具有相同 key 的数据分到同一个分区中。 - reduce:对分组后的数据进行聚合计算,输出一个结果。 - sum/min/max:对分组后的数据进行求和/最大值/最小值计算,输出一个结果。 - window:将数据按照时间窗口进行分组,进行聚合计算。 - join:将两个流的数据按照指定的条件进行连接,输出一个新的流。 - union:将两个流合并成一个流。 - coMap/coFlatMap:将两个流的数据进行合并处理,输出一个新的流。 2. 数据源算子 数据源算子用于从外部数据源中读取数据,常用的算子有: - socketTextStream:从指定的 Socket 地址读取文本数据。 - readTextFile:从指定的文件路径读取文本数据。 - readCsvFile:从指定的 CSV 文件路径读取 CSV 数据。 - addSource:从自定义数据源中读取数据。 3. 数据汇算子 数据汇算子用于将数据写入到外部系统中,常用的算子有: - print:将数据打印到控制台。 - writeAsText:将数据以文本形式写入到指定的文件路径。 - writeAsCsv:将数据以 CSV 形式写入到指定的文件路径。 - addSink:将数据写入到自定义的数据汇中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值