声明: 1. 本文为我的个人复习总结, 并非那种从零基础开始普及知识 内容详细全面, 言辞官方的文章
2. 由于是个人总结, 所以用最精简的话语来写文章
3. 若有错误不当之处, 请指出
FlinkSQL & TableAPI:
创建表环境, 创建表, 表数据和流数据的互转 要用到TableAPI
对于写SQL部分:
FlinkSQL是直接写SQL, 查询用的直接就是SQL的select关键字,
而TableAPI的查询用的是select( )API;
API是流批一体
Table:
表是由 CataLog+数据库+表名 组成的, CataLog和数据库有默认值
CataLogSchema > DataBaseSchema > Table
CataLogSchema 里存储元数据信息, 如数据库, 表, 视图的信息
创建表环境:
// 直接创建, 基于流处理
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
// 带上EnvironmentSettings的方式
// 基于流处理
EnvironmentSettings bsSettings = EnvironmentSettings.newInstance( )
.useBlinkPlanner( )
.inStreamingMode( )
.build( );
StreamTableEnvironment bsTableEnv = StreamTableEnvironment.create(env, bsSettings);
// 基于批处理
EnvironmentSettings bbSettings = EnvironmentSettings.newInstance( )
.useBlinkPlanner( )
.inBatchMode( )
.build( );
TableEnvironment bbTableEnv = TableEnvironment.create(bbSettings);
输入:
1. 把DataStream转为Table(常用):
这种表的数据是不断变化的, 是动态表
Table sensorTable = tableEnv.fromDataStream(dataStream, "id, timestamp.rowtime as ts, temperature");
2. 根据外部系统创建Table:
需要自己指明文件格式(用来分割字段), 字段名称
通过定义TableSchema:
CSV:
tableEnv.connect(new FileSystem( ).path("sensor.txt"))
.withFormat(new Csv( ))
.withSchema(new Schema( )
.field("id", DataTypes.STRING( ))
.field("timestamp", DataTypes.BIGINT( ))
.field("temperature", DataTypes.DOUBLE( ))
)
.createTemporaryTable("inputTable");
Kafka:
tableEnv.connect(
new Kafka( )
.version("0.11")
.topic("sensor")
.property("zookeeper.connect", "localhost:2181")
.property("bootstrap.servers", "localhost:9092"))
.withFormat(new Csv( ))
.withSchema(new Schema( )
.field("id", DataTypes.STRING( ))
.field("timestamp", DataTypes.BIGINT( ))
.field("temperature", DataTypes.DOUBLE( ))
)
.createTemporaryTable("kafkaInputTable");
通过写SQL的DDL语句:
String sinkDDL = "create table dataTable (" +
" id varchar(20) not null, " +
" ts bigint, " +
" temperature double"
) with (" +
" 'connector.type' = 'filesystem', " +
" 'connector.path' = '/sensor.txt', " +
" 'format.type' = 'csv')";
tableEnv.sqlUpdate(sinkDDL);
还支持: ElasticSearch、MySQL、HBase、Hive
指定时间字段 & 时间语义:
-
DataStream 转化成 Table 时指定
// 事件时间, 在DataStream里指定watermark延迟时间 .assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<SensorReading>(Time.seconds(1)) { @Override public long extractTimestamp(SensorReading element) { return element.getTimestamp( ) * 1000L; } }); Table sensorTable = tableEnv.fromDataStream(dataStream, "id, temperature, timestamp.rowtime"); //处理时间, 新增一个字段作为时间字段 Table sensorTable = tableEnv.fromDataStream(dataStream, "id, temperature, timestamp, pt.proctime");
-
定义 Table Schema 表结构时指定
// 事件时间 tableEnv.connect( new FileSystem( ).path("sensor.txt")) .withFormat(new Csv( )) .withSchema(new Schema( ) .field("id", DataTypes.STRING( )) .field("timestamp", DataTypes.BIGINT( )) .rowtime( new Rowtime( ) .timestampsFromField("timestamp") .watermarksPeriodicBounded(1000) ) .field("temperature", DataTypes.DOUBLE( )) ) .createTemporaryTable("inputTable"); // 处理时间 tableEnv.connect( new FileSystem( ).path("..\\sensor.txt")) .withFormat(new Csv( )) .withSchema(new Schema( ) .field("id", DataTypes.STRING( )) .field("timestamp", DataTypes.BIGINT( )) .field("temperature", DataTypes.DOUBLE( )) .field("pt", DataTypes.TIMESTAMP(3)) .proctime( ) ) .createTemporaryTable("inputTable");
-
创建表时写SQL的DDL语句中指定
// 事件时间 String sinkDDL = "create table dataTable (" + " id varchar(20) not null, " + " ts bigint, " + " temperature double, " + " rt AS TO_TIMESTAMP( FROM_UNIXTIME(ts) ), " + " watermark for rt as rt - interval '1' second" + ") with (" + " 'connector.type' = 'filesystem', " + " 'connector.path' = '/sensor.txt', " + " 'format.type' = 'csv')"; tableEnv.sqlUpdate(sinkDDL); // 处理时间 String sinkDDL = "create table dataTable (" + " id varchar(20) not null, " + " ts bigint, " + " temperature double, " + " pt AS PROCTIME( ) " + ") with (" + " 'connector.type' = 'filesystem', " + " 'connector.path' = '/sensor.txt', " + " 'format.type' = 'csv')"; tableEnv.sqlUpdate(sinkDDL);
输出:
1. 把Table转为DataStream:
没聚合操作 || 聚合 + window, 一般用追加模式 (在窗口关闭时才进行计算, 就也为追加模式了)
聚合+非window, 一般用撤回模式(有更新操作)
-
追加模式
DataStream<Row> resultStream = tableEnv.toAppendStream(resultTable,Row.class);
-
撤回模式
DataStream<Tuple2<Boolean, Row>> aggResultStream = tableEnv.toRetractStream(aggResultTable, Row.class);aggResultStream.print("aggResult");
2. 输出到外部系统:
文件:
// 构建TableSink表信息tableEnv.connect(new FileSystem( ).path("…\\resources\\out.txt")) .withFormat(new Csv( )) .withSchema(new Schema( ) .field("id", DataTypes.STRING( )) .field("temp", DataTypes.DOUBLE( )) ) .createTemporaryTable("outputTable"); // 输出到TableSinkresultSqlTable.insertInto("outputTable");
更新模式:
-
追加模式(Append Mode)
只有insert
-
撤回模式(Retract Mode)
有insert, delete
-
更新插入模式(Upsert Mode)
有upsert
输出到外部文件系统时才能用(控制台打印时没法撤回的)
Window:
-
滚动窗口
TUMBLE(time_attr, interval)
TUMBLE_PROCTIME(time_attr, interval)
TUMBLE_ROWTIME(time_attr, interval)
-
滑动窗口
HOP(time_attr, interval, interval)
HOP_PROCTIME(time_attr, interval, interval)
HOP_ROWTIME(time_attr, interval, interval)
这里参数是与DataStream反着来的, 第一个interval是窗口滑动步长, 第二个interval是窗口大小
-
会话窗口
SESSION(time_attr, interval)
SESSION_PROCTIME(time_attr, interval)
SESSION_ROWTIME(time_attr, interval)
其他相关函数:
TUMBLE_START(time_attr, interval)
HOP_START(time_attr, interval, interval)
SESSION_START(time_attr, interval)
HOP_ROWTIME(time_attr, interval, interval)
SESSION_ROWTIME(time_attr, interval)
函数:
系统函数:
power(x,y)
upper(“hello”)
char_length(“hello”)
date ‘2020-06-14’
timestamp ‘2020-06-14’
to_timestamp (from_unixtime(ts, ‘格式’)) 格式默认为’YYYY-MM-DD hh:mm:ss’
current_time
开创函数over:
partitionBy 可选
orderBy 必选, 且指定字段为 时间语义的字段(是处理时间时, 额外生成了一个时间字段)
preceding 可选
自定义UDF:
- 继承ScalarFunction
- 编写eval方法
自定义UDTF:
- 继承TableFunction<OUT>
- 编写eval方法
SQL写法, 字段可以被单引号引住
侧写:
-- 相当于隐式地 侧写split(id) as idselect id, word from movie, lateral table(split(id))
自定义UDAF:
-
继承AggregateFunction<OUT,STATE>
STATE是中间数据类型
-
重写createAccumulator方法
-
重写getValue方法
-
编写accumulate方法
自定义UDTAF
这个只能用TableAPI的方式, 不支持FlinkSQL的方式
常用作求topN
其实就是先分组, 后聚合侧写(这个聚合侧写是输出每个小组里的topN)
- 继承TableAggregateFunction<OUT,STATE>
- 重写createAccumulator方法
- 编写emitValue方法
- 编写accumulate方法
Join:
join时肯定要用到状态, 可以指定状态的最大时间
// 0代表状态永不清空tableEnv.getConfig( ).setIdleStateRetention(Duration.ofSeconds(10))
这个最大时间是指 距离最近一次使用
超过多长时间后才清空, 类似于Session的概念
底层实现起来就是定时器:
定时器里去执行清空状态的任务, 每当有数据发生join时: 便把当前定时器删掉, 然后重新注册定时器