Flink DataSteam操作

操作符将一个或多个数据流转换为新的数据流。程序可以将多个转换组合成复杂的数据流拓扑。

本节描述了基本转换、应用这些转换后的有效物理分区以及对Flink的操作符chaining的理解。

DataStream数据转换(DataStream Transformations)

Transformation Description
Map

DataStream → DataStream
取一个元素并生成一个元素。一个map 函数,使输入流的值加倍:
dataStream.map { x => x * 2 }

FlatMap

DataStream → DataStream
取一个元素并生成0个、1个或多个元素。一个flatmap函数,将句子分割成单词:
dataStream.flatMap { str => str.split(" ") }

Filter

DataStream → DataStream
为每个元素计算boolean函数,并保留该函数返回true的元素。过滤掉零值的过滤器:
dataStream.filter { _ != 0 }

KeyBy

DataStream → KeyedStream
逻辑上根据key对流分区,每个分区包含相同键的元素。 这是通过哈希分区实现的。有关如何指定键,请参见Key。这个转换返回一个KeyedStream。
dataStream.keyBy("someKey") // Key by field "someKey"
dataStream.keyBy(0) // Key by the first element of a Tuple

Reduce

KeyedStream → DataStream
keyed数据流上的"rolling" reduce。将当前元素与最后一个缩减值组合,并发出新值。

创建一个局部求和的reduce函数
keyedStream.reduce { _ + _ }

Fold

KeyedStream → DataStream
在一个keyed数据流上通过“滚动”折叠初始值,将当前元素与最后一个折叠值组合并发出新值。

当应用于序列(1,2,3,4,5)时,发出序列“start-1”、“start-1-2”、“start-1-2-3”、…

val result: DataStream[String] = keyedStream.fold("start")((str, i) => { str + "-" + i })

Aggregations

KeyedStream → DataStream
在keyed数据流上滚动聚合。min和minBy的区别是min返回最小值,而minBy返回该字段中值最小的元素(max和maxBy也是如此)。

keyedStream.sum(0)
keyedStream.sum("key")
keyedStream.min(0)
keyedStream.min("key")
keyedStream.max(0)
keyedStream.max("key")
keyedStream.minBy(0)
keyedStream.minBy("key")
keyedStream.maxBy(0)
keyedStream.maxBy("key")

Window

KeyedStream → WindowedStream
Windows可以在已经分区的KeyedStreams上定义。Windows根据一些特征对每个键中的数据进行分组(例如,最近5秒内到达的数据)。有关windows的描述,请参见windows。

dataStream.keyBy(0).window(TumblingEventTimeWindows.of(Time.seconds(5))) // Last 5 seconds of data

WindowAll

DataStream → AllWindowedStream
窗口可以在常规的数据流上定义。Windows根据一些特征对所有流事件进行分组(例如,最近5秒内到达的数据)。有关windows的完整描述,请参见windows。

注意:在许多情况下,这是非并行转换。windowAll操作符的所有记录将在一个任务中为完成。

dataStream.windowAll(TumblingEventTimeWindows.of(Time.seconds(5))) // Last 5 seconds of data

Window Apply

WindowedStream → DataStream
AllWindowedStream → DataStream
将通用函数作为一个整体应用于窗口。下面是一个手动求和窗口元素的函数。

注意:如果使用的是windowAll转换,则需要使用AllWindowFunction。

windowedStream.apply { WindowFunction }

// applying an AllWindowFunction on non-keyed window stream
allWindowedStream.apply { AllWindowFunction }

Window Reduce

WindowedStream → DataStream

对window 应用函数做reduce操作并返回reduce值。

windowedStream.reduce { _ + _ }

Window Fold
WindowedStream → DataStream
对窗口应用函数做flod操作并返回折叠值。将示例函数应用于sequence (1,2,3,4,5)时,将序列折叠成字符串“start-1-2-3-4-5”:

val result: DataStream[String] = windowedStream.fold("start", (str, i) => { str + "-" + i })

Aggregations on windows
WindowedStream → DataStream
聚合窗口的内容。min和minBy的区别在于,min返回最小值,而minBy返回该字段中最小值的元素(max和maxBy也是如此)。

windowedStream.sum(0)
windowedStream.sum("key")
windowedStream.min(0)
windowedStream.min("key")
windowedStream.max(0)
windowedStream.max("key")
windowedStream.minBy(0)
windowedStream.minBy("key")
windowedStream.maxBy(0)
windowedStream.maxBy("key")

Union
DataStream → DataStream
两个或多个数据流的Union,创建包含来自所有流的所有元素的新流。注意:如果您将一个数据流与它自己Union,您将在结果流中获得每个元素两次。

dataStream.union(otherStream1, otherStream2, ...)

Window Join
DataStream,DataStream → DataStream
Join指定key和公共窗口上的两个数据流。

dataStream.join(otherStream)
.where(<key selector>)
.equalTo(<key selector>)
.window(TumblingEventTimeWindows.of(Time.seconds(3)))
.apply { ... }

Window CoGroup
DataStream,DataStream → DataStream
将指定key和公共窗口上的两个数据流分组。dataStream.coGroup(otherStream)
.where(0).equalTo(1)
.window(TumblingEventTimeWindows.of(Time.seconds(3)))
.apply {}

