使用flink通过窗口实现数据源(mq)数据过滤,解决cannot be cast to org.apache.flink.table.dataformat.BinaryGeneric

使用flink通过窗口实现数据源(mq)数据过滤。

需求:一个老师有基本属性包括(编号,名字,年龄,学生集合,以及图片信息)需要通过flink窗口实现多字段过滤以及取最大年龄的数据

  1. 定义student类
public class Student {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Student() {
    }
    public Student(String name) {
        this.name = name;
    }
}
  1. 定义mq数据源
/***
 * @Description 自定义数据源
 * @Param null
 */
public class RocketMqTuple5Source extends RichParallelSourceFunction<Tuple5<String, String, Integer, List<Student>, byte[]>> {
    private Consumer consumer;
    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        Properties properties = ConfigUtil.getRocketMqConfiguration();
        properties.put(PropertyKeyConst.GROUP_ID, "leo-test-flink" + ConfigUtil.getDomainConfig());
        consumer = ONSFactory.createConsumer(properties);
    }
    @Override
    public void close() throws Exception {
        try {
            cancel();
        } finally {
            super.close();
        }
    }
    @Override
    public void run(SourceContext<Tuple5<String, String, Integer, List<Student>, byte[]>> sourceContext) {
        //这里通过订阅DEVICE_TO_ATHENA_TOPIC 来接受任务消息和图片特征提取消息
        consumer.subscribe("flink-test-demo",
                "test",
                new MessageListener() {
                    @Override
                    public Action consume(Message message, ConsumeContext context) {
                        try {
                            //反序列化
                            MqData mqData = JSON.parseObject(new String(message.getBody()),
                                    MqData.class);
                            List<Student> students = new ArrayList<>();
                            students.add(new Student("def"));
                            int b = 456;
                            int a = 457;
                            byte test = (byte) b;
                            byte test1 = (byte)a;
                            byte[] bys={test,test1};
                            // 模仿图片流数据
                            Tuple5<String, String, Integer, List<Student>, byte[]> tuple = new Tuple5<String, String, Integer, List<Student>, byte[]>(
                                    mqData.getNo(), mqData.getName(), mqData.getAge(),students,bys
                            );
                            sourceContext.collect(tuple);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        return Action.CommitMessage;
                    }
                });
        consumer.start();
        System.out.println("=================consumer start");
        //这里sleep是因为RichParallelSourceFunction在run 方法执行完了就close了,为了使mq消费者一直活着,需要通过sleep来保持线程
        while (consumer.isStarted()) {
            try {
                //System.out.println("=================Thread start sleep");
                Thread.sleep(50);
                //System.out.println("=================Thread end sleep");
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
                Thread.currentThread().interrupt();
            }
        }

    }

    @Override
    public void cancel() {
        if (consumer != null) {
            consumer.shutdown();
        }
    }
}
  1. flink执行类
public class MqDataSourceTuple5Test {

    public static void main(String[] args) throws Exception {
        // 获取执行环境配置信息
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        EnvironmentSettings bsSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build();
        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, bsSettings);

        // 添加自定义数据源(mq)
        DataStream<Tuple5<String, String, Integer, List<Student>, byte[]>> text = env.addSource(new RocketMqTuple5Source()).keyBy(0);

        // 把mq数据注册成表,字段后面加“b”是由于flink不支持某些关键字的命名
        tableEnv.registerDataStream("mqDataTable", text, "nob, nameb, ageb, students, bys");

        // 查询mq数据表
        Table stageTable = tableEnv.sqlQuery("SELECT nob, nameb, mqDataTable.ageb, students, bys FROM  mqDataTable");

        // 将table转为dataStream
//        DataStream<Row> stream = tableEnv.toAppendStream(stageTable, Row.class);
        DataStream<Tuple5<String, String, Integer,List<Student>, byte[]>> stream1 = tableEnv.toAppendStream(stageTable, TypeInformation.of(new TypeHint<Tuple5<String, String, Integer,List<Student>, byte[]>>() {}));

        // 根据编号和名字分区,取年龄最大的一条数据,这里每一步需要通过returns指定执行算子后返回的数据类型,取决于你后续sink接受什么类型的数据
        DataStream<Row> keyByStream = stream1.keyBy(0,1)
        .timeWindow(Time.seconds(10)).maxBy(2).returns(Types.TUPLE(Types.STRING, Types.STRING, Types.INT, Types.GENERIC(List.class), Types.GENERIC(byte.class)))
                .flatMap(new FlatMapFunction<Tuple5<String, String, Integer, List<Student>, byte[]>, Row>() {
                    @Override
                    public void flatMap(Tuple5<String, String, Integer, List<Student>, byte[]> value, Collector<Row> out) throws Exception {
                        Row row = new Row(5);
                        row.setField(0, value.f0);
                        row.setField(1, value.f1);
                        row.setField(2, value.f2);
                        row.setField(3, value.f3);
                        row.setField(4, value.f4);
                        out.collect(row);
                    }
                }).returns(Types.ROW(Types.STRING, Types.STRING, Types.INT, Types.GENERIC(List.class), Types.GENERIC(byte.class)));


        // 输出(可以调用自定义sink方法)
        keyByStream.print();
        env.execute();
    }
}

  1. 通过mq控制台发送测试数据
    在这里插入图片描述
  2. 控制台输出结果
    在这里插入图片描述

以上写法纯属自己对flink的理解,如有更好的写法欢迎指出,分享!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值