Flink程序骨架
- 获取一个
执行环境(execution environment)
; - 加载/创建初始数据;
- 指定数据相关的转换;
- 指定计算结果的存储位置;
- 触发程序执行;
示例程序
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;
public class WindowWordCount {
public static void main(String[] args) throws Exception {
//获取执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//
DataStream<Tuple2<String, Integer>> dataStream = env
//加载初始数据
.socketTextStream("localhost", 9999)
//数据转换
.flatMap(new Splitter())
.keyBy(value -> value.f0)
.window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
.sum(1);
//输出计算结果
dataStream.print();
//触发程序执行
env.execute("Window WordCount");
}
public static class Splitter implements FlatMapFunction<String, Tuple2<String, Integer>> {
@Override
public void flatMap(String sentence, Collector<Tuple2<String, Integer>> out) throws Exception {
for (String word: sentence.split(" ")) {
out.collect(new Tuple2<String, Integer>(word, 1));
}
}
}
}
#启动输入流
nc -lk 9999
执行模式:批执行模式和流执行模式
#命令行模式配置
bin/flink run -Dexecution.runtime-mode=BATCH <jarFile>
#代码方式配置
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRuntimeMode(RuntimeExecutionMode.BA
TCH);
Flink数据类型
Flink中如此多的类型统一使用TypeInformation类来表示,此抽象类为对应数据类型提供序列化功能;Flink会自动探测传入的数据类型,生成对应的TypeInformation,调用对应的序列化器,因此用户其实无须关心类型推测
Flink API层次
Flink 为流式/批式处理应用程序的开发提供了不同级别的抽象。
-
Flink API 最底层的抽象为有状态实时流处理。其抽象实现是 Process Function,并且 Process Function 被 Flink 框架集成到了 DataStream API 中来为我们使用。它允许用户在应用程序中自由地处理来自单流或多流的事件(数据),并提供具有全局一致性和容错保障的状态。此外,用户可以在此层抽象中注册事件时间(event time)和处理时间(processing time)回调方法,从而允许程序可以实现复杂计算。
-
Flink API 第二层抽象是 Core APIs。实际上,许多应用程序不需要使用到上述最底层抽象的 API,而是可以使用 Core APIs 进行编程:其中包含 DataStream API(应用于有界/无界数据流场景)和 DataSet API(应用于有界数据集场景)两部分。Core APIs 提供的流式 API(Fluent API)为数据处理提供了通用的模块组件,例如各种形式的用户自定义转换(transformations)、联接(joins)、聚合(aggregations)、窗口(windows)和状态(state)操作等。此层 API 中处理的数据类型在每种编程语言中都有其对应的类。
Process Function 这类底层抽象和 DataStream API 的相互集成使得用户可以选择使用更底层的抽象 API 来实现自己的需求。DataSet API 还额外提供了一些原语,比如循环/迭代(loop/iteration)操作。
-
Flink API 第三层抽象是 Table API。Table API 是以表(Table)为中心的声明式编程(DSL)API,例如在流式数据场景下,它可以表示一张正在动态改变的表。Table API 遵循(扩展)关系模型:即表拥有 schema(类似于关系型数据库中的 schema),并且 Table API 也提供了类似于关系模型中的操作,比如 select、project、join、group-by 和 aggregate 等。Table API 程序是以声明的方式定义应执行的逻辑操作,而不是确切地指定程序应该执行的代码。尽管 Table API 使用起来很简洁并且可以由各种类型的用户自定义函数扩展功能,但还是比 Core API 的表达能力差。此外,Table API 程序在执行之前还会使用优化器中的优化规则对用户编写的表达式进行优化。
表和 DataStream/DataSet 可以进行无缝切换,Flink 允许用户在编写应用程序时将 Table API 与 DataStream/DataSet API 混合使用。
-
Flink API 最顶层抽象是 SQL。这层抽象在语义和程序表达式上都类似于 Table API,但是其程序实现都是 SQL 查询表达式。SQL 抽象与 Table API 抽象之间的关联是非常紧密的,并且 SQL 查询语句可以在 Table API 中定义的表上执行。
DataStream API
基本数据流转换
- map:对DataStream中的每个元素使用自定义的mapper函数进行处理
// 函数式接口
// T为输入类型,O为输出类型
@FunctionalInterface
public interface MapFunction<T, O> extends Function, Serializable {
// 调用该API即继承并实现这个虚方法
O map(T value) throws Exception;
}
- fliter:对每个DataStream中的每个元素进行过滤
@Public
@FunctionalInterface
public interface FilterFunction<T> extends Function, Serializable {
//对输入数据进行判定
boolean filter(T value) throws Exception;
}
- flatmap:对输入每个元素进行转换,与map不同之处是,flatmao输出可以是0个,一个或多个;
@Public
@FunctionalInterface
public interface FlatMapFunction<T, O> extends Function, Serializable {
//输出为Collector集合
void flatMap(T value, Collector<O> out) throws Exception;
}
- 分组和聚合
keyby:根据事件的某种属性或数据的某个字段进行分组,转化成keyedStream;
Aggregation:聚合,常见的函数有sum、max、min等,需指定那个字段进行聚合;
reduce:聚合方法的一种,在KeyedStream上生效,接受两个输入,生成一个输出
@Public
@FunctionalInterface
public interface ReduceFunction<T> extends Function, Serializable {
//根据分组对元素进行合并
T reduce(T value1, T value2) throws Exception;
}
多数据流转换
- union:对同类型数据流进行合并成新的DataStream,数据按先进先出合并,且不去重;
- connect:连接两个不同的数据流,数据类型可以不同,连接后转化为ConnectStream,ConnectStream可以对两个数据流应用不同的处理方法,两个流可以共享状态;
RichFunction函数
相比不加Rich的函数增加了如下方法
- open():算子调用前会执行这个方法,进行一些初始化工作
- close():算子最后一次调用后执行这个方法,释放资源
- getRuntimeContext():获取运行时上下文,获取算子的信息,如并行度,任务序号,广播数据、累加器、数据监控
Table API和SQL
程序结构
// 创建TableEnvironment
TableEnvironment tableEnv = TableEnvironment.create(/*…*/);
//创建 source table,datagen是一个内置连接器,用于生成随机数
tableEnv.createTemporaryTable("SourceTable", TableDescriptor.forConnector("datagen")
.schema(Schema.newBuilder()
.column("f0", DataTypes.STRING())
.build())
.option(DataGenConnectorOptions.ROWS_PER_SECOND, 100L)
.build());
// 创建sink table blackhole是内置连接器,接收输入,一般用于测试,不是实质sink;
tableEnv.executeSql("CREATE TEMPORARY TABLE SinkTable WITH ('connector' = 'blackhole') LIKE SourceTable (EXCLUDING OPTIONS) ");
// 创建table
Table table1 = tableEnv.from("SourceTable");
// 创建table
Table table2 = tableEnv.sqlQuery("SELECT * FROM SourceTable");
// table1数据插入SinkTable
TableResult tableResult = table1.insertInto("SinkTable").execute();
动态表
- 批处理关系查询与流处理的区别
- 动态表持续查询
动态表表示不断流入的数据表,数据流是不断流入的,动态表也是随着新数据的流入不断更新的,动态表上的查询被称为持续查询,底层计算式持续不断的;
- 状态使用
Table API & SQL 程序是声明式的,管道内的状态会在哪以及如何被使用并不明确;Planner 会确认是否需要状态来得到正确的计算结果, 管道会被现有优化规则集优化成尽可能少地使用状态;
形如 SELECT ... FROM ... WHERE
这种只包含字段映射或过滤器的查询的查询语句通常是无状态的管道。 然而诸如 join、 聚合或去重操作需要在 Flink 抽象的容错存储内保存中间结果。
Catalogs
Catalog提供了元数据信息,如数据库、表、分区及其他外部系统中存储的函数和信息;四种类型
- GenericInMemoryCatalog
基于内存的Catalog,元数据自在session的生命周期内可用,flink默认catalog
- jdbcCatalog
用户可以将flink通过jdbc协议关联到数据库,使用方法参考jdbcCatalog文档
https://nightlies.apache.org/flink/flink-docs-release-1.16/zh/docs/connectors/table/jdbc/
- HiveCatalog
HiveCatalog
有两个用途:作为原生 Flink 元数据的持久化存储,以及作为读写现有 Hive 元数据的接口;Flink 的 Hive 文档 提供了有关设置 HiveCatalog
以及访问现有 Hive 元数据的详细信息。
- 用户自定义Catalog
函数
Table API & SQL提供给用户强大的操作数据的方法:函数。对于函数,可以有两个维度来对其分类。
第一个维度根据是否为系统内置来分类。系统内置函数(System Function)是Flink提供的内置函数,在任何地方都可以直接拿来使用。非系统内置函数一般注册到某个Catalog下的数据库里,该函数有自己的命名空间(Namespace),表示该函数归属于哪个Catalog和Database。
第二个维度根据是否为临时函数来分类。临时函数(Temporary Function)只存在于某个Flink Session中,Session结束后就被销毁,其他Session无法使用。非临时函数,又被称为持久化函数(Persistent Function),可以存在于多个Flink Session中,它可以是一个系统内置函数,也可以是一个目录函数。
Table API
使用示例
mport org.apache.flink.table.api.*;
import static org.apache.flink.table.api.Expressions.*;
EnvironmentSettings settings = EnvironmentSettings
.newInstance()
.inStreamingMode()
.build();
TableEnvironment tEnv = TableEnvironment.create(settings);
// 在表环境中注册 Orders 表
// ...
// 指定表程序
Table orders = tEnv.from("Orders"); // schema (a, b, c, rowtime)
Table counts = orders
.groupBy($("a"))
.select($("a"), $("b").count().as("cnt"));
// 打印
counts.execute().print();
具体使用参考文档
https://nightlies.apache.org/flink/flink-docs-release-1.16/zh/docs/dev/table/tableapi/
SQL
- SQL客户端
#启动客户端
./bin/sql-client.sh
三种可视化模式
#表格模式
SET 'sql-client.execution.result-mode' = 'table';
#变更日志模式,不会实体化和可视化结果,而是由插入(+)和撤销(-)组成的持续查询产生结果流。
SET 'sql-client.execution.result-mode' = 'changelog';
#Tableau模式(tableau mode)更接近传统的数据库,会将执行的结果以制表的形式直接打在屏幕之上。
SET 'sql-client.execution.result-mode' = 'tableau';
详细使用文档https://nightlies.apache.org/flink/flink-docs-release-1.16/zh/docs/dev/table/sqlclient/
- SQL Gateway
SQL Gateway是一个服务,可以多用户远程执行flinksql;通过访问8083端口执行flinksql
#启动SQL Gateway
./bin/sql-gateway.sh start -Dsql-gateway.endpoint.rest.address=localhost
详细文档https://nightlies.apache.org/flink/flink-docs-release-1.16/zh/docs/dev/table/sql-gateway/overview/
- sql语法
https://nightlies.apache.org/flink/flink-docs-release-1.16/zh/docs/dev/table/sql/overview/