FlinkSql之TableAPI详解
一、FlinkSql的概念
核心概念
Flink 的 Table API 和 SQL 是流批统一的 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详解的更多相关文章
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Android Notification 详解(一)——基本操作
Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...
- Android Notification 详解——基本操作
Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...
- Git初探--笔记整理和Git命令详解
几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
- Node.js npm 详解
一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...
随机推荐
- JavaScript 异步编程(一):认识异步编程
前言 "异步"的大规模流行是在 Web 2.0浪潮中,它伴随着 AJAX 席卷了 Web.前端充斥了各种 AJAX 和事件,这些都是典型的异步应用场景.现在的 Web 应用已经不再 ...
- feign的fallback操作
Fallback可以帮助我们在使用Feign去调用另外一个服务时,如果出现了问题,走服务降级,返回一个错误数据,避免功能因为一个服务出现问题,全部失效. 依赖: <dependency> ...
- ARC120F Wine Thief (组合数学)
题面 有一个长为 N N N 的序列,相邻的两个数中只能选一个,总共选 k k k 个数,一种方案的价值为选的 k k k 个数的和,问所有合法方案的价值总和,答案对 998244353 取模. 1 ...
- HTML创建访问加密代码
在</head>前面加入即可 普通方式 此方法屏蔽F12查看源码但是屏蔽不了Ctrl+U查看源码 解决方式加密html即可注意!解密比较繁琐切记要记住自己设置的密码 <SCRIPT ...
- vs完整编译Opencv+contrib
准备条件 Opencv源码(以4.3.0为例) OpenContrib源码(以4.3.0)为例 最新版的CMake GUI CMake 生成项目 设置source code 和生成的build文件夹 ...
- Linux常用基础命令三
一.ln 软链接 软链接也称为符号链接,类似于 windows 里的快捷方式,有自己的数据块,主要存放 了链接其他文件的路径. 在查看文件目录中,软连接是以'l'开头 创建软链接 ln -s [原文件 ...
- KingbaseES 如何实现Oracle pipelined 功能
管道函数即是可以返回行集合(可以使嵌套表nested table 或数组 varray)的函数,我们可以像查询物理表一样查询它或者将其赋值给集合变量.KingbaseES 数据库可以用 setof 实 ...
- jenkins流水线部署springboot应用到k8s集群(k3s+jenkins+gitee+maven+docker)(2)
前言:上篇已介绍了jenkins在k3s环境部署,本篇继续上篇讲述流水线构建部署流程 1.从gitlab上拉取代码步骤 在jenkins中,新建一个凭证:Manage Jenkins -> Ma ...
- Openstack neutron:目录
为什么? 最近一直在学习SDN方面的知识,本着"最好的学习就是分享"的精神,记录下本系列的文章,尝试更好地去理解SDN这一正当红的技术. 如何? SDN领域现在已经充斥了大量的公司 ...
- Kibana:在Kibana中对数据进行深入分析 (drilldown)
文章转载自:https://blog.csdn.net/UbuntuTouch/article/details/105193907 在上面,我们需要把之前地址栏中拷贝的内容粘贴过来,并做相应的修改.针 ...