Flink项目实战篇 基于Flink的城市交通监控平台(下)

系列文章目录

Flink项目实战篇 基于Flink的城市交通监控平台(上)
Flink项目实战篇 基于Flink的城市交通监控平台(下)



4. 智能实时报警

本模块主要负责城市交通管理中,可能存在违章或者违法非常严重的行为,系统可以自动实时报警。可以实现亿级数据在线分布式计算秒级反馈。满足实战的“实时”需要,争分夺秒、聚力办案。做的真正“零”延迟的报警和出警。主要功能包括:实时套牌分析,实时危险驾驶分析等。

4.1 实时套牌分析

当某个卡口中出现一辆行驶的汽车,我们可以通过摄像头识别车牌号,然后在10秒内,另外一个卡口(或者当前卡口)也识别到了同样车牌的车辆,那么很有可能这两辆车之中有很大几率存在套牌车,因为一般情况下不可能有车辆在10秒内经过两个卡口。如果发现涉嫌套牌车,系统实时发出报警信息,同时这些存在套牌车嫌疑的车辆,写入Mysql数据库的结果表中,在后面的模块中,可以对这些违法车辆进行实时轨迹跟踪。

本需求可以使用CEP编程,也可以使用状态编程。我们采用状态编程。

完整的代码:

object RepatitionCarWarning {
   
   
  def main(args: Array[String]): Unit = {
   
   
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //导入scala包
    import org.apache.flink.streaming.api.scala._

    //设置并行度
    env.setParallelism(1)

    //设置事件时间
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

    val props = new Properties()
    props.setProperty("bootstrap.servers","mynode1:9092,mynode2:9092,mynode3:9092")
    props.setProperty("group.id","test4")
    props.setProperty("key.deserializer",classOf[StringDeserializer].getName)
    props.setProperty("value.deserializer",classOf[StringDeserializer].getName)

    val trafficDStream: DataStream[TrafficLog] = env.addSource(new FlinkKafkaConsumer[String]("traffic-topic", new SimpleStringSchema(), props).setStartFromEarliest())
//    val trafficDStream: DataStream[TrafficLog] = env.socketTextStream("mynode5",9999)
      .map(line => {
   
   
        val arr: Array[String] = line.split(",")
        TrafficLog(arr(0).toLong, arr(1), arr(2), arr(3), arr(4).toDouble, arr(5), arr(6))
      }).assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[TrafficLog](Time.seconds(5)) {
   
   
      override def extractTimestamp(element: TrafficLog): Long = element.actionTime
    })

    trafficDStream.keyBy(_.car).process(new KeyedProcessFunction[String,TrafficLog,RepatitionCarInfo] {
   
   
      lazy private val valueState: ValueState[TrafficLog] = getRuntimeContext.getState(new ValueStateDescriptor[TrafficLog]("valueState",classOf[TrafficLog]))

      override def processElement(value: TrafficLog, ctx: KeyedProcessFunction[String, TrafficLog, RepatitionCarInfo]#Context, out: Collector[RepatitionCarInfo]): Unit = {
   
   
        if(valueState.value() != null){
   
   //如果状态中包含当前车辆
          val log: TrafficLog = valueState.value()
          //同一车辆数据,判断两次通过卡扣间隔时长
          var dur = (log.actionTime  - value.actionTime).abs
          if(dur < 10*1000){
   
   
            out.collect(new RepatitionCarInfo(value.car,"涉嫌套牌",System.currentTimeMillis(),
              s"该车辆连续两次经过的卡扣及对应时间为:${log.monitorId} - ${log.actionTime} , ${value.monitorId} - ${value.actionTime} "))
          }
          //更新状态数据
          if(log.actionTime < value.actionTime){
   
   
            valueState.update(value)
          }
        }else{
   
    //状态中不包含当前车辆
          valueState.update(value)
        }
      }
    })
        .addSink(new JdbcWriteSink[RepatitionCarInfo]("RepatitionCarInfo"))

    env.execute()
  }
}

4.2 实时危险驾驶分析

在本项目中,危险驾驶是指在道路上驾驶机动车:追逐超速竞驶。我们规定:如果一辆机动车在2分钟内,超速通过卡口超过3次以上;而且每次超速的超过了规定速度的20%以上;这样的机动车涉嫌危险驾驶。系统需要实时找出这些机动车,并报警,追踪这些车辆的轨迹。注意:如果有些卡口没有设置限速值,可以设置一个城市默认限速。

