flink数据分析(具体业务逻辑)

Handler 接口类

**
 * 定义处理接口
 */
public interface Handler {

    /**
     * 有抽象类的子类进行实现
     * @param posInfo
     * @param ruleParam
     * @param ctx
     * @param vehicleState
     * @param alarmState
     * @param out
     * @throws Exception
     */
    void handle(VehiclePosInfo posInfo, RuleParam ruleParam, KeyedBroadcastProcessFunction.ReadOnlyContext ctx, ValueState<VehicleState> vehicleState, MapState<String, AlarmEvent> alarmState, Collector<AlarmEvent> out, Map<Long, LimitSpeedData> limitSpeedDataMap) throws Exception;
}

基础处理器抽象类 StreamHandler.java

/**
 * 基础处理器抽象类
 */
@Slf4j
public abstract class StreamHandler implements Handler {
	  /**
     * 处理器名称
     */
    protected String handlerName;

    protected StreamHandler(String handlerName) {
        this.handlerName = handlerName;
    }

    public String getHandlerName() {
        return handlerName;
    }
    /**
     * 获取报警附加信息抽象方法,由子类去实现,非报警业务无需实现该方法
     *
     * @param extend
     * @param englishName
     * @param beginEvent  开始报警
     * @return
     */
    protected abstract String getAlarmAttachInfo(Map<String, Object> extend, RuleParam ruleParam, String englishName, boolean beginEvent);

 /**
     * 获取报警附加信息抽象方法,由子类去实现,非报警业务无需实现该方法
     *
     * @param extend
     * @param englishName
     * @param beginEvent  开始报警
     * @return
     */
    protected abstract String getPathName(Map<String, Object> extend, RuleParam ruleParam, String englishName, boolean beginEvent);

/**
     * 模板方法,做一些统一处理工作,过滤补传数据,设置行停状态等
     *
     * @param posInfo
     * @param ctx
     * @param lastVehicleState
     * @param alarmState
     * @param out
     */
    public void handleStream(VehiclePosInfo posInfo, RuleParam ruleParam, KeyedBroadcastProcessFunction.ReadOnlyContext ctx, ValueState<VehicleState> lastVehicleState, MapState<String, AlarmEvent> alarmState, Collector<AlarmEvent> out, Map<Long, LimitSpeedData> limitSpeedDataMap) throws Exception {

        handle(posInfo, ruleParam, ctx, lastVehicleState, alarmState, out,limitSpeedDataMap);

    }
     /**
     * 判断停车
     *
     * @return
     */
    protected boolean isStop(VehiclePosInfo posInfo) {

        return posInfo.getSpeed() == 0 || posInfo.getSpeed() < 5;
    }
     /**
     * 判断运行
     *
     * @return
     */
    protected boolean isRun(VehiclePosInfo posInfo) {
        return posInfo.getSpeed() > 5;
    }
    /**
     * @param englishAlarmName
     * @param posInfo
     * @param ruleParam
     * @param ctx
     * @param lastVehicleState
     * @param alarmState
     * @param out
     */
    protected void endAlarm(String englishAlarmName, VehiclePosInfo posInfo, RuleParam ruleParam, KeyedBroadcastProcessFunction.ReadOnlyContext ctx, ValueState<VehicleState> lastVehicleState, MapState<String, AlarmEvent> alarmState, Collector<AlarmEvent> out) throws Exception {
        this.alarmHandle(englishAlarmName, posInfo, ruleParam, ctx, lastVehicleState, alarmState, out, false, true);
    }
	
	/**
     * @param englishAlarmName
     * @param posInfo
     * @param ruleParam
     * @param ctx
     * @param lastVehicleState
     * @param alarmState
     * @param out
     */
    protected void beginAlarm(String englishAlarmName, VehiclePosInfo posInfo, RuleParam ruleParam, KeyedBroadcastProcessFunction.ReadOnlyContext ctx, ValueState<VehicleState> lastVehicleState, MapState<String, AlarmEvent> alarmState, Collector<AlarmEvent> out) throws Exception {
        this.alarmHandle(englishAlarmName, posInfo, ruleParam, ctx, lastVehicleState, alarmState, out, true, false);
    }
	
