一、FlinkSql的概念

核心概念

Flink 的 Table APISQL 是流批统一的 API。 这意味着 Table API & SQL 在无论有限的批式输入还是无限的流式输入下,都具有相同的语义。 因为传统的关系代数以及 SQL 最开始都是为了批式处理而设计的, 关系型查询在流式场景下不如在批式场景下容易理解.

动态表和连续查询

动态表(Dynamic Tables) 是 Flink 的支持流数据的 Table API 和 SQL 的核心概念。

与表示批处理数据的静态表不同,动态表是随时间变化的。可以像查询静态批处理表一样查询它们。查询动态表将生成一个连续查询(Continuous Query)。一个连续查询永远不会终止,结果会生成一个动态表。查询不断更新其(动态)结果表,以反映其(动态)输入表上的更改。

TableAPI

首先需要导入依赖

 <dependency>
     <groupId>org.apache.flink</groupId>
     <artifactId>flink-table-planner-blink_${scala.binary.version}</artifactId>
     <version>${flink.version}</version>
     <scope>provided</scope>
 </dependency>
 <dependency>
     <groupId>org.apache.flink</groupId>
     <artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
     <version>${flink.version}</version>
     <scope>provided</scope>
 </dependency>
 <dependency>
     <groupId>org.apache.flink</groupId>
     <artifactId>flink-csv</artifactId>
     <version>${flink.version}</version>
 </dependency>
 <dependency>
     <groupId>org.apache.flink</groupId>
     <artifactId>flink-json</artifactId>
     <version>${flink.version}</version>
 </dependency>
 ​
 <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
 <dependency>
     <groupId>org.apache.commons</groupId>
     <artifactId>commons-compress</artifactId>
     <version>1.21</version>
 </dependency>
 /**
  * 使用TableAPI的基本套路:
  * 1.创建表的执行环境
  * 2.创建表,将流转换为动态表,表的字段名从bean的属性名自动抽取
  * 3.对动态表进行查询
  * 4.把动态表转换为流
  */

这里需要注意的问题:

1.TableAPI 中将动态表转换为流时有两种方法

 DataStream<Row> rowDataStream = tableEnvironment.toAppendStream(result, Row.class);

toAppendStream方法只能在查询时使用,不能使用包含聚合函数等更新语句

 DataStream<Tuple2<Boolean, Row>> tuple2DataStream = tableEnvironment.toRetractStream(select, Row.class);

toRetractStream则可以使用

2.上述两种方法内传入的参数Row.class,表示将表中查询出的数据封装为行类型,也就是对每行进行封装,解决查询出的数据列少于或者多于原表。如何能够确保所查询的数据与之前封装的Bean有完全一致的结构则也可以封装为原Bean.class

代码实现:

 package net.cyan.FlinkSql;
 ​
 import net.cyan.POJO.WaterSensor;
 import org.apache.flink.api.common.functions.FilterFunction;
 import org.apache.flink.api.java.tuple.Tuple2;
 import org.apache.flink.configuration.Configuration;
 import org.apache.flink.streaming.api.datastream.DataStream;
 import org.apache.flink.streaming.api.datastream.DataStreamSource;
 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;
 ​
 import static org.apache.flink.table.api.Expressions.$;
 ​
 /**
  * 使用TableAPI的基本套路:
  * 1.创建表的执行环境
  * 2.创建表,将流转换为动态表,表的字段名从bean的属性名自动抽取
  * 3.对动态表进行查询
  * 4.把动态表转换为流
  */
 public class Demo1 {
     public static void main(String[] args) {
         Configuration configuration=new Configuration();
         configuration.setInteger("rest.port",3333);
         //创建执行环境
         StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(configuration);
         env.setParallelism(1);
         //模拟数据
         DataStreamSource<WaterSensor> WaterSensorSource = env.fromElements(
                 new WaterSensor("S1", 1000L, 10),
                 new WaterSensor("S1", 1000L, 10),
                 new WaterSensor("S2", 2000L, 20),
                 new WaterSensor("S3", 3000L, 30),
                 new WaterSensor("S4", 4000L, 40),
                 new WaterSensor("S5", 5000L, 50)
        );
         //创建表的执行环境
         StreamTableEnvironment tableEnvironment = StreamTableEnvironment.create(env);
         //创建表,将流转换为动态表,表的字段名从bean的属性名自动抽取
         Table table = tableEnvironment.fromDataStream(WaterSensorSource);
         //对表进行查询
         //1、过时的查询书写
         Table result = table
                .where("id='S1'")
                .select("*");
         //2、不过时的书写
         Table result1 = table
 //               .where($("id").isEqual("S1"))
                .select($("id"), $("ts"), $("vc"));
         //3.聚合函数
         Table select = table
                .groupBy($("id"))
                .aggregate($("vc").sum().as("sum_vc"))
                .select($("id"), $("sum_vc"));
         //把动态表转换为流,使用到了之前创建的表运行环境
 ​
         SingleOutputStreamOperator<Row> tuple2DataStream = tableEnvironment
                .toRetractStream(select, Row.class)
                .filter(t -> t.f0)
                .map(t -> t.f1);
 //       DataStream<Row> rowDataStream = tableEnvironment.toAppendStream(result, Row.class);
 //       DataStream<Row> rowDataStream1 = tableEnvironment.toAppendStream(result1, Row.class);
 //       rowDataStream.print();
 //       rowDataStream1.print();
         tuple2DataStream.print();
 ​
 ​
         try {
             //启动执行环境
             env.execute();
        } catch (Exception e) {
             e.printStackTrace();
        }
 ​
 ​
 ​
    }
 }

