一、Flink SQL简介
Flink SQL是apache Flink中的一种声明式的SQL API,它允许用户已SQL语句的形式对有界(批处理)和无界(流处理)数据进行查询和分析。
中文官网:【https://nightlies.apache.org/flink/flink-docs-release-1.18/zh/docs/dev/】
1.1 Flink SQL 特点
-
统一的批流处理:
Flink SQL对批处理和流处理提供了统一的编程模型。 使用相同的SQL雨具,可以处理静态数据集(批处理)以及实时流入的动态数据(流处理) -
声明式编程:
用户只需要通过SQL语句描述所需的数据转换和查询逻辑,而无需关心底层的世贤细节。
比如,要从一个包含用户行为数据的表中筛选出特定时间段内活跃用户的行为记录,只需要用SQL的WHERE子句指定时间范围和活跃用户的条件即可,无需手动编写复杂的代码逻辑来实现数据筛选和处理。 -
与标准SQL高度兼容:
Flink SQL支持大部分标准的SQL语法。
比如,常见的SELECT、JOIN、GROUP BY等操作在Flink SQL中都有相应的视线,并且语法类似。 -
可扩展性:
Flink SQL可以与FLINK的其他功能模块(如用户自定义函数、连接器等)结合使用,满足复杂的业务需求。
比如,如果要对数据进行特定的业务逻辑处理,可以自定义一个函数并在FlInk SQL 中调用,同时,可以通过连接器链接到各种数据源(包kafka、hive、JDBC数据源等)进行数据的输入和输出
1.2 工作原理
-
解析和验证:
当用户提交一个Flink SQL查询时,首先会被解析器 解析成 抽象语法树(AST)。然后,验证器 会对AST进行验证,检查语法是否正确以及所引用的表和列是否存在等。 -
优化:
进过验证的查询 会被 优化器 进行优化。优化器会根据查询的特点和数据的分布情况,生成最优的执行计划。 -
执行:
优化后的执行计划会被 转换成 Flink的数据流图(Dataflow Graph),并由Flink的 执行引擎 执行。
在流处理模式下,数据会持续流入,Flink SQL 会实时处理数据并输出结果;
在批处理模式下,数据会一次性加载并进行处理;
1.3 应用场景
-
实时数据分析:
在金融领域,实时监控股票交易数据,计算股票价格的移动平均线、涨跌幅等指标;
在电商领域,实时分析用户的行为数据,如用户点击、购买行为等,一遍及时调整营销策略; -
数据集成
可以使用Flink SQL从多个数据源(如数据库、消息队列、文件系统等)读取数据,进行清洗、转换 和整合,然后将结果写入到目标数据源中。 -
ETL(Extract,Transformation,Load)任务
执行数据抽取、转换和加载任务。 从原始数据源中抽取数据,进行各种数据转换操作(如数据清洗、格式转换、字段计算等),然后将处理后的数据加载到目标存储系统中。
例如,从日志文件中抽取数据,去除无效记录,转换数据格式,然后加载到数据库中供后续分析使用。
二、Flink SQL语法
2.1 CREATE create语句
根据指定的表名创建一个表,如果同名表存在,则无法创建。
- 定义表
Flink SQL使用CREATE TABLE语句来定义数据源。
CREATE TABLE kafka_table(
id BIGINT,
name STRING,
ts TIMESTAMP(3)
)WITH (
'connector' = 'kafka',
'topic' = 'test_topic',
'properties.bootstrp.servers' = 'localhost:9092',
'format' = 'json',
'scan.startup.mode' ='earliest - offset'
);
定义一个名为mytable的表,包含id(长整型)、name(字符串)、ts(时间戳,进度为毫秒)的三个列。
WITH子句指定了 kafka 连接器的相关属性,包括
connector(连接器类型为kafka)、
topic(读取的kafka主题)、
properties.bootstrp.servers(卡发卡服务器的地址)、
format(数据格式为json)、
scan.startup.mode(从最早的偏移量开始读取)
CREATE TABLE my_mysql_table (
id INT,
name VARCHAR(50),
age INT
) WITH (
'connector' = 'jdbc',
'url' = 'jdbc:mysql://localhost:3306/mydatabase',
'username' = 'your_username',
'password' = 'your_password',
'table - name' = 'mytable_in_mysql'
);
在上述示例中:
connector = ‘jdbc’:指定使用 JDBC Connector 来连接外部数据库。
url:指定了 MySQL 数据库的连接地址。localhost表示本地主机,3306是 MySQL 的默认端口,mydatabase是你要连接的数据库名称。
username和password:是用于登录 MySQL 数据库的用户名和密码。
table - name:是 MySQL 数据库中你要与之交互的表的名称。
- 自定义数据源(通过实现接口)
除了连接常见的数据源,我们还可以自定义数据源。这需要实现TableSource接口。例如,定义一个简单的自定义数据源来生成数字序列
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.api.DataTypes;
import org.apache.flink.table.api.TableSchema;
import org.apache.flink.table.sources.StreamTableSource;
import java.util.Arrays;
import java.util.List;
public class CustomNumberSource implements StreamTableSource<Integer> {
private final List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
@Override
public DataStream<Integer> getDataStream(StreamExecutionEnvironment execEnv) {
return execEnv.fromCollection(numbers);
}
@Override
public TableSchema getTableSchema() {
return TableSchema.builder()
.field("number", DataTypes.INT())
.build();
}
}
然后再Flink SQL环境中注册这个定义数据源:
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
EnvironmentSettings settings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build();
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, settings);
tableEnv.registerTableSource("custom_number_table", new CustomNumberSource());
2.2 SELECT select语句
2.2.1 简单查询
从前面定义的kafka_table中查询id和name 列:
SELECT id,name From kafka_table;
这里返回一个包含id和name的两列数据的结果集
2.2.2 过滤操作
使用where 子句进行过滤,例如 从kafka_name中查询id 大于10且name以“A”开头 的记录
select * from kafka_name where id > 10 and name like ‘A%’;
2.2.3 聚合操作
sum、count、avg、group by等,
比如计算kafka_table中id的总和:select sum(id) from kafka_name;
分组聚合,按name分组计算id的平均值:select name, avg(id) from kafka_name group name;
2.2.4 窗口操作(针对流数据)
对于流数据,窗口操作非常重要。
例如,定义一个滚动窗口来计算每10秒内id的总和:
SELECT TUMBLE_START(ts, INTERVAL '10' SECOND) as window_start, SUM(id)
FROM kafka_table
GROUP BY TUMBLE(ts, INTERVAL '10' SECOND);
这里使用TUMBLE函数来定义滚动窗口,TUMBLE_START函数用于获取窗口的开始时间,对id进行求和操作实在每个10秒的窗口内惊醒的。
2.3 INSERT 语句
插入到另一个表(可以是外部存储)
使用insert into 语句将查询到的结果插入到另一个表中。
例如,将前面查询到的id>10的记录插入到一个名为filtered_table表中
INSERT INTO filtered_table
SELECT * FROM kafka_table WHERE id > 10;
2.4 输出到控制台(用于调试)
可以将结果输出到控制台进行调试。
在java代码中,执行查询并将结果转换为DataStream后打印输出:
Table resultTable = tableEnv.sqlQuery("SELECT * FROM kafka_table WHERE id > 10");
DataStream<Row> resultStream = tableEnv.toDataStream(resultTable);
resultStream.print();
三、基础流程
1. 所有Flink的操作都是基于StreamExecutionEnvironment;
2.