Flink实时计算运用(五)Flink Table API & SQL 案例实战

1. Table API & SQL 实战运用

  1. 案例说明

    • 功能说明

      通过socket读取数据源,进行单词的统计处理。

    • 实现流程

      • 初始化Table运行环境

      • 转换操作处理:

        1)以空格进行分割

        2)给每个单词计数累加1

        3)根据单词进行分组处理

        4)求和统计

        5)输出打印数据

      • 执行任务

  2. FlinkTable API 方式实现

    StreamTableApiApplication,代码实现:

    //获取流处理的运行环境
    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
    EnvironmentSettings environmentSettings = EnvironmentSettings.newInstance().useOldPlanner().inStreamingMode().build();
    
    //获取Table的运行环境
    StreamTableEnvironment tabEnv = StreamTableEnvironment.create(env, environmentSettings);
    
    //接入数据源
    DataStreamSource<String> lines = env.socketTextStream("10.10.20.15", 9922);
    
    //对字符串进行分词压平
    SingleOutputStreamOperator<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
        @Override
        public void flatMap(String line, Collector<String> out) throws Exception {
            Arrays.stream(line.split(" ")).forEach(out::collect);
        }
    });
    
    //将DataStream转换成Table对象,字段名默认的是f0,给定字段名是word
    Table table = tabEnv.fromDataStream(words, "word");
    
    //按照单词进行分组聚合操作
    Table resultTable = table.groupBy("word").select("word, sum(1L) as counts");
    
    //在流处理中,数据会源源不断的产生,需要累加处理,只能采用用toRestractStream
    //        DataStream<WordCount> wordCountDataStream = tabEnv.toAppendStream(resultTable, WordCount.class);
    //        wordCountDataStream.printToErr("toAppendStream>>>");
    
    DataStream<Tuple2<Boolean, WordCount>> wordCountDataStream = tabEnv.toRetractStream(resultTable, WordCount.class);
    wordCountDataStream.printToErr("toRetractStream>>>");
    
    env.execute();
    

    测试验证:

    开启socket输入, 输入字符串:

    [root@flink1 flink-1.11.2]# nc -lk 9922
    
  3. FlinkTable SQL 方式实现

    代码实现:

    StreamTableSqlApplication实现类:

    //获取流处理的运行环境
    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
    EnvironmentSettings environmentSettings = EnvironmentSettings.newInstance().useOldPlanner().inStreamingMode().build();
    
    //获取Table的运行环境
    StreamTableEnvironment tabEnv = StreamTableEnvironment.create(env, environmentSettings);
    
    //接入数据源
    DataStreamSource<String> lines = env.socketTextStream("10.10.20.15", 9922);
    
    //对字符串进行分词压平
    SingleOutputStreamOperator<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
        @Override
        public void flatMap(String line, Collector<String> out) throws Exception {
            Arrays.stream(line.split(" ")).forEach(out::collect);
        }
    });
    
    //将DataStream转换成Table对象,字段名默认的是f0,给定字段名是word
    tabEnv.registerDataStream("t_wordcount", words, "word");
    
    //按照单词进行分组聚合操作
    Table resultTable = tabEnv.sqlQuery("select word,count(1) as counts from t_wordcount group by word");
    
    DataStream<Tuple2<Boolean, WordCount>> wordCountDataStream = tabEnv.toRetractStream(resultTable, WordCount.class);
    wordCountDataStream.printToErr("toRetractStream>>>");
    env.execute();
    