二、TableAPI读取文件

使用TableAPI读取文件时,我们首先需要知道去哪里读取也就是文件路径、读取文件的格式、读取出来的数据的结构也就是结果表的表结构及表名

 package net.cyan.FlinkSql;
 ​
 import org.apache.flink.configuration.Configuration;
 import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
 ​
 import org.apache.flink.table.api.DataTypes;
 import org.apache.flink.table.api.Table;
 import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
 import org.apache.flink.table.descriptors.Csv;
 import org.apache.flink.table.descriptors.FileSystem;
 import org.apache.flink.table.descriptors.Schema;
 import org.apache.flink.table.types.DataType;
 ​
 import static org.apache.flink.table.api.Expressions.$;
 ​
 public class Demo2_readWriteText {
     public static void main(String[] args) {
         //创建执行环境
 //       Configuration configuration = new Configuration();
 //       configuration.setInteger("rest.port", 3333);
         StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
         env.setParallelism(1);
         StreamTableEnvironment talEnv = StreamTableEnvironment.create(env);
         //创建查询的数据结果封装类型
         Schema schema = new Schema()
                .field("id", DataTypes.STRING())
                .field("ts", DataTypes.BIGINT())
                .field("vc", DataTypes.INT());
         talEnv
                .connect(new FileSystem().path("input/sensor.txt"))  //读取文件路径
                .withFormat(new Csv()) //读取文件的数据格式
                .withSchema(schema) //读取出来的数据格式
                .createTemporaryTable("sensor");//定义结果表名
 ​
         //进行查询
         Table select = talEnv.from("sensor")
                .where($("id").isEqual("sensor_1"))
                .select($("id"), $("ts"), $("vc"));
 ​
 ​
         //将查询结果写入到新文件中
         //同样建立一个动态表连接
         talEnv
                .connect(new FileSystem().path("input/b.txt"))  //写入路径
                .withFormat(new Csv()) //写入文件的数据格式
                .withSchema(schema) //写入的数据格式
                .createTemporaryTable("abc");//定义写入表名
         //进行写入操作
 ​
         select.executeInsert("abc");
 ​
 //       try {
 //           //启动执行环境
 //           env.execute();
 //       } catch (Exception e) {
 //           e.printStackTrace();
 //       }
 ​
    }
 }

三、TableAPI 读取、写入Kakfa

基本流程

1>需要创建表的运行环境

 //创建表的运行环境
 StreamTableEnvironment tabEnv = StreamTableEnvironment.create(env);

2>创建查询出的数据写出结构

 //创建表结构
 Schema schema=new Schema()
        .field("id",DataTypes.STRING())
        .field("ts",DataTypes.BIGINT())
        .field("vc",DataTypes.INT());

3> 创建kafka连接

 //创建kafka连接
 tabEnv.connect(
         new Kafka()
        .version("universal")// 版本号
        .property("bootstrap.servers","hadoop102:9092")//地址
        .property("group.id","cy")//消费者组
        .topic("first")//消费主题
 ​
  )
        .withFormat(new Json())//写入的格式
        .withSchema(schema)
        .createTemporaryTable("a");//临时表

4> 进行查询

 //创建表
 Table select = tabEnv.from("a").select("*");

5> 创建写入kafka连接

 //创建写入主题
 tabEnv.connect(
         new Kafka()
                .version("universal")// 版本号
                .property("bootstrap.servers","hadoop102:9092")//地址
                .topic("first1")//消费主题
                .sinkPartitionerRoundRobin()//随机分区
 ​
 )
        .withFormat(new Json())//写入的格式
        .withSchema(schema)
        .createTemporaryTable("c");

