文章目录
一 数据源及入口
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
//设置时间语义 时间发生时间
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
env.setParallelism(1)
val socketSource: DataStream[String] = env.socketTextStream("localhost", 7777)
val mapStream: DataStream[SensorReading] = socketSource
.map(data => {
val split: Array[String] = data.split("\\W+")
SensorReading(split(0).trim, split(1).trim.toLong, split(2).trim.toDouble)
})
//fun: (T, Option[S]) => (TraversableOnce[R], Option[S])): DataStream[R]
val richFlatMapStream: DataStream[SensorReading] = mapStream.
keyBy(_.id)
.flatMapWithState(tmpStageChangeFunction)
richFlatMapStream.print("warning")
env.execute()
}
二 key State
键控状态是根据输入数据流中定义的键(key)来维护和访问的。Flink为每个键值维护一个状态实例,并将具有相同键的所有数据,都分区到同一个算子任务中,这个任务会维护和处理这个key对应的状态。当任务处理一条数据时,它会自动将状态的访问范围限定为当前数据的key。因此,具有相同key的所有数据都会访问相同的状态。Keyed State很类似于一个分布式的key-value map数据结构,只能用于KeyedStream(keyBy算子处理之后)
Flink的Keyed State支持以下数据类型:
2.1 ValueState[T]保存单个的值,值的类型为T。
- get操作: ValueState.value()
- set操作: ValueState.update(value: T)
2.2 ListState[T]保存一个列表,列表里的元素的数据类型为T。基本操作如下:
- ListState.add(value: T)
- ListState.addAll(values: java.util.List[T])
- ListState.get()返回Iterable[T]
- ListState.update(values: java.util.List[T])
2.3 MapState[K, V]保存Key-Value对。
- MapState.get(key: K)
- MapState.put(key: K, value: V)
- MapState.contains(key: K)
- MapState.remove(key: K)
2.4 ReducingState[T]
2.5 AggregatingState[I, O]
2.6 State.clear()是清空操作。
三 RichFlatMapFunction
class TempFlatMapFunction(limit:Long) extends RichFlatMapFunction[SensorReading,SensorReading]{
// 定义状态 缓存上次的温度值
var tmpState:MapState[String,Double]= _;
override def open(parameters: Configuration): Unit = {
tmpState= getRuntimeContext.getMapState(new MapStateDescriptor[String,Double]("lastTemp",classOf[String],classOf[Double]))
}
override def flatMap(in: SensorReading, collector: Collector[SensorReading]): Unit = {
// 从状态中取出当前的
val lastTmp = tmpState.get(in.id)
val diff = (lastTmp-in.tm).abs
if(diff > limit){
collector.collect(in)
}
tmpState.put(in.id,in.tm) // 更新状态的值
}
}
四 flatMapWithState
调用:
val richFlatMapStream: DataStream[SensorReading] = mapStream.
keyBy(_.id)
.flatMapWithState(tmpStageChangeFunction)
//函数
def tmpStageChangeFunction(v:SensorReading,option: Option[Double])={
option match {
case None =>(List.empty,Some(v.tm)) //第一次没值的时候 取当前数据的温度
case Some(value)=>{
val diff: Double =(v.tm-value).abs //有值则判断 温度变化范围是否超过了 预设的值
if(diff> 17){
(List(v),Some(v.tm))
}else{
(List.empty,None)
}
}
}
}