Flink 基本API
Flink剖析:
Flink程序看起来像是转换数据集合的常规程序。每个程序包含相同的基本部分:
1、获得一个execution environment,
2、加载/创建初始数据,
3、指定此数据的转换,
4、指定放置计算结果的位置,
5、触发程序执行
Flink程序是实现分布式集合转换的常规程序(例如,Filter,映射,更新状态,Join,分组,定义窗口,聚合)。
集合最初是从源创建的(例如,通过读取文件,kafka主题或从本地的内存中集合)。
结果通过接收器返回,接收器可以例如将数据写入(分布式)文件或标准输出(例如,命令行终端)。
Flink程序可以在各种环境中运行,独立运行或嵌入其他程序中。执行可以在本地JVM中执行,也可以在许多计算机的集群上执行。
所有Flink程序都是懒惰地执行:当执行程序的main方法时,数据加载和转换不会直接发生。而是创建每个算子操作并将其添加到程序的计划中。当execute()运行环境上的调用显式触发执行时,实际执行算子操作。程序是在本地执行还是在集群上执行取决于运行环境的类型
根据数据源的类型(即有界或无界源),编写批处理程序或流程序,
Scala DataSet API的类都可以在org.apache.flink.api.scala包中找到, DataSet API用于批处理
Scala DataStream API的类可以在org.apache.flink.streaming.api.scala中找到 。 DataStream API用于流式处理
特殊类DataSet:
Flink具有特殊类DataSet并DataStream在程序中表示数据。可以包含重复项的不可变数据集合。
在DataSet数据有限,DataStream数据元的数量可以是无界的。这些集合在某些关键方面与常规Java集合不同。首先,它们是不可变的,这意味着一旦创建它们就无法添加或删除数据元。你也不能简单地检查里面的数据元。集合最初通过在Flink程序添加源创建和新的集合从这些通过将它们使用API方法如衍生map,filter等等。
1、获得一个execution environment:
StreamExecutionEnvironment是所有Flink的基础。可以使用以下静态方法获取一个StreamExecutionEnvironment:getExecutionEnvironment()或者createLocalEnvironment()---->createRemoteEnvironment(host: String, port: Int, jarFiles: String*)
通常,只需要使用getExecutionEnvironment()
如果在IDE中执行程序或作为常规Java程序,它将创建一个本地环境,将在本地计算机上执行的程序。
如果从程序中创建了一个JAR文件,并通过命令行调用它,则Flink集群管理器将执行的main方法并getExecutionEnvironment()返回一个运行环境,以便在集群上执行的程序。
2、加载/创建初始数据:
对于指定数据源,运行环境有几种方法可以使用各种方法从文件中读取:
可以逐行读取它们,CSV文件或使用完全自定义数据输入格式。要将文本文件作为一系列行读取,可以使用:
val env = StreamExecutionEnvironment.getExecutionEnvironment()
val text: DataStream[String] = env.readTextFile("file:///path/to/file")
3、指定此数据的转换,
提供一个DataStream,然后可以在其上应用转换来创建新的派生DataStream。
通过使用转换函数调用DataSet上的方法来应用转换。例如,Map转换如下所示:
val input: DataSet[String] = ...
val mapped = input.map { x => x.toInt }
这将通过将原始集合中的每个String转换为Integer来创建新的DataStream。
4、指定放置计算结果的位置,
一旦有了包含最终结果的DataStream,就可以通过创建接收器将其写入外部系统。这些只是创建接收器的一些示例方法:
writeAsText(path: String)
print()
5、触发程序执行
一旦指定的完整程序,你需要触发执行程序调用 execute()上StreamExecutionEnvironment。根据执行的类型,ExecutionEnvironment将在本地计算机上触发执行或提交程序以在群集上执行。
该execute()方法返回一个JobExecutionResult,包含执行时间和累加器结果。
3、指定此数据的转换,
3.1、指定Keys:
某些转换(join,coGroup,keyBy,groupBy)要求在数据元集合上定义键。
其他转换(Reduce,GroupReduce,Aggregate,Windows)允许数据在应用之前在Keys上分组。
3.1.1DataSet被分组为
DataSet<...> input = // [...]
DataSet<...> reduced = input
.groupBy(/*define key here*/)
.reduceGroup(/*do something*/);
3.1.2使用DataStream指定Keys
DataStream<...> input = // [...]
DataStream<...> windowed = input
.keyBy(/*define key here*/)
.window(/*window specification*/);
Flink的数据模型不基于键值对。因此,无需将数据集类型物理打包到键和值中。键是“虚拟的”:它们被定义为实际数据上的函数,以指导分组算子。
3.2、定义元组的键
3.2.1最简单的情况是在元组的一个或多个字段上对元组进行分组:
DataStream<Tuple3<Integer,String,Long>> input = // [...]
KeyedStream<Tuple3<Integer,String,Long>,Tuple> keyed = input.keyBy(0)
3.2.2元组在第一个字段(整数类型)上分组。
DataStream<Tuple3<Integer,String,Long>> input = // [...]
KeyedStream<Tuple3<Integer,String,Long>,Tuple> keyed = input.keyBy(0,1)
在这里,将元组分组在由第一个和第二个字段组成的复合键上。
关于嵌套元组的注释:如果你有一个带有嵌套元组的DataStream,例如:DataStream<Tuple3<Tuple2<Integer, Float>,String,Long>> ds;
指定keyBy(0)将导致系统使用full Tuple2作为键(以Integer和Float为键)。
如果要定位到嵌套中Tuple2,则必须使用下面解释的字段表达式键:
1.使用Field Expressions定义键
可以使用基于字符串的字段表达式来引用嵌套字段,并定义用于分组,排序,连接或coGrouping的键。
字段表达式可以非常轻松地选择(嵌套)复合类型中的字段,例如Tuple和POJO类型。
java eg:我们有一个WCPOJO,其中包含两个字段“word”和“count”。
需求:按字段分组word,