	/**
     * 通用报警处理方法
     *
     * @param englishAlarmName
     * @param posInfo
     * @param ruleParam
     * @param ctx
     * @param lastVehicleState
     * @param alarmState
     * @param out
     * @param existAlarm
     * @param lastExistAlarm
     * @throws Exception
     */
    protected void alarmHandle(String englishAlarmName, VehiclePosInfo posInfo, RuleParam ruleParam, KeyedBroadcastProcessFunction.ReadOnlyContext ctx, ValueState<VehicleState> lastVehicleState, MapState<String, AlarmEvent> alarmState, Collector<AlarmEvent> out, Boolean existAlarm, Boolean lastExistAlarm) throws Exception {
		//情况1 当前报警
        if (existAlarm) {
        	//1.1当前报警,上次不报警 ,产生开始报警事件(如果离线,也表示上次不报警)
            if (!lastExistAlarm) {
                // 获取是否高速上的标志
                //1.1.1产生开始报警事件
                AlarmEvent beginAlarmEvent = beginAlarmEvent(posInfo, lastVehicleState.value(), ruleParam, englishAlarmName, ctx);
                //1.1.2中间状态记录该报警事件
                alarmState.put(englishAlarmName, beginAlarmEvent);
                //1.1.3发送报警

                log.info("开始报警:{}", JSON.toJSONString(beginAlarmEvent));

                out.collect(beginAlarmEvent);
                //线上模式
                if (!Main.localMode) {
                    RedisDataUtil.updateAlarm(beginAlarmEvent,ctx);
                }

            }
          //1.2当前报警,上次报警  ,产生持续报警事件
            if (lastExistAlarm) {  
            	//1.2.1获取开始报警事件
                AlarmEvent beginAlarmEvent = alarmState.get(englishAlarmName);
                //持续报警次数加 1
                beginAlarmEvent.setAlarmNum(beginAlarmEvent.getAlarmNum() + 1);
                beginAlarmEvent.setSpeed(posInfo.getSpeed());
                //更新中间数据状态
                alarmState.put(englishAlarmName, beginAlarmEvent);
            }
        }
        // 情况2 当前不报警
        if (!existAlarm) { 
        	//2.1当前不报警,上次报警,产生结束报警事件,清除报警
            if (lastExistAlarm) {
            	//2.1.1获取开始报警事件
                AlarmEvent beginAlarmEvent = alarmState.get(englishAlarmName);
//                //2.1.2 产生结束报警事件
                AlarmEvent endAlarmEvent = endAlarmEvent(posInfo, lastVehicleState.value().getLastPosInfo(), englishAlarmName, ruleParam, beginAlarmEvent);
                //2.1.3 发送结束报警事件
                if (endAlarmEvent !=null){
                    out.collect(endAlarmEvent);
                    //2.1.4 中间状态清除该报警事件
                    log.info("删除报警车牌:{}",posInfo.getPlate());
                    alarmState.remove(englishAlarmName);
                    //线上模式
                   if (!Main.localMode) {
                       RedisDataUtil.updateAlarm(endAlarmEvent,ctx);
                    log.info("结束报警:{}", JSON.toJSONString(endAlarmEvent));
                   }

                }
            }
            //2.2当前不报警,上次不报警 (不做任何处理)
            if (!lastExistAlarm) {

            }
        }
        
	}
 /**
     * 构建开始报警事件
     *
     * @param posInfo
     * @param englishAlarmName
     * @return
     */
     protected AlarmEvent beginAlarmEvent(VehiclePosInfo posInfo, VehicleState state, RuleParam ruleParam, String englishAlarmName, KeyedBroadcastProcessFunction.ReadOnlyContext ctx) {
     	AlarmDefine alarmDefine = AlarmTypeCache.getAlarmDefine(englishAlarmName);
        if(alarmDefine==null){
            log.info("alarmDefine信息为空:{}",englishAlarmName);
            return null;
        }
		AlarmEvent event = new AlarmEvent();
        //设置基础属性
        setBaseProp(posInfo, event,alarmDefine);
        //结束status为1
        event.setStatus((byte) 1);
        event.setAlarmId(IdGenUtil.nextId());
        event.setAlarmNum(1);
        event.setAlarmClass(alarmDefine.getAlarmClass());
        event.setAlarmType(alarmDefine.getAlarmType());
        event.setChineseName(alarmDefine.getChineseName());
        event.setEnglishName(alarmDefine.getEnglishName());
        return event;
  
     }
**
     * 设置基础属性
     *
     * @param posInfo
     * @param event
     */
    protected void setBaseProp(VehiclePosInfo posInfo, AlarmEvent event,AlarmDefine alarmDefine) {
    		event.setVehicleId(posInfo.getVehicleId());
        event.setGroupId(posInfo.getGroupId());
        event.setPlate(posInfo.getPlate());
        event.setPlateColorByte(posInfo.getPlateColor());
        event.setEventTime(posInfo.getDevTime() != null ? posInfo.getDevTime().getTime() : 0);
        event.setCompanyGroupId(GroupCache.getCompanyId(Long.valueOf(event.getGroupId())));
        event.setLat(posInfo.getLat());
        event.setDirect(posInfo.getDirect() != null ? new Double(posInfo.getDirect()).intValue() : 0);
        event.setLon(posInfo.getLon());
        event.setType((byte) 2);
        event.setSpeed(posInfo.getSpeed());
        event.setVehicleShape(posInfo.getVehicleShape());
    }
/**
     * 构建结束报警事件
     *
     * @param posInfo
     * @param englishAlarmName
     * @param beginAlarmEvent
     * @return
     */
    protected AlarmEvent endAlarmEvent(VehiclePosInfo posInfo, VehiclePosInfo last, String englishAlarmName, RuleParam ruleParam, AlarmEvent beginAlarmEvent) {
    	.....具体逻辑	
    }
/**
     * 判断设备时间是否在时间范围内  精确到分钟  例:22:00_05:00、22:00:00_05:00:00 21:00_23:00
     *
     * @param rule
     * @param date
     * @return
     */
      protected static boolean isInTimeFrame(String rule, Date date){
	  	LocalDateTime currTime = LocalDateTimeUtil.of(date.getTime(), ZoneId.systemDefault());
        String currTimeStr = LocalDateTimeUtil.format(currTime, "HH:mm:ss");
        String[] times = null;
        if (rule.contains("_")){
            times = rule.split("_");
        }else if (rule.contains("-")){
            times = rule.split("-");
        }
        String startTime = null;
        String endTime = null;
        if (times[0].split(":").length==2){
            startTime = times[0]+":00";
            endTime = times[1]+":00";
        } else {
            startTime = times[0];
            endTime = times[1];
        }
        if(startTime.compareTo(endTime)>0){
            if(currTimeStr.compareTo(startTime)>=0||currTimeStr.compareTo(endTime)<=0){
                return true;
            }
        }else if(startTime.compareTo(endTime)<0){
            if(currTimeStr.compareTo(startTime)>=0&&currTimeStr.compareTo(endTime)<=0){
                return true;
            }
        }
        return false;
	  }
	/**
     * 判断两次定位数据是否夸天
     *
     * @return
     */
    protected boolean isCrossDay(Date currentDevTime, Date lastDevTime) {
        if (currentDevTime != null && lastDevTime != null) {
            return currentDevTime.getDay() != lastDevTime.getDay();
        }

        return false;
    }
 /**
     * @Title: timeDifference
     * @Description: 两个时间相差多少天多少小时多少分
     * @param @param t1
     * @param @param t2
     * @param @return 参数
     * @return String 返回类型
     * @throws
     */
	public static String timeDifference(long diff) {
		StringBuffer buf = new StringBuffer();
        // 时间差
//        long diff = Math.abs(t1 - t2);
        // 一天的毫秒数
        long nd = 1000 * 24 * 60 * 60;
        // 一小时的毫秒数
        long nh = 1000 * 60 * 60;
        // 一分钟的毫秒数
        long nm = 1000 * 60;
        // 一秒钟的毫秒数
        long ns = 1000;
        // 多少天
        long day = diff / nd;
        // 多少小时
        long hour = diff % nd / nh;
        // 多少分
        long min = diff % nd % nh / nm;
        // 多少秒
        long sec = diff % nd % nh % nm / ns;
        // x天 或者 ""
        buf.append(day > 0 ? day + "天" : "");
   
        // x时 或者 x时x分
        buf.append(hour > 0 ? hour + "小时" : (min > 0 ? (day > 0 ? hour + "小时" : "") + min + "分钟" : ""));
        // x分 或者 ""
        buf.append((hour > 0 && min > 0) ? min + "分钟" : "");
        // x秒 或者 ""
        buf.append((sec > 0) ? sec + "秒" : "");
        // 结果
        return buf.toString();
	}
}

