Flink学习12-FlinkTab&SQL(一)

概述

在这里插入图片描述
以上是Flink官方提供了四层不同级别的抽象来开发应用程序。Table Api实际上对底层算子的封装,而SQL则是最顶层的抽象。在生产开发中用到最多的也是SQL开发。接下来通过一个简单案例来了解Table API 和SQL的使用方式。

package com.TableAndSql;

import com.model.Access;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.api.Table;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
import org.apache.flink.types.Row;

public class Stream_Table_SQl {
    public static void main(String[] args) throws Exception{
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamTableEnvironment tableenv = StreamTableEnvironment.create(env);
        SingleOutputStreamOperator<Access> stream = env.readTextFile("/Users/IdeaProjects/Test/Flink_Project/Flink_BasedApi/src/main/java/com/data/1.txt")
                .map(new MapFunction<String, Access>() {
                    @Override
                    public Access map(String s) throws Exception {
                        String[] value = s.split(",");
                        Long time = Long.parseLong(value[0]);
                        String name = value[1];
                        Integer count = Integer.parseInt(value[2]);
                        return new Access(time, name, count);
                    }
                });
        //datastream ==> table
        Table table = tableenv.fromDataStream(stream);
        tableenv.createTemporaryView("access",table);
        //通过sql方式查询table

        Table query = tableenv.sqlQuery("select name,sum(conut) as counts from access group by name");

        //通过table api的方式查询table
       // Table query = table.select("*").where("name='wangwu'");
       // Table query = table.select($("name"),$("conut"));

        // table ==> datastream
       // tableenv.toAppendStream(query, Row.class).print();
        //tableenv.toAppendStream(query, Access.class).print("access:");

        tableenv.toRetractStream(query, Row.class).filter(x -> x.f0).print();
        env.execute("Stream_Table_SQl");
    }
}

在上述案例中实现的是从本地读取文件数据流,读出来的实际上还是datastream。既然要通过table或者sql操作数据流,所以需要将datastream转换成table。而datastream流里的元素通过封装成对象的三个字段传入到table里,所以我们不需要定义此表的表结构,在操作Table Api或者Sql时直接获取表字段即可。

Table Api对接方式

对于上述案例也可以这样改写:通过TableEnv直接读取本地文件,由于此时读取的是原始数据,所以在创建表之前需要提前定义好表结构。表结构分为两块去定义:format定义如何将二进制数据映射到表的列上(存储数据格式)。flink支持以下格式:
在这里插入图片描述
schema定义表字段类型。

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamTableEnvironment tableenv = StreamTableEnvironment.create(env);

        tableenv.connect(new FileSystem().path("/Users/IdeaProjects/Test/Flink_Project/Flink_BasedApi/src/main/java/com/data/1.txt"))
                .withFormat(new Csv())
                .withSchema(new Schema()
                        .field("timestamps", DataTypes.BIGINT())
                        .field("name", DataTypes.STRING())
                        .field("counts", DataTypes.INT())
                ).createTemporaryTable("usertab");
        Table usertab = tableenv.from("usertab");
        Table table = usertab.groupBy("name")
                .aggregate($("counts").sum().as("counts"))
                .select($("name"), $("counts"));
        tableenv.toRetractStream(table,Row.class).print();
SQL对接方式

对于上述案例也可以这样改写:SQL和Table本质相同,connect定义数据来源,format定义存储格式,schema定义表字段类型。flink官方支持以下connector:
在这里插入图片描述

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamTableEnvironment tableenv = StreamTableEnvironment.create(env);
        String sourcetab = "create table usertab(" +
                "timestamps BIGINT," +
                "name String," +
                "counts Int" +
                ")with(" +
                "'connector' = 'filesystem'," +
                "'path' = 'file:///Users/IdeaProjects/Test/Flink_Project/Flink_BasedApi/src/main/java/com/data/1.txt'," +
                "'format' = 'csv'" +
                ")";
        String sql = "select name,sum(counts) as counts from usertab group by name";
        tableenv.executeSql(sourcetab);
        Table table = tableenv.sqlQuery(sql);

        tableenv.toRetractStream(table, Row.class).print();

字段映射

还是分析上述案例,可以看到无论是Datastream Api、Table还是Sql都是在创建表之前做好字段映射。Flink中数据类型到表字段映射的方式有两种:基于字段位置映射和基于字段名称映射。按数据类型划分又可划分为:原子类型、Tuple类型、POJO类型、Row类型。其中原子类型、Tuple类型和Row类型是基于字段位置映射,POJO基于字段名称映射。这四种数据类型都有不同的使用局限:
在这里插入图片描述
尽一步分析,基于字段位置映射,就是定义的时候字段顺序要一致。如果不一致可能会导致字段与数据类型不匹配。而基于字段名称映射就不会有此类问题。上述第一个案例中就是POJO数据类型,按照名称进行匹配的。我们也可以改造成按照位置进行匹配,如下:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamTableEnvironment tableenv = StreamTableEnvironment.create(env);
        SingleOutputStreamOperator<Tuple3<Long, String, Integer>> stream = env.readTextFile("/Users/IdeaProjects/Test/Flink_Project/Flink_BasedApi/src/main/java/com/data/1.txt")
                .map(new MapFunction<String, Tuple3<Long, String, Integer>>() {
                    @Override
                    public Tuple3<Long, String, Integer> map(String value) throws Exception {
                        String[] values = value.split(",");
                        Long time = Long.parseLong(values[0]);
                        String name = values[1];
                        Integer count = Integer.parseInt(values[2]);
                        return Tuple3.of(time, name, count);
                    }
                });
        Table table = tableenv.fromDataStream(stream,$("time"),$("name"),$("count"));
        tableenv.createTemporaryView("access",table);
        Table query = tableenv.sqlQuery("select name,sum(conut) as counts from access group by name");
        tableenv.toRetractStream(query, Row.class).filter(x -> x.f0).print();
        env.execute("TableAndSqlTest");

流表数据相互转换

流式查询(streaming query)的结果表会动态更新,即,当新纪录到达查询的输入流时,查询结果会改变。因此,像这样将动态查询结果转换成 DataStream 需要对表的更新方式进行编码。
将 Table 转换为 DataStream 有两种模式:
Append Mode: 仅当动态 Table 仅通过INSERT更改进行修改时,才可以使用此模式,即,它仅是追加操作,并且之前输出的结果永远不会更新。对应toAppendStream方法
Retract Mode: 任何情形都可以使用此模式。它使用 boolean 值对 INSERT 和 DELETE 操作的数据进行标记。对应toRetractStream方法。
一般情况下涉及到聚合操作时需要使用Retract Mode。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值