Connect
DataStream,DataStream → ConnectedStreams
“Connects”两个保留类型的数据流,允许在两个流之间共享状态。

someStream : DataStream[Int] = ...
otherStream : DataStream[String] = ...

val connectedStreams = someStream.connect(otherStream)

CoMap, CoFlatMap
ConnectedStreams → DataStream
类似于连接数据流上的map和flatMap

connectedStreams.map(
(_ : Int) => true,
(_ : String) => false
)

connectedStreams.flatMap(
(_ : Int) => true,
(_ : String) => false
)

Split
DataStream → SplitStream
根据某种标准将流分成两个或多个流。

val split = someDataStream.split(
(num: Int) =>
(num % 2) match {
case 0 => List("even")
case 1 => List("odd")
})

Select
SplitStream → DataStream
从分割流中选择一个或多个流。

val even = split select "even"
val odd = split select "odd"
val all = split.select("even","odd")

Iterate
DataStream → IterativeStream → DataStream
通过将一个操作符的输出重定向到之前的某个操作符,在流中创建一个“反馈”循环。这对于定义持续更新模型的算法特别有用。下面的代码从一个流开始,并持续地应用迭代。大于0的元素被发送回反馈通道,其余的元素被转发到下游。有关完整描述,请参见迭代。

initialStream.iterate {
iteration => {
val iterationBody = iteration.map {/do something/}
(iterationBody.filter(_ > 0), iterationBody.filter(_ <= 0))
}
}

Extract Timestamps
DataStream → DataStream
从记录中提取时间戳,以便与使用事件时间语义的窗口一起工作。

stream.assignTimestamps { timestampExtractor }

通过匿名模式匹配从元组、case类和集合中提取,如下所示:

val data: DataStream[(Int, String, Double)] = // [...]
data.map {
  case (id, name, temperature) => // [...]
}

API不支持开箱即用。要使用这个特性,您应该使用Scala API扩展

元组的数据流可以进行以下转换:
JAVA

Transformation Description
Project
DataStream → DataStream
从元组中选择字段的子集

DataStream<Tuple3<Integer, Double, String>> in = // [...]
DataStream<Tuple2<String, Integer>> out = in.project(2,0);

物理分区(Physical partitioning)

Flink还通过以下函数对转换后的流分区进行低级控制(如果需要的话)。

Transformation Description
Custom partitioning
DataStream → DataStream
使用用户定义的分区器为每个元素选择目标任务。

dataStream.partitionCustom(partitioner, "someKey")
dataStream.partitionCustom(partitioner, 0)

Random partitioning
根据均匀分布随机划分元素。

dataStream.shuffle()

Rebalancing (Round-robin partitioning)
DataStream → DataStream
分区元素循环,每个分区创建相同的负载。对于数据倾斜情况下的性能优化非常有用。

dataStream.rebalance()

Rescaling
DataStream → DataStream
循环地将元素划分到下游操作的子集中。如果您希望在管道中。例如,从源的每个并行实例中向多个映射器的子集展开分配负载,但不希望使用rebalance()带来的完全再平衡,那么这种方法非常有用。这只需要本地数据传输,而不需要通过网络传输数据,这取决于其他配置值,比如TaskManagers的槽数。

上游操作向下游操作发送元素的子集依赖于上游和下游操作的并行度。例如,如果上游操作并行度为2,下游操作并行度为4,然后一个上游操作将元素分配给两个下游操作,而另一个上游操作将分配给另外两个下游操作。另一方面,如果下游操作具有并行性2,而上游操作具有并行性4,那么两个上游操作将分布到一个下游操作,而另外两个上游操作将分布到另一个下游操作。

如果不同的并行度不是彼此的倍数,那么一个或多个下游操作将具有来自上游操作的不同数量的输入。

在上面的例子中,连接模式的可视化如图所示:
dataStream.rescale()
Broadcasting
DataStream → DataStream
向每个分区广播元素。

dataStream.broadcast()

任务链和资源组(Task chaining and resource groups)

链接两个后续转换意味着将它们放在同一个线程中以获得更好的性能。如果可能的话,Flink默认情况下是链操作符(例如,两个后续的map转换)。如果需要,该API提供了对链接的细粒度控制:

如果想在整个作业中禁用链接,请使用StreamExecutionEnvironment.disableOperatorChaining()。对于更细粒度的控制,可以使用以下函数。请注意,这些函数只能在DataStream转换之后使用,因为它们引用前一个转换。例如,您可以使用someStream.map(…). startnewchain(),但不能使用someStream.startNewChain()

资源组是Flink中的插槽,参见插槽。如果需要,可以手动将操作符隔离在不同的插槽中。

Transformation Description
开始新链

从这个运算符开始,开始一个新的链。两个map()将被链接,filter()将不会链接到第一个映射器。

someStream.filter(...).map(...).startNewChain().map(...)

禁用链

禁用链map操作符

someStream.map(...).disableChaining()

集槽共享组
设置操作的槽共享组。Flink会将具有相同槽共享组的操作放到同一个槽中,同时将没有槽共享组的操作保留在其他槽中。这可以用来隔离槽。如果所有输入操作都在同一个槽共享组中,则从输入操作继承槽共享组。默认槽共享组的名称为“default”,可以通过调用slotSharingGroup(“default”)显式地将操作放入这个组中。

someStream.filter(...).slotSharingGroup("name")
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容