具体业务的例子:超速报警分析
OverSpeedPlatform.java

**
 * @author ljy
 * 平台超速业务处理类
 */

@Slf4j
public class OverSpeedPlatform extends StreamHandler {
	public final static String OVER_SPEED = "overSpeedPlatform";
    public static String vehicleShape = null;
    public OverSpeedPlatform() {
        super("平台超速报警处理类");
    }
    @Override
    public void handle(VehiclePosInfo posInfo, RuleParam ruleParam, KeyedBroadcastProcessFunction.ReadOnlyContext ctx, ValueState<VehicleState> vehicleState, MapState<String, AlarmEvent> alarmState, Collector<AlarmEvent> out, Map<Long, LimitSpeedData> limitSpeedDataMap) throws Exception {
    	VehicleState state = vehicleState.value();
        VehiclePosInfo last = state.getLastPosInfo();
        boolean lastExistOverSpeedAlarm = alarmState.contains(OVER_SPEED);
        //离线需要结束掉报警
        if (isOffline(posInfo, last) && lastExistOverSpeedAlarm) {
            this.endAlarm(OVER_SPEED, posInfo, ruleParam, ctx, vehicleState, alarmState, out);
            lastExistOverSpeedAlarm = false;

        }
         vehicleShape = posInfo.getVehicleShape();
        if (vehicleShape == null) {
            return;
        }
        // 获取平台超速报警规则
        GeneralRule rulePlatform = ruleParam.getGeneralRuleMap().get(GeneralRuleType.OVER_SPEED_PLATFORM);
         if (posInfo.getPlate().equals(plate)){
            log.info("规则{}", JSON.toJSONString(rulePlatform));
        }
        // 规则参数
        String params;
        // 规则数组
        String [] param;
        // 车辆类型
        String vehicleShapeRule = null;
        // 限速值
        String speedlimit = null;
        // 持续时长
        String duration = null;
        // 超速比
        String overSpeedRatio = null;
        
        if (rulePlatform !=null){
        	 params = rulePlatform.getParam();
            if (params!=null){
                param = params.split(",");
                if (param.length == 4){
                    vehicleShapeRule = param[0];
                    speedlimit = param[1];
                    duration = param[2];
                    overSpeedRatio = param[3];
                }

            }
        }
        // 当规则车型为空时,判断上次是否存在报警,存在结束掉报警
            if (StringUtils.isBlank(vehicleShapeRule)) {
                if(lastExistOverSpeedAlarm){
                    this.endAlarm(OVER_SPEED, posInfo, ruleParam, ctx, vehicleState, alarmState, out);
                }
                return;
            }
            if (StringUtils.isNotBlank(vehicleShapeRule) && !vehicleShape.equals(vehicleShapeRule)){
                if (posInfo.getPlate().equals(plate)) {
                    log.info("当前车辆类型跟规则类型不一致");
                }
                if(lastExistOverSpeedAlarm){
                    this.endAlarm(OVER_SPEED, posInfo, ruleParam, ctx, vehicleState, alarmState, out);
                }
                return;
            }else {
            if(lastExistOverSpeedAlarm){
                this.endAlarm(OVER_SPEED, posInfo, ruleParam, ctx, vehicleState, alarmState, out);
            }
            return;
        }
        boolean existOverSpeedAlarm = existOverSpeedAlarm(posInfo, state, speedlimit, duration, overSpeedRatio);
        if(existOverSpeedAlarm){
            // 根据超速比推送报警等级
//            Integer alarmPushLevel = alarmPushAccordingToSpeedProportion(lastExistOverSpeedAlarm,existOverSpeedAlarm,ruleParam,OVER_SPEED,posInfo,out,alarmState,vehicleState,speedlimit);
            posInfo.getExtend().put(posInfo.getVehicleShape()+"超速比",speedlimit);
//            posInfo.getExtend().put("alarmPushLevel",alarmPushLevel);
            this.alarmHandle(OVER_SPEED, posInfo, ruleParam, ctx, vehicleState, alarmState, out, true, lastExistOverSpeedAlarm);
            // 这里做风险逻辑处理
//            DealRiskPush.dealRiskLevelData(vehicleState, alarmState, out, OVER_SPEED, lastExistOverSpeedAlarm, true, posInfo,Double.parseDouble(speedlimit),false);
        }  else if (lastExistOverSpeedAlarm) {
            // 这里做风险逻辑处理
//            DealRiskPush.dealRiskLevelData(vehicleState, alarmState, out, OVER_SPEED, true, false, posInfo,Double.parseDouble(speedlimit),false);
            this.alarmHandle(OVER_SPEED, posInfo, ruleParam, ctx, vehicleState, alarmState, out, false, true);
            //不存在报警,清空报警开始时间
            state.setStartOverSpeedTime(null);
        }  
    }
    @Override
    protected String getPathName(Map<String, Object> extend, RuleParam ruleParam, String englishName, boolean beginEvent) {
        return null;
    }
	private boolean existOverSpeedAlarm(VehiclePosInfo posInfo, VehicleState state, String speedLimit, String duration,String overSpeedRate) {	
		boolean existAlarm = false;
		if (StringUtils.isNotBlank(speedLimit)) {
			boolean sign = posInfo.getSpeed().intValue() > (Double.parseDouble(speedLimit) + (Double.parseDouble(speedLimit) * (overSpeedRate==null?0:Double.parseDouble(overSpeedRate) / 100)));
            if (sign) {
                //判断是否是第一次
                if (state.getStartOverSpeedTime() == null) {
                    state.setStartOverSpeedTime(posInfo.getDevTime());
                } else {
                    //判断是否大于规则设置的持续时间
                    if (posInfo.getDevTime().getTime() - state.getStartOverSpeedTime().getTime() > (duration == null?0:Integer.parseInt(duration))*1000) {
                        existAlarm = true;
                    }
                }
            }
		}
		 return existAlarm;
	}
@Override
    protected String getAlarmAttachInfo(Map<String, Object> extend, RuleParam ruleParam, String englishName, boolean beginEvent) {

        if(OVER_SPEED.equals(englishName)){
            if (StringUtils.isNotBlank(vehicleShape)) {
                if(extend.get(vehicleShape+"超速比")!=null){
                    return (String) extend.get(vehicleShape+"超速比");
                }
            }
        }
        return null;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在这个科技高速发展的时代,经历了PC时代几乎人手一台电脑,随之衍生出站长这个概念;移动互联网时代几乎人手一部智能手机,智能手机一般都会安装很多应用,目前应用呈爆发式的增长;随着产业的不断深入发展,小程序的发展也日益壮大,应用涵盖各个领域;如今一个公司就可能有多个软件应用,对于软件开发商来说,急需一套分析系统帮助软件运营,如果单独开发一个分析系统去针对一个软件进行分析的话,成本会非常的大,这个成本包含开发成本以及以后的维护成本。为了解决了上述的问题,我们开发出了一套云产品:亿级动态数据统计分析系统,本系统可以支持所有的终端  (Web端、移动端、小程序端等 )数据统计,只要简单的使用sdk就可以接入我们的系统,软件开发商可以很轻松的对软件使用的情况进行监控,及时辅助公司对该软件的运营。该产品历经2年的实践,商业价值极高。本套案例是完全基于真实的产品进行开发和讲解的,同时对架构进行全面的升级,采用了全新的 Flink 架构+Node.js+Vue.js等,完全符合目前企业级的使用标准。对于本套课程在企业级应用的问题,可以提供全面的指导。Flink作为第四代大数据计算引擎,越来越多的企业在往Flink转换。Flink在功能性、容错性、性能方面都远远超过其他计算框架,兼顾高吞吐和低延时。Flink能够基于同一个Flink运行时,提供支持流处理和批处理两种类型应用的功能。也就是说同时支持流处理和批处理。Flink将流处理和批处理统一起来,也就是说作为流处理看待时输入数据流是无界的;批处理被作为一种特殊的流处理,只是它的输入数据流被定义为有界的。Flink技术特点1. 流处理特性支持高吞吐、低延迟、高性能的流处理支持带有事件时间的窗口(Window)操作支持有状态计算的Exactly-once语义支持高度灵活的窗口(Window)操作,支持基于time、count、session,以及data-driven的窗口操作支持具有Backpressure功能的持续流模型支持基于轻量级分布式快照(Snapshot)实现的容错一个运行时同时支持Batch on Streaming处理和Streaming处理Flink在JVM内部实现了自己的内存管理支持迭代计算支持程序自动优化:避免特定情况下Shuffle、排序等昂贵操作,间结果有必要进行缓存2. API支持对Streaming数据类应用,提供DataStream API对批处理类应用,提供DataSet API(支持Java/Scala)3. Libraries支持支持机器学习(FlinkML)支持图分析(Gelly)支持关系数据处理(Table)支持复杂事件处理(CEP)4. 整合支持支持Flink on YARN支持HDFS支持来自Kafka的输入数据支持Apache HBase支持Hadoop程序支持Tachyon支持ElasticSearch支持RabbitMQ支持Apache Storm支持S3支持XtreemFS课程所涵盖的知识点包括:Flink、 Node.js、 Vue.js、 Kafka、Flume、Spring、SpringMVC、Dubbo、HDFS、Hbase、Highcharts等等  企业一线架构师讲授,代码在老师指导下可以复用,提供企业解决方案。  版权归作者所有,盗版将进行法律维权。   

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值