这样的需求在Flink也是有两种解决思路,第一:状态编程。第二:CEP编程。但是当前的需求使用状态编程过于复杂了。所以我们采用第二种。同时还要注意:Flume在采集数据的过程中出现了数据乱序问题,一般最长延迟5秒。

涉嫌危险驾驶的车辆信息保存到Mysql数据库表(t_violation_list)中,以便后面的功能中统一追踪这些车辆的轨迹。

注意:如果要设置水位线需要设置在两个连接流连接之后。

完整的代码:

case class newTrafficLog(actionTime:Long,monitorId:String,cameraId:String,car:String,speed:Double,roadId:String,areaId:String,monitorLimitSpeed:Int)

object DangerDriveCarWarning {
   
   
  def main(args: Array[String]): Unit = {
   
   
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment

    //设置并行度
    env.setParallelism(1)
    //导入隐式转换
    import org.apache.flink.streaming.api.scala._
    val props = new Properties()
    props.setProperty("bootstrap.servers","mynode1:9092,mynode2:9092,mynode3:9092")
    props.setProperty("group.id","test5")
    props.setProperty("key.serializer",classOf[StringDeserializer].getName)
    props.setProperty("value.serializer",classOf[StringDeserializer].getName)

    //设置事件时间
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

    //主流
//    val mainDStream: DataStream[TrafficLog] = env.addSource(new FlinkKafkaConsumer[String]("traffic-topic", new SimpleStringSchema(), props).setStartFromEarliest())
    val mainDStream: DataStream[TrafficLog] = env.socketTextStream("mynode5",9999)
      .map(line => {
   
   
      val arr: Array[String] = line.split(",")
      TrafficLog(arr(0).toLong, arr(1), arr(2), arr(3), arr(4).toDouble, arr(5), arr(6))
    })

    //广播流,读取mysql中的数据,这里主要是读取卡扣限速的数据
    val bcDStream: BroadcastStream[MonitorLimitSpeedInfo] = env.addSource(new JdbcReadSource("MonitorLimitSpeedInfo"))
     .map(
      one => {
   
   
        one.asInstanceOf[MonitorLimitSpeedInfo]
      })
      .broadcast(GlobalConstant.MONITOR_LIMIT_SPEED_DESCRIPTOR)

    //将日志流与广播流进行整合,将道路卡扣限速信息与每条车辆运行日志数据结合
    val trafficAllInfoDStream: DataStream[newTrafficLog] = mainDStream.connect(bcDStream).process(new BroadcastProcessFunction[TrafficLog, MonitorLimitSpeedInfo, newTrafficLog] {
   
   
      //处理每个日志元素
      override def processElement(value: TrafficLog, ctx: BroadcastProcessFunction[TrafficLog, MonitorLimitSpeedInfo, newTrafficLog]#ReadOnlyContext, out: Collector[newTrafficLog]): Unit = {
   
   
        //获取状态
        val mapState: ReadOnlyBroadcastState[String, MonitorLimitSpeedInfo] = ctx.getBroadcastState(GlobalConstant.MONITOR_LIMIT_SPEED_DESCRIPTOR)
        //获取当前道路当前卡扣 对应的限速 ,如果没有就设置限速为80
        var limitSpeed = 80
        if (mapState.contains(value.roadId + "_" + value.monitorId)) {
   
   
          limitSpeed = mapState.get(value.roadId + "_" + value.monitorId).speedLimit
        }
        out.collect(new newTrafficLog(value.actionTime, value.monitorId, value.cameraId, value.car, value.speed, value.roadId, value.areaId, limitSpeed))

      }

      //处理广播元素
      override def processBroadcastElement(value: MonitorLimitSpeedInfo, ctx: BroadcastProcessFunction[TrafficLog, MonitorLimitSpeedInfo, newTrafficLog]#Context, out: Collector[newTrafficLog]): Unit = {
   
   
        //获取状态
        val mapState: BroadcastState[String, MonitorLimitSpeedInfo] = ctx.getBroadcastState(GlobalConstant.MONITOR_LIMIT_SPEED_DESCRIPTOR)
        //更新当前道路当前卡扣的限速数据
        mapState.put(value.roadId + "_" + value.monitorId, value)
        println("广播状态准备就绪")
      }
    }).assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[newTrafficLog](Time.seconds(0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值