2. Flink SQL 滚动窗口实战

  1. Flink SQL 窗口说明

    Flink SQL支持的窗口聚合主要是两种:Window聚合和Over聚合。这里主要介绍Window聚合。Window聚合支持两种时间属性定义窗口:Event Time和Processing Time。每种时间属性类型支持三种窗口类型:滚动窗口(TUMBLE)、滑动窗口(HOP)和会话窗口(SESSION)

  2. 案例说明

    统计在过去的1分钟内有多少用户点击了某个的网页,可以通过定义一个窗口来收集最近1分钟内的数据,并对这个窗口内的数据进行计算。

    测试数据:

    用户名访问地址访问时间
    张三http://taobao.com/xxx2021-05-10 10:00:00
    张三http://taobao.com/xxx2021-05-10 10:00:10
    张三http://taobao.com/xxx2021-05-10 10:00:49
    张三http://taobao.com/xxx2021-05-10 10:01:05
    张三http://taobao.com/xxx2021-05-10 10:01:58
    李四http://taobao.com/xxx2021-05-10 10:02:10
  3. 滚动窗口运用

    滚动窗口(Tumbling windows)要用Tumble类来定义,另外还有三个方法:

    • over:定义窗口长度

    • on:用来分组(按时间间隔)或者排序(按行数)的时间字段

    • as:别名,必须出现在后面的groupBy中

    实现步骤:

    • 初始化流运行环境

    • 在流模式下使用blink planner

    • 创建用户点击事件数据

    • 将源数据写入临时文件并获取绝对路径

    • 创建表载入用户点击事件数据

    • 对表运行SQL查询,并将结果作为新表检索

    • Table转换成DataStream

    • 执行任务

    TumbleUserClickApplication,实现代码:

    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
    EnvironmentSettings environmentSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build();
    StreamTableEnvironment tabEnv = StreamTableEnvironment.create(env, environmentSettings);
    
    // 将源数据写入临时文件并获取绝对路径
    String contents =
            "张三,http://taobao.com/xxx,2021-05-10 10:00:00\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:00:10\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:00:49\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:01:05\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:01:58\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:02:10\n";
    String path = FileUtil.createTempFile(contents);
    
    String ddl = "CREATE TABLE user_clicks (\n" +
            "  username varchar,\n" +
            "  click_url varchar,\n" +
            "  ts TIMESTAMP(3),\n" +
            "  WATERMARK FOR ts AS ts - INTERVAL '2' SECOND\n" +
            ") WITH (\n" +
            "  'connector.type' = 'filesystem',\n" +
            "  'connector.path' = '" + path + "',\n" +
            "  'format.type' = 'csv'\n" +
            ")";
    
    tabEnv.sqlUpdate(ddl);
    
    //对表数据进行sql查询,并将结果作为新表进行查询
    String query = "SELECT\n" +
            "  TUMBLE_START(ts, INTERVAL '1' MINUTE),\n" +
            "  TUMBLE_END(ts, INTERVAL '1' MINUTE),\n" +
            "  username,\n" +
            "  COUNT(click_url)\n" +
            "FROM user_clicks\n" +
            "GROUP BY TUMBLE(ts, INTERVAL '1' MINUTE), username";
    
    Table result = tabEnv.sqlQuery(query);
    
    tabEnv.toAppendStream(result, Row.class).print();
    
    env.execute();
    

    以1分钟作为时间滚动窗口,水印延迟2秒。

    输出结果:

    4> 2021-10-10T10:00,2021-10-10T10:01,张三,3
    4> 2021-10-10T10:01,2021-10-10T10:02,张三,2
    4> 2021-10-10T10:02,2021-10-10T10:03,张三,1
    

3. Flink SQL 滑动窗口实战

  1. 实现步骤

    • 初始化流运行环境

    • 在流模式下使用blink planner

    • 创建用户点击事件数据

    • 将源数据写入临时文件并获取绝对路径

    • 创建表载入用户点击事件数据

    • 对表运行SQL查询,并将结果作为新表检索

    • Table转换成DataStream

    • 执行任务

  2. 实现代码

    代码HopUserClickApplication:

    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
    EnvironmentSettings environmentSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build();
    StreamTableEnvironment tabEnv = StreamTableEnvironment.create(env, environmentSettings);
    
    // 将源数据写入临时文件并获取绝对路径
    String contents =
            "张三,http://taobao.com/xxx,2020-10-10 10:00:00\n" +
                    "张三,http://taobao.com/xxx,2020-10-10 10:00:10\n" +
                    "张三,http://taobao.com/xxx,2020-10-10 10:00:49\n" +
                    "张三,http://taobao.com/xxx,2020-10-10 10:01:05\n" +
                    "张三,http://taobao.com/xxx,2020-10-10 10:01:58\n" +
                    "张三,http://taobao.com/xxx,2020-10-10 10:02:10\n";
    String path = FileUtil.createTempFile(contents);
    
    String ddl = "CREATE TABLE user_clicks (\n" +
            "  username varchar,\n" +
            "  click_url varchar,\n" +
            "  ts TIMESTAMP(3),\n" +
            "  WATERMARK FOR ts AS ts - INTERVAL '2' SECOND\n" +
            ") WITH (\n" +
            "  'connector.type' = 'filesystem',\n" +
            "  'connector.path' = '" + path + "',\n" +
            "  'format.type' = 'csv'\n" +
            ")";
    
    tabEnv.sqlUpdate(ddl);
    
    //对表数据进行sql查询,并将结果作为新表进行查询,每隔30秒,统计一次过去1分钟的数据
    String query = "SELECT\n" +
            "  HOP_START(ts, INTERVAL '30' SECOND, INTERVAL '1' MINUTE),\n" +
            "  HOP_END(ts, INTERVAL '30' SECOND, INTERVAL '1' MINUTE),\n" +
            "  username,\n" +
            "  COUNT(click_url)\n" +
            "FROM user_clicks\n" +
            "GROUP BY HOP (ts, INTERVAL '30' SECOND, INTERVAL '1' MINUTE), username";
    
    Table result = tabEnv.sqlQuery(query);
    
    tabEnv.toAppendStream(result, Row.class).print();
    
    env.execute();
    

    每隔30秒,统计一次过去1分钟的用户点击数量。

    输出结果:

    4> 2021-05-10T09:59:30,2021-05-10T10:00:30,张三,2
    4> 2021-05-10T10:00,2021-05-10T10:01,张三,3
    4> 2021-05-10T10:00:30,2021-05-10T10:01:30,张三,2
    4> 2021-05-10T10:01,2021-05-10T10:02,张三,2
    4> 2021-05-10T10:01:30,2021-05-10T10:02:30,张三,2
    4> 2021-05-10T10:02,2021-05-10T10:03,张三,1
    

