DataStream API
1.DataStream 概览
1.1 使用示例
package com.lyh.flink
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
object SocketWindowWordCount {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
val dStream: DataStream[String] = env.socketTextStream("localhost", 9999, '\n')
val windowWordCount = dStream.flatMap(w => w.split("\\s"))
.map(w => WordWithCount(w, 1))
.keyBy(0)
.timeWindow(Time.seconds(5))
.sum(1)
.setParallelism(1)
windowWordCount.print()
env.execute("Socket Window WordCount")
}
case class WordWithCount(word: String, count: Int)
}
启动并查看结果:
nc -lk 9999
hello word word
1> WordWithCount(hello,1)
2> WordWithCount(word,2)
1.2 数据源 Data Source
- File
- readFile
- readTextFile
- Socket
- socketTextStream
- Collection
- fromCollection()
- fromElement()
- fromParallelCollection()
- Custom自定义
- addSource()方法
1.3 数据输出 Data Sink
- print()
- writeAsText()
- writeAsCsv()
- writeToSocket()
- writeUsingOutputFormat()
- addSink()
1.4 Opeator作用概览
算子名称 | 转换类型 | 描述 |
---|---|---|
map | DataStream → DataSteam | |
flatMap | DataStream → DataSteam | |
filter | DataStream → DataSteam | |
keyBy | DataStream → KeyedStream | |
reduce | KeyedStream → DataStream | |
fold | KeyedStream → DataStream | |
aggregations | KeyedStream → DataStream | sum,min,max,minBy,maxBy |
window | KeyedStream → DataStream | |
windowAll | DataStream → AllWindowedStream | |
window apply | WindowedStream → DataStream/AllWindowedStream → DataStream | |
window reduce | WindowedSteam → DataStream | |
fold | WindowedSteam → DataStream | |
aggregations on window | WindowedSteam → DataStream | sum,min,max,minBy,maxBy聚合函数 |
union | DataStream → DataStream | |
join | DataStream,DataStream → DataStream | |
intervalJoin | KeyedStream,KeyedStream → DataStream | |
coGroup | DataStream,DataStream → DataStream | |
connect | DataStream,DataStream → ConnectedStreams | |
coMap | ConnectedStreams → DataStream | |
split | DataStream → SplitStream | |
select | SplitStream → DataStream | |
iterator | DataStream → IterativeStream → DataStream | |
assignTimestamps | DataStream → DataStream |
1.5 KeyedStream
在flink中一个很重要的operator就是keyby这个算子,可能会占比到70-80%,我们着重理解一下keyedstream.假设一个有DataStream,按照窗口操作,比如1个小时的counter。如果这个1小时数据量非常的大,那么在flink单个taskmanager肯定算不完,需要多台计算节点来计算,这时候用到keyby将相同特性的key分发到不同的tm进行计算,最后对结果进行汇总保存这时候充分体现了flink分布式计算的威力。同时我们知道flink是状态流计算,调用keyby后可以由各小块计算只负责自己那一部分的状态,不用关心其他的状态。同时调用keyby后数据划分会非常明确,不会随任务的重启,并发度等影响,故在数据恢复时也会比较方便。最后注意应用keyby是一定要保证key的数量远远大于并发度,不然的话会有很多资源是空跑状态。
1.6 物理分组
global:无论下游有多少个实例,都会发往下游的第一个实例.A1->b1,A2->B2.很少用
brocast:将上游实例都发一份到下游所有实例。A1->(b1-b5) A2->(b1-b5) 广播适用于小内存算子
forward : 一对一发送 A1->A2,B1-B2
shuffle:随机分配
rebalance:round-robin分配
recale: local round-robin分配(在本机轮循)
partitionCustom():自定义分组逻辑,函数只能返回一个具体的下游实例,不能返回一组或多个,所以可以叫单播
1.7类型系统
DataStream需要一个明确的类型,例如:DataStream,DataStream<Tuple2<String,Integer>>
类型 | 说明 |
---|---|
基本类型 | String,java基本类型包装类 |
复合类型 | tuple或scala中的row, case class,POJO |
集合类型 | option,either,list,map |
上述类型的数组 | |
其他类型 | 自定义typeinformation或kryo不推荐使用 |
- Tuple不支持null字段,而且不能超过25个字段
- Row类型支持null字段
- 尽量使用flink内置的类型
2.DataStream API原理
一个DataStream是怎么转换为另一个DataStream的呢?
DataStream调用map方法-->
调用DataStream.transform方法(入参是一个function)-->
Function生成OneInputStreamOperator-->
OneInputStreamOperator生成OneInputTransformation,transformation会添加到transformations list中,后续生成StreamGraph时会用到-->
由OneInputTransformation可以生成SingleOutputStreamOperator-->
SingleOutputStreamOperator继承自DataStream也就是一个新的DataStream