1、map与flatMap
val streamMap = stream.map { x => x * 2 }
flatMap 的函数签名:
def flatMap[A,B](as: List[A])(f: A ⇒ List[B]): List[B]
例如:flatMap(List(1,2,3))(i ⇒ List(i,i))
结果是List(1,1,2,2,3,3)
,
而List("a b", "c d").flatMap(line ⇒ line.split(" "))
结果是List(a, b, c, d)
。
val streamFlatMap = stream.flatMap{
x => x.split(" ")
}
2、Filter
val streamFilter = stream.filter{
x => x == 1
}
3、KeyBy与滚动聚合算子(Rolling Aggregation)
DataStream → KeyedStream:KeyBy逻辑地将一个流拆分成不相交的分区,每个分区包含具有相同key 的元素,在内部以hash 的形式实现的。
KeyBy一般结合滚动聚合算子使用。滚动聚合算子(Rolling Aggregation)可以针对KeyedStream 的每一个支流做聚合。常用的滚动聚合算子:
sum()
min()
max()
minBy()
maxBy()
// 分组聚合,输出每个传感器当前最小值
val aggStream = dataStream
.keyBy("id") // 根据id进行分组
.minBy("temperature")
aggStream.print()
min与minBy的区别:
我们看sensor_1的结果,min(“temperature”)的结果只在乎temperature(第三列)的正确性,不管其他列与temperature是否正确对应,如timestamp(第二列)永远为sensor_1第一条数据的timestamp;而minBy(“temperature”)的结果会完整输出整条数据,对应关系也正确。
// 原始数据
sensor_1,1547718199,35.8
sensor_6,1547718201,15.4
sensor_7,1547718202,6.7
sensor_10,1547718205,38.1
sensor_1,1547718206,32
sensor_1,1547718208,36.2
sensor_1,1547718210,29.7
sensor_1,1547718213,30.9
// minBy结果
SensorReading(sensor_1,1547718199,35.8)
SensorReading(sensor_6,1547718201,15.4)
SensorReading(sensor_7,1547718202,6.7)
SensorReading(sensor_10,1547718205,38.1)
SensorReading(sensor_1,1547718206,32.0)
SensorReading(sensor_1,1547718206,32.0)
SensorReading(sensor_1,1547718210,29.7)
SensorReading(sensor_1,1547718210,29.7)
// min结果
SensorReading(sensor_1,1547718199,35.8)
SensorReading(sensor_6,1547718201,15.4)
SensorReading(sensor_7,1547718202,6.7)
SensorReading(sensor_10,1547718205,38.1)
SensorReading(sensor_1,1547718199,32.0)
SensorReading(sensor_1,1547718199,32.0)
SensorReading(sensor_1,1547718199,29.7)
SensorReading(sensor_1,1547718199,29.7)
4、Reduce
KeyedStream → DataStream:一个分组数据流的聚合操作,合并当前的元素和上次聚合的结果,产生一个新的值,返回的流中包含每一次聚合的结果,而不是只返回最后一次聚合的最终结果。
val stream2 = env.readTextFile("YOUR_PATH\\sensor.txt")
.map( data => {
val dataArray = data.split(",")
SensorReading(dataArray(0).trim, dataArray(1).trim.toLong,
dataArray(2).trim.toDouble)
})
.keyBy("id")
.reduce( new MyReduceFunction )
class MyReduceFunction extends ReduceFunction[SensorReading]{
//输出当前最小的温度值,以及最近的时间戳
override def reduce(x: SensorReading, y: SensorReading): SensorReading =
SensorReading(x.id, y.timestamp, x.temperature.min(y.temperature))
}
注:其中x为流操作上次的结果,y为本次新进入的数据。
也可以直接使用reduce函数
reduce( (x, y) => SensorReading(x.id, y.timestamp, x.temperature.min(y.temperature) )
5、Split 和Select(分流)
DataStream → SplitStream:根据某些特征把一个DataStream 拆分成两个或者多个DataStream。
SplitStream→DataStream:从一个SplitStream 中获取一个或者多个DataStream。
需求:传感器数据按照温度高低(以30 度为界),拆分成两个流。
val splitStream = dataStream
.split( data => {
if( data.temperature > 30.0 ) Seq("high") else Seq("low")
} )
val highTempStream = splitStream.select("high")
val lowTempStream = splitStream.select("low")
val allTempStream = splitStream.select("high", "low")
6、Connect 和CoMap(合流)
DataStream,DataStream → ConnectedStreams:连接两个保持他们类型的数据流,两个数据流被Connect之后,只是被放在了一个同一个流中,内部依然保持各自的数据和形式不发生任何变化,两个流相互独立。
ConnectedStreams → DataStream:作用于ConnectedStreams 上,功能与map和flatMap一样,对ConnectedStreams 中的每一个Stream 分别进行map 和flatMap处理。
// 合流,connect
val warningStream = highTempStream.map( data => (data.id, data.temperature) )
val connectedStreams = warningStream.connect(lowTempStream)
// 用coMap对数据进行分别处理
val coMapResultStream: DataStream[Any] = connectedStreams
.map(
waringData => (waringData._1, waringData._2, "warning") ,
lowTempData => (lowTempData.id, "healthy")
)
7、Union
DataStream → DataStream:对两个或者两个以上的DataStream 进行union 操作,产生一个包含所有DataStream 元素的新DataStream。
//合并以后打印
val unionStream = highTempStream.union(lowTempStream, allTempStream)
unionStream.print()
Connect 与Union 区别:
- Union 之前两个流的类型必须是一样,Connect 可以不一样,在之后的coMap 中再去调整成为一样的。
- Connect 只能操作两个流,Union 可以操作多个。