4. Flink SQL 会话窗口实战

  1. 实现步骤

    • 初始化流运行环境

    • 在流模式下使用blink planner

    • 创建用户点击事件数据

    • 将源数据写入临时文件并获取绝对路径

    • 创建表载入用户点击事件数据

    • 对表运行SQL查询,并将结果作为新表检索

    • Table转换成DataStream

    • 执行任务

  2. 代码实现:

    代码:SessionUserClickApplication

    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
    EnvironmentSettings environmentSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build();
    StreamTableEnvironment tabEnv = StreamTableEnvironment.create(env, environmentSettings);
    
    // 将源数据写入临时文件并获取绝对路径
    String contents =
            "张三,http://taobao.com/xxx,2021-05-10 10:00:00\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:00:10\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:00:49\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:01:05\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:01:58\n" +
                    "张三,http://taobao.com/xxx,2021-05-10 10:02:10\n";
    String path = FileUtil.createTempFile(contents);
    
    String ddl = "CREATE TABLE user_clicks (\n" +
            "  username varchar,\n" +
            "  click_url varchar,\n" +
            "  ts TIMESTAMP(3),\n" +
            "  WATERMARK FOR ts AS ts - INTERVAL '2' SECOND\n" +
            ") WITH (\n" +
            "  'connector.type' = 'filesystem',\n" +
            "  'connector.path' = '" + path + "',\n" +
            "  'format.type' = 'csv'\n" +
            ")";
    
    tabEnv.sqlUpdate(ddl);
    
    //对表数据进行sql查询,并将结果作为新表进行查询,每隔30秒统计一次数据
    String query = "SELECT\n" +
            "  SESSION_START(ts, INTERVAL '30' SECOND),\n" +
            "  SESSION_END(ts, INTERVAL '30' SECOND),\n" +
            "  username,\n" +
            "  COUNT(click_url)\n" +
            "FROM user_clicks\n" +
            "GROUP BY SESSION (ts, INTERVAL '30' SECOND), username";
    
    Table result = tabEnv.sqlQuery(query);
    
    tabEnv.toAppendStream(result, Row.class).print();
    
    env.execute();
    

    每隔30秒统计一次用户点击数据.

    输出结果:

    4> 2021-05-10T10:00,2021-05-10T10:00:40,张三,2
    4> 2021-05-10T10:00:49,2021-05-10T10:01:35,张三,2
    4> 2021-05-10T10:01:58,2021-05-10T10:02:40,张三,2
    

本文由mirson创作分享,如需进一步交流,请加QQ群:19310171或访问www.softart.cn

第一章 整体介绍 2 1.1 什么是 Table APIFlink SQL 2 1.2 需要引入的依赖 2 1.3 两种 planner(old & blink)的区别 4 第二章 API 调用 5 2.1 基本程序结构 5 2.2 创建表环境 5 2.3 在 Catalog 中注册表 7 2.3.1 表(Table)的概念 7 2.3.2 连接到文件系统(Csv 格式) 7 2.3.3 连接到 Kafka 8 2.4 表的查询 9 2.4.1 Table API 的调用 9 2.4.2 SQL 查询 10 2.5 将 DataStream 转换成表 11 2.5.1 代码表达 11 2.5.2 数据类型与 Table schema 的对应 12 2.6. 创建临时视图(Temporary View) 12 2.7. 输出表 14 2.7.1 输出到文件 14 2.7.2 更新模式(Update Mode) 15 2.7.3 输出到 Kafka 16 2.7.4 输出到 ElasticSearch 16 2.7.5 输出到 MySql 17 2.8 将表转换成 DataStream 18 2.9 Query 的解释和执行 20 1. 优化查询计划 20 2. 解释成 DataStream 或者 DataSet 程序 20 第三章 流处理中的特殊概念 20 3.1 流处理和关系代数(表,及 SQL)的区别 21 3.2 动态表(Dynamic Tables) 21 3.3 流式持续查询的过程 21 3.3.1 将流转换成表(Table) 22 3.3.2 持续查询(Continuous Query) 23 3.3.3 将动态表转换成流 23 3.4 时间特性 25 3.4.1 处理时间(Processing Time) 25 3.4.2 事件时间(Event Time) 27 第四章 窗口(Windows) 30 4.1 分组窗口(Group Windows) 30 4.1.1 滚动窗口 31 4.1.2 滑动窗口 32 4.1.3 会话窗口 32 4.2 Over Windows 33 1) 无界的 over window 33 2) 有界的 over window 34 4.3 SQL 中窗口的定义 34 4.3.1 Group Windows 34 4.3.2 Over Windows 35 4.4 代码练习(以分组滚动窗口为例) 36 第章 函数(Functions) 38 5.1 系统内置函数 38 5.2 UDF 40 5.2.1 注册用户自定义函数 UDF 40 5.2.2 标量函数(Scalar Functions) 40 5.2.3 表函数(Table Functions) 42 5.2.4 聚合函数(Aggregate Functions) 45 5.2.5 表聚合函数(Table Aggregate Functions) 47
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

麦神-mirson

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

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

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

打赏作者

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

抵扣说明:

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

余额充值