6> 写入

 //写入
 select.executeInsert("c");

完整代码如下

 package net.cyan.FlinkSql;
 ​
 import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
 import org.apache.flink.table.api.DataTypes;
 import org.apache.flink.table.api.Table;
 import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
 import org.apache.flink.table.descriptors.Json;
 import org.apache.flink.table.descriptors.Kafka;
 import org.apache.flink.table.descriptors.Schema;
 ​
 public class Demo5_readWriteKafka {
     public static void main(String[] args) {
        //创建执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
         //创建表的运行环境
         StreamTableEnvironment tabEnv = StreamTableEnvironment.create(env);
         //创建表结构
         Schema schema=new Schema()
                .field("id",DataTypes.STRING())
                .field("ts",DataTypes.BIGINT())
                .field("vc",DataTypes.INT());
         //创建kafka连接
         tabEnv.connect(
                 new Kafka()
                .version("universal")// 版本号
                .property("bootstrap.servers","hadoop102:9092")//地址
                .property("group.id","cy")//消费者组
                .topic("first")//消费主题
 ​
          )
                .withFormat(new Json())//写入的格式
                .withSchema(schema)
                .createTemporaryTable("a");
         //创建表
         Table select = tabEnv.from("a").select("*");
         //创建写入主题
         tabEnv.connect(
                 new Kafka()
                        .version("universal")// 版本号
                        .property("bootstrap.servers","hadoop102:9092")//地址
                        .topic("first1")//消费主题
                        .sinkPartitionerRoundRobin()//随即分区
 ​
        )
                .withFormat(new Json())//写入的格式
                .withSchema(schema)
                .createTemporaryTable("c");
 ​
         //写入
         select.executeInsert("c");
 ​
 ​
    }
 }
 

FlinkSql之TableAPI详解的更多相关文章

  1. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  2. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  3. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  4. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  5. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  6. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  7. Git初探--笔记整理和Git命令详解

    几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...

  8. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

  9. Node.js npm 详解

    一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...

随机推荐

  1. openstack 安装neutron网络服务安装 报错:Unknown operation 'enabled'

     注:这个脚本文件有一个地方是错误的,最后一行需要修改一下 # vim /usr/local/bin/iass-install-neutron-controller-gre.sh # 改systemc ...

  2. 【ARK UI】HarmonyOS ETS如何创建PixeMap并显示Image组件上

    ​参考资料 图片处理 Context模块 api讲解 image.createPixelMap createPixelMap(number: fd, options: InitializationOp ...

  3. React报错之Expected an assignment or function call and instead saw an expression

    正文从这开始~ 总览 当我们忘记从函数中返回值时,会产生"Expected an assignment or function call and instead saw an express ...

  4. HCIA-Datacom 4.1 实验一:访问控制列表配置实验

    实验介绍 访问控制列表ACL(Access Control List)是由一条或多条规则组成的集合.所谓规则,是指描述报文匹配条件的判断语句,这些条件可以是报文的源地址.目的地址.端口号等.ACL本质 ...

  5. 【java】学习路线14-抽象类、多态

    /*抽象类 abstractabstract class A{    }注意abstract类中不一定需要有abstract方法但是有abstract方法的类中,该类一定是abstract方法抽象类不 ...

  6. 【设计模式】Java设计模式 - 桥接模式

    [设计模式]Java设计模式 - 桥接模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起 ...

  7. Windows Server体验之SSH远程连接

    经过之前的各种远程管理方法,Windows Server可以被很好的管理,也能符合大多数Windows管理员的使用习惯.不过既然是命令行版本的Windows能不能和Linux一样管理呢?Windows ...

  8. Java套接字实现应用程序对数据库的访问

    最近在完成软件体系结构上机实验时,遇到一个有点点小难度的选做题,题目信息如下: 利用套接字技术实现应用程序中对数据库的访问.应用程序只是利用套接字连接向服务器发送一个查询的条件,而服务器负责对数据库的 ...

  9. PHP使用ZipArchive压缩、解压缩、加密压缩包等

    <?php use ZipArchive; class Zip { /** * @var array $files 需要压缩的文件或文件夹 */ public $files = []; /** ...

  10. 中国DevOps平台市场,华为云再次位居领导者位置

    摘要:华为云软件开发生产线DevCloud在市场份额和发展战略两大维度均排名第一,再次位居领导者位置. 9月21日 ,国际权威分析师机构IDC发布<IDC MarketScape: 中国 Dev ...