Переглянути джерело

完成站点水量预警的大部分逻辑

andyliu 3 тижнів тому
батько
коміт
60d041bb1e

+ 318 - 77
src/main/java/com/shkpr/service/warncore/bizhandler/SiteDataHandler.java

@@ -1,11 +1,13 @@
 package com.shkpr.service.warncore.bizhandler;
 
+import com.global.base.tools.CastUtil;
 import com.global.base.tools.FastJsonUtil;
 import com.shkpr.service.warncore.commtools.CommTool;
 import com.shkpr.service.warncore.commtools.TimeTool;
 import com.shkpr.service.warncore.components.locks.CountDownLatchEx;
 import com.shkpr.service.warncore.components.locks.OrdWarnPlanLockMgr;
 import com.shkpr.service.warncore.constants.CommFieldStatus;
+import com.shkpr.service.warncore.constants.FrequencyUnit;
 import com.shkpr.service.warncore.dbdao.DBMgrProxy;
 import com.shkpr.service.warncore.dbdao.services.intef.OrdWarnPlanInfoDBService;
 import com.shkpr.service.warncore.dbdao.services.intef.OrdWarnPlanRulesDBService;
@@ -93,20 +95,30 @@ public class SiteDataHandler {
 
     private ResponseCode handlerDataFun(OrdWarnPlanDetail planDetail, List<OrdWarnPlanRules> rules){
         ResponseCode code = ResponseCode.RESULT_NORMAL;
-        String step = "Start To Pre Analysis";
+        String step = "Start to pre analysis.";
         if (getWarnPlanInfoDBService().existsLineEx(OrdWarnPlanInfoTable.R_INFO.TABLE
                 , new HashMap<String, Object>(){{put(OrdWarnPlanInfoTable.R_INFO.STATUS, CommFieldStatus.ENABLE);
                     put(OrdWarnPlanInfoTable.R_INFO.UNIQUE_ID, planDetail.getUid());
                     put(OrdWarnPlanInfoTable.R_INFO.VERSION, planDetail.getVersion());
                 }}, null, "") <= 0){
-            step = "Plan Is Changed,Do Analysis Next Time";
+            step = "Plan is changed,do analysis next time";
             code = ResponseCode.RESULT_BAD;
         }
 
+        boolean doForTodayBefore = false;//是否只分析今日之前的数据
         final long curUTCTm = TimeTool.getCurMsUTC();
-        final int curClock = (int)((curUTCTm/1000/60/60%24+8)%24);
-        final String curDate = TimeTool.convertUTC2DateStr(curUTCTm, TimeTool.YEAR_MONTH_DAY_FORMAT);
+        int curClock = (int)((curUTCTm/1000/60/60%24+8)%24);
         long queryBeginUTC = 0L, queryEndUTC = 0L, conditionMinUTC = 0L;
+        final String curDate = TimeTool.convertUTC2DateStr(curUTCTm, TimeTool.YEAR_MONTH_DAY_FORMAT);
+        if (FrequencyUnit.MIN.equals(planDetail.getFrequencyUnit())){//以分钟为单位进行分析
+        }else{//以小时或其他单位进行分析
+            curClock = curClock - 1;
+            if (curClock < 0){
+                curClock = 23;
+                doForTodayBefore = true;
+            }
+        }
+
         OrdWarnPlanTempStep thisStepTempRes = new OrdWarnPlanTempStep(planDetail);
         do {
             if (code != ResponseCode.RESULT_NORMAL)
@@ -118,30 +130,53 @@ public class SiteDataHandler {
                     conditionMinUTC = TimeTool.convertDateStr2UTC(String.format("%s %2d:00:00", curDate, rules.get(i).getStart()));
                 if (curClock >= rules.get(i).getStart() && curClock <= rules.get(i).getEnd()){
                     findStartClock = rules.get(i).getStart();
-                    queryEndUTC = Math.min(curUTCTm, TimeTool.convertDateStr2UTC(String.format("%s %2d:59:59", curDate, rules.get(i).getEnd())));
+                    if (FrequencyUnit.MIN.equals(planDetail.getFrequencyUnit())){//以分钟为单位进行分析
+                        queryEndUTC = Math.min(curUTCTm
+                                , TimeTool.convertDateStr2UTC(String.format("%s %2d:59:59", curDate, rules.get(i).getEnd())));
+                    }else {//以小时或其他单位进行分析
+                        queryEndUTC = Math.min(TimeTool.convertDateStr2UTC(String.format("%s %2d:59:59", curDate, curClock))
+                                , TimeTool.convertDateStr2UTC(String.format("%s %2d:59:59", curDate, rules.get(i).getEnd())));
+                    }
                 }
             }
             if (findStartClock < 0){
-                step = "Not In Time Range,Do Analysis Next Time";
+                step = "Not in time range,do analysis next time";
                 code = ResponseCode.RESULT_BAD;
                 break;
             }
 
-            findStartClock = findStartClock-1;
-            for (int i=rules.size()-1;i>=0;i--){
-                if (findStartClock < 0)
-                    break;
-                if (findStartClock == rules.get(i).getEnd())
-                    findStartClock = rules.get(i).getStart()-1;
+            if (doForTodayBefore){//只分析昨日23:00:00-23:59:59的数据
+                conditionMinUTC = conditionMinUTC - TimeTool.MS_ONE_DAY;//针对昨日:触发规则列表中第一个时段的起始时刻
+                queryBeginUTC = TimeTool.getTodayBeginUTC()-TimeTool.MS_ONE_HOUR;
+                queryEndUTC = TimeTool.getTodayBeginUTC()-TimeTool.MS_ONE_SEC;
+            }else {
+                findStartClock = findStartClock-1;
+                for (int i=rules.size()-1;i>=0;i--){
+                    if (findStartClock < 0)
+                        break;
+                    if (findStartClock == rules.get(i).getEnd())
+                        findStartClock = rules.get(i).getStart()-1;
+                }
+                queryBeginUTC = TimeTool.convertDateStr2UTC(String.format("%s %2d:00:00", curDate, findStartClock+1));
             }
-            queryBeginUTC = TimeTool.convertDateStr2UTC(String.format("%s %2d:00:00", curDate, findStartClock+1));
 
             if (thisStepTempRes.getLastCompareSampleTime() <= 0L //从未分析过则重新计数
                  || thisStepTempRes.getLastCompareSampleTime() < queryBeginUTC){//样本跨了时段则重新计数
                 thisStepTempRes.resetData();
             }else if (thisStepTempRes.getLastCompareSampleTime() >= queryBeginUTC){
-                queryBeginUTC = thisStepTempRes.getLastCompareSampleTime() + 1000L;
+                if (FrequencyUnit.MIN.equals(planDetail.getFrequencyUnit())) {//以分钟为单位进行分析
+                    queryBeginUTC = thisStepTempRes.getLastCompareSampleTime() + TimeTool.MS_ONE_SEC;
+                }else {//以小时或其他单位进行分析
+                    queryBeginUTC = thisStepTempRes.getLastCompareSampleTime() + TimeTool.MS_ONE_HOUR;
+                }
+            }
+
+            if (queryBeginUTC > queryEndUTC){
+                step = "Time is invalid,do analysis next time";
+                code = ResponseCode.RESULT_BAD;
+                break;
             }
+            thisStepTempRes.setDoForTodayBefore(doForTodayBefore);
             thisStepTempRes.setQueryBeginUTC(queryBeginUTC);
             thisStepTempRes.setQueryEndUTC(queryEndUTC);
             thisStepTempRes.setConditionMinUTC(conditionMinUTC);
@@ -150,7 +185,7 @@ public class SiteDataHandler {
                 thisStepTempRes.setDayTriggerTimes(0);
             if (planDetail.getDayTriggerUpperTimes() > 0
                     && thisStepTempRes.getDayTriggerTimes() >= planDetail.getDayTriggerUpperTimes()){//触发事件达到最大个数
-                step = "Event Arrive Max Limit,Stop Analysis For Today";
+                step = "Event arrive at max limit,stop analysis for today";
                 code = ResponseCode.RESULT_BAD;
                 break;
             }
@@ -163,7 +198,7 @@ public class SiteDataHandler {
             if (planDetail.getItemKey().endsWith("miss")){//数据缺失
 
             }else if (planDetail.getItemKey().endsWith("swo")){//小时水量
-
+                return analysisDataForWO(planDetail, rules, thisStepTempRes);
             }else {
                 if ("set".equals(planDetail.getDoPickWay())){//时段曲线
                     return analysisDataBySet(planDetail, rules, thisStepTempRes);
@@ -173,10 +208,50 @@ public class SiteDataHandler {
         return code;
     }
 
+    /**
+     * 原始值匹配规则条件
+     * @param originValue
+     * @param condition
+     * @return -1: 未知错误;0 -- 未匹配;1 -- 已匹配
+     */
+    private int matchedToRuleItem(String originValue, OrdWarnRuleCondition condition){
+        if (StringUtils.isEmpty(originValue))
+            return 0;
+        int matched = -1;
+        try {
+            int nRes = CommTool.compareFloat(originValue, condition.getThreshold());
+            if (nRes == 0){
+                if ("!=".equals(condition.getMethod())){
+                    matched = 0;
+                }else if (condition.getMethod().contains("=")){
+                    matched = 1;
+                }else
+                    matched = 0;
+            }else if (nRes > 0){
+                if ("!=".equals(condition.getMethod())){
+                    matched = 1;
+                }else if (condition.getMethod().contains(">")){
+                    matched = 1;
+                }else
+                    matched = 0;
+            }else {
+                if ("!=".equals(condition.getMethod())){
+                    matched = 1;
+                }else if (condition.getMethod().contains("<")){
+                    matched = 1;
+                }else
+                    matched = 0;
+            }
+        }catch (Exception e){
+            matched = -1;
+        }
+        return matched;
+    }
+
     //处理时段样本数据
     private ResponseCode analysisDataBySet(OrdWarnPlanDetail planDetail, List<OrdWarnPlanRules> rules, OrdWarnPlanTempStep thisTempStep){
         ResponseCode code = ResponseCode.RESULT_NORMAL;
-        String step = "Start To Deep Analysis";
+        String step = "Start to deep analysis";
         long curTime = TimeTool.getCurMsUTC();
         final String siteId = rules.get(0).getObjId();
         SiteSampleDataResult siteSampleData = null;
@@ -195,32 +270,40 @@ public class SiteDataHandler {
             }catch (Exception e){}
 
             if (siteSampleData == null){
-                step = String.format("Get Site Sample Data Failed");
+                step = String.format("Get site sample data failed");
                 code = ResponseCode.RESULT_BAD;
                 break;
             }
             if (CommTool.listSize(siteSampleData.getData()) <= 0
                     || CommTool.listSize(siteSampleData.getData().get(0).getRecords()) <= 0){
-                step = String.format("Get Site Sample Data Empty");
+                step = String.format("Get site sample data empty");
                 code = ResponseCode.RESULT_BAD;
                 break;
             }
+            //要求getRecords()中的数据为按time升序排列
+            Collections.sort(siteSampleData.getData().get(0).getRecords(), new Comparator<SiteSampleGroupItem>() {
+                @Override
+                public int compare(SiteSampleGroupItem o1, SiteSampleGroupItem o2) {
+                    return Long.compare(o1.getTime(),o2.getTime());//按时间升序排列
+                }
+            });
 
             for (SiteSampleGroupItem sampleItem:siteSampleData.getData().get(0).getRecords()){
-                if (sampleItem.getTime() <= 0L || CommTool.listSize(sampleItem.getFields()) <= 0)
+                long sampleRecordTm = sampleItem.getTime();
+                if (sampleRecordTm <= 0L || CommTool.listSize(sampleItem.getFields()) <= 0)
                     continue;
                 if (planDetail.getDayTriggerUpperTimes() > 0
                         && thisTempStep.getDayTriggerTimes() >= planDetail.getDayTriggerUpperTimes()){
-                    step = String.format("Event Arrive Max Limit");
+                    step = String.format("Event arrive at max limit");
                     code = ResponseCode.RESULT_BAD;
                     break;
                 }
 
                 boolean matched = false;
                 OrdWarnPlanRules findRule = null;
-                int dataClock = (int)((sampleItem.getTime()/1000/60/60%24+8)%24);
+                int sampleRecordClock = (int)((sampleRecordTm/1000/60/60%24+8)%24);
                 for (OrdWarnPlanRules ruleItem:rules){
-                    if (dataClock <= ruleItem.getEnd() && dataClock >= ruleItem.getStart()){
+                    if (sampleRecordClock <= ruleItem.getEnd() && sampleRecordClock >= ruleItem.getStart()){
                         findRule = ruleItem;
                         break;
                     }
@@ -229,50 +312,27 @@ public class SiteDataHandler {
                     continue;
                 for (OrdWarnRuleCondition condition:findRule.getConditions()){
                     String originValue = "";
+                    String backTag = condition.getFormat().substring(condition.getFormat().lastIndexOf("@")+1);
                     for (KeyValue kv:sampleItem.getFields()){
-                        if (condition.getTag().equals(kv.getKey())){
+                        if (backTag.equals(kv.getKey())){
                             originValue = kv.getValue();
                             break;
                         }
                     }
-                    if (StringUtils.isEmpty(originValue))
-                        matched = matched || false;
-                    else {
-                        try {
-                            int nRes = CommTool.compareFloat(originValue, condition.getThreshold());
-                            if (nRes == 0){
-                                if ("!=".equals(condition.getMethod())){
-                                    matched = (matched || false);
-                                }else if (condition.getMethod().contains("=")){
-                                    matched = (matched || true);
-                                }else
-                                    matched = (matched || false);
-                            }else if (nRes > 0){
-                                if ("!=".equals(condition.getMethod())){
-                                    matched = (matched || true);
-                                }else if (condition.getMethod().contains(">")){
-                                    matched = (matched || true);
-                                }else
-                                    matched = (matched || false);
-                            }else {
-                                if ("!=".equals(condition.getMethod())){
-                                    matched = (matched || true);
-                                }else if (condition.getMethod().contains("<")){
-                                    matched = (matched || true);
-                                }else
-                                    matched = (matched || false);
-                            }
-                        }catch (Exception e){
-                            step = String.format("Compare Value Exception Error");
-                            code = ResponseCode.RESULT_BAD;
-                        }
+                    int pkRes = matchedToRuleItem(originValue, condition);
+                    if (pkRes == -1){
+                        step = String.format("Compare value exception error");
+                        code = ResponseCode.RESULT_BAD;
+                        break;
+                    }else {
+                        matched = matched || (pkRes==1?true:false);
                     }
                 }
-                if (code == ResponseCode.RESULT_BAD){
+                if (code != ResponseCode.RESULT_NORMAL)
                     break;
-                }
+
                 if (!matched){//本次没有匹配成功
-                    thisTempStep.setLastCompareSampleTime(sampleItem.getTime());
+                    thisTempStep.setLastCompareSampleTime(sampleRecordTm);
                     thisTempStep.setLastCompareSampleResult(0);
                     thisTempStep.setFirstMatchSampleTime(0L);
                     thisTempStep.setLastEventId("");
@@ -281,57 +341,59 @@ public class SiteDataHandler {
                 }//本次匹配成功进入下一步
 
                 if (thisTempStep.getLastCompareSampleResult() <= 0){//上一次没有匹配成功
-                    thisTempStep.setLastCompareSampleTime(sampleItem.getTime());
+                    thisTempStep.setLastCompareSampleTime(sampleRecordTm);
                     thisTempStep.setLastCompareSampleResult(1);
-                    thisTempStep.setFirstMatchSampleTime(sampleItem.getTime());
+                    thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
                     continue;
                 }//上一次匹配成功了进入下一步
 
-                long diffMatch = sampleItem.getTime()-thisTempStep.getLastCompareSampleTime();//两个最近匹配样本之间的采集时间差(单位:毫秒)
-                if (diffMatch > planDetail.getThresholdPeriod()*TimeTool.MS_ONE_MIN){//两个最近匹配样本间缺失的数据太多、或跨了天、或跨了时段,可认为重新计数
-                    thisTempStep.setLastCompareSampleTime(sampleItem.getTime());
+                long triggerEventPeriodSwitch = planDetail.getFrequency()*planDetail.getThreshold()*TimeTool.MS_ONE_MIN;//触发预警事件的最小时长(单位:毫秒)
+                long diffMatch = sampleRecordTm-thisTempStep.getLastCompareSampleTime();//两个最近匹配样本之间的采集时间差(单位:毫秒)
+                if (diffMatch > triggerEventPeriodSwitch){//两个最近匹配样本间缺失的数据太多、或跨了天、或跨了时段,可认为重新计数
+                    thisTempStep.setLastCompareSampleTime(sampleRecordTm);
                     thisTempStep.setLastCompareSampleResult(1);
-                    thisTempStep.setFirstMatchSampleTime(sampleItem.getTime());
+                    thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
                     thisTempStep.setLastEventId("");
                     thisTempStep.setLastEventTime(0L);
                     continue;
                 }//两个最近匹配样本间隔很近,可认为是持续匹配,则进入下一步
 
                 if (thisTempStep.getLastCompareSampleTime() < thisTempStep.getConditionMinUTC()){//上一个匹配样本是非当前天的,可认为重新计数
-                    thisTempStep.setLastCompareSampleTime(sampleItem.getTime());
+                    thisTempStep.setLastCompareSampleTime(sampleRecordTm);
                     thisTempStep.setLastCompareSampleResult(1);
-                    thisTempStep.setFirstMatchSampleTime(sampleItem.getTime());
+                    thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
                     thisTempStep.setLastEventId("");
                     thisTempStep.setLastEventTime(0L);
                     continue;
                 }//上一个匹配样本是当天的,则进入下一步
 
-                long matchLen = (thisTempStep.getFirstMatchSampleTime()<=0)?0:(sampleItem.getTime()-thisTempStep.getFirstMatchSampleTime());//样本匹配的持续时长(单位:毫秒)
+                long matchLen = (thisTempStep.getFirstMatchSampleTime()<=0)?0:(sampleRecordTm-thisTempStep.getFirstMatchSampleTime());//样本匹配的持续时长(单位:毫秒)
                 if (StringUtils.isEmpty(thisTempStep.getLastEventId())){//之前无预警事件
-                    if (matchLen < planDetail.getThresholdPeriod()*TimeTool.MS_ONE_MIN){//还得持续等待,达不到触发事件的累计时长
-                        thisTempStep.setLastCompareSampleTime(sampleItem.getTime());
+                    if (matchLen < triggerEventPeriodSwitch){//还得持续等待,达不到触发事件的累计时长
+                        thisTempStep.setLastCompareSampleTime(sampleRecordTm);
                         thisTempStep.setLastCompareSampleResult(1);
                         if (thisTempStep.getFirstMatchSampleTime() <= 0)
-                            thisTempStep.setFirstMatchSampleTime(sampleItem.getTime());
+                            thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
                     }else {//触发一个新的事件
-                        thisTempStep.setLastCompareSampleTime(sampleItem.getTime());
+                        thisTempStep.setLastCompareSampleTime(sampleRecordTm);
                         thisTempStep.setLastCompareSampleResult(1);
                         thisTempStep.setLastEventId("新事件ID");
                         thisTempStep.setLastEventTime(curTime);
                         thisTempStep.setLastEventAction(1);
                         thisTempStep.setDayTriggerTimes(thisTempStep.getDayTriggerTimes()+1);
+                        //[!!!]do not change the FirstMatchSampleTime[!!!]
                     }
                 }else {//之前有预警事件
                     if (thisTempStep.getLastEventAction() >= 2){//之前的预警事件已处理,则可认为进行重新计数
-                        thisTempStep.setLastCompareSampleTime(sampleItem.getTime());
+                        thisTempStep.setLastCompareSampleTime(sampleRecordTm);
                         thisTempStep.setLastCompareSampleResult(1);
-                        thisTempStep.setFirstMatchSampleTime(sampleItem.getTime());
+                        thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
                         thisTempStep.setLastEventId("");
                         thisTempStep.setLastEventTime(0L);
                     }else {//之前的预警事件未处理,则更新预警事件的样本截止时刻
-                        thisTempStep.setLastCompareSampleTime(sampleItem.getTime());
+                        thisTempStep.setLastCompareSampleTime(sampleRecordTm);
                         thisTempStep.setLastCompareSampleResult(1);
-                        eventId2NewEndUTC.put(thisTempStep.getLastEventId(), sampleItem.getTime());
+                        eventId2NewEndUTC.put(thisTempStep.getLastEventId(), sampleRecordTm);
                     }
                 }
             }
@@ -339,8 +401,187 @@ public class SiteDataHandler {
         return code;
     }
 
-    //处理时段差值数据
-    private void handleDataByDiff(){
+    //处理时段的用水量
+    private ResponseCode analysisDataForWO(OrdWarnPlanDetail planDetail, List<OrdWarnPlanRules> rules, OrdWarnPlanTempStep thisTempStep){
+        ResponseCode code = ResponseCode.RESULT_NORMAL;
+        String step = "Start to deep analysis";
+        long curTime = TimeTool.getCurMsUTC();
+        final String siteId = rules.get(0).getObjId();
+        SiteStatsDataResult siteStatsData = null;
+        Map<String, Long> eventId2NewEndUTC = new HashMap<>();//需要更新预警事件的样本截止时间
+        List<Long> tagTime = new ArrayList<>();//每个整点时刻,用于查询站点的统计数据
+        long tmpStepToStep = thisTempStep.getQueryBeginUTC();
+        do {
+            tagTime.add(tmpStepToStep);
+            tmpStepToStep += TimeTool.MS_ONE_HOUR;
+        }while (tmpStepToStep < thisTempStep.getQueryEndUTC());
 
+        do {
+            if (siteStatsData == null){
+                step = String.format("Get site stats data failed");
+                code = ResponseCode.RESULT_BAD;
+                break;
+            }
+            if (CommTool.listSize(siteStatsData.getData()) <= 0){
+                step = String.format("Get site stats data empty");
+                code = ResponseCode.RESULT_BAD;
+                break;
+            }
+            //要求getReport()中的数据为按tag升序排列,注:tag为每个整点时刻的UTC时间
+            Collections.sort(siteStatsData.getData(), new Comparator<SiteStatsDataItem>() {
+                @Override
+                public int compare(SiteStatsDataItem o1, SiteStatsDataItem o2) {
+                    return o1.getTag().compareTo(o2.getTag());
+                }
+            });
+            for (SiteStatsDataItem sampleItem:siteStatsData.getData()){
+                long sampleRecordTm = CastUtil.castLong(sampleItem.getTag(), 0L);
+                if (sampleRecordTm <= 0L
+                        || sampleItem.getCode() != 0
+                        || CommTool.listSize(sampleItem.getReport()) <= 0)
+                    continue;
+                if (planDetail.getDayTriggerUpperTimes() > 0
+                        && thisTempStep.getDayTriggerTimes() >= planDetail.getDayTriggerUpperTimes()){
+                    step = String.format("Event arrive at max limit");
+                    code = ResponseCode.RESULT_BAD;
+                    break;
+                }
+
+                boolean matched = false;
+                OrdWarnPlanRules findRule = null;
+                int sampleRecordClock = (int)((sampleRecordTm/1000/60/60%24+8)%24);
+                for (OrdWarnPlanRules ruleItem:rules){
+                    if (sampleRecordClock <= ruleItem.getEnd() && sampleRecordClock >= ruleItem.getStart()){
+                        findRule = ruleItem;
+                        break;
+                    }
+                }
+                if (findRule == null)
+                    continue;
+
+                for (OrdWarnRuleCondition condition:findRule.getConditions()){
+                    String originValue = "";
+                    String backTag = condition.getFormat().substring(condition.getFormat().lastIndexOf("@")+1);
+                    for (KeyValue kv:sampleItem.getReport()){
+                        if (backTag.equals(kv.getKey())){
+                            originValue = kv.getValue();
+                            break;
+                        }
+                    }
+                    int pkRes = matchedToRuleItem(originValue, condition);
+                    if (pkRes == -1){
+                        step = String.format("Compare value exception error");
+                        code = ResponseCode.RESULT_BAD;
+                        break;
+                    }else {
+                        matched = matched || (pkRes==1?true:false);
+                    }
+                }
+                if (code != ResponseCode.RESULT_NORMAL)
+                    break;
+
+                if (!matched){//本次没有匹配成功
+                    thisTempStep.setLastCompareSampleTime(sampleRecordTm);
+                    thisTempStep.setLastCompareSampleResult(0);
+                    thisTempStep.setFirstMatchSampleTime(0L);
+                    thisTempStep.setLastEventId("");
+                    thisTempStep.setLastEventTime(0L);
+                    continue;
+                }//本次匹配成功进入下一步
+
+                long triggerEventPeriodSwitch = planDetail.getFrequency()*planDetail.getThreshold();//触发预警事件的最小时长(单位:小时)
+                if (thisTempStep.getLastCompareSampleResult() <= 0){//上一次没有匹配成功
+                    thisTempStep.setLastCompareSampleTime(sampleRecordTm);
+                    thisTempStep.setLastCompareSampleResult(1);
+                    thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
+                    if (triggerEventPeriodSwitch <= 1){//触发事件
+                        thisTempStep.setLastEventId("新事件ID");
+                        thisTempStep.setLastEventTime(curTime);
+                        thisTempStep.setLastEventAction(1);
+                        thisTempStep.setDayTriggerTimes(thisTempStep.getDayTriggerTimes()+1);
+                    }
+                    continue;
+                }//上一次匹配成功了进入下一步
+
+                long diffMatch = (sampleRecordTm-thisTempStep.getLastCompareSampleTime())/TimeTool.MS_ONE_HOUR;//两个最近匹配样本之间的采集时间差(单位:小时)
+                if (diffMatch > triggerEventPeriodSwitch){//两个最近匹配样本间缺失的数据太多、或跨了天、或跨了时段,可认为重新计数
+                    thisTempStep.setLastCompareSampleTime(sampleRecordTm);
+                    thisTempStep.setLastCompareSampleResult(1);
+                    thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
+                    if (triggerEventPeriodSwitch <= 1){//触发事件
+                        thisTempStep.setLastEventId("新事件ID");
+                        thisTempStep.setLastEventTime(curTime);
+                        thisTempStep.setLastEventAction(1);
+                        thisTempStep.setDayTriggerTimes(thisTempStep.getDayTriggerTimes()+1);
+                    }else {
+                        thisTempStep.setLastEventId("");
+                        thisTempStep.setLastEventTime(0L);
+                    }
+                    continue;
+                }//两个最近匹配样本间隔很近,可认为是持续匹配,则进入下一步
+
+                if (thisTempStep.getLastCompareSampleTime() < thisTempStep.getConditionMinUTC()){//上一个匹配样本是非当前天的,可认为重新计数
+                    thisTempStep.setLastCompareSampleTime(sampleRecordTm);
+                    thisTempStep.setLastCompareSampleResult(1);
+                    thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
+                    if (triggerEventPeriodSwitch <= 1){//触发事件
+                        thisTempStep.setLastEventId("新事件ID");
+                        thisTempStep.setLastEventTime(curTime);
+                        thisTempStep.setLastEventAction(1);
+                        thisTempStep.setDayTriggerTimes(thisTempStep.getDayTriggerTimes()+1);
+                    }else {
+                        thisTempStep.setLastEventId("");
+                        thisTempStep.setLastEventTime(0L);
+                    }
+                    continue;
+                }//上一个匹配样本是当天的,则进入下一步
+
+                long matchLen = (thisTempStep.getFirstMatchSampleTime()<=0)?0:((sampleRecordTm-thisTempStep.getFirstMatchSampleTime())/TimeTool.MS_ONE_HOUR);//样本匹配的持续时长(单位:小时)
+                if (StringUtils.isEmpty(thisTempStep.getLastEventId())){//之前无预警事件
+                    if (matchLen < triggerEventPeriodSwitch){//还得持续等待,达不到触发事件的累计时长
+                        thisTempStep.setLastCompareSampleTime(sampleRecordTm);
+                        thisTempStep.setLastCompareSampleResult(1);
+                        if (thisTempStep.getFirstMatchSampleTime() <= 0){
+                            thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
+                            if (triggerEventPeriodSwitch <= 1){//补充触发事件
+                                thisTempStep.setLastEventId("新事件ID");
+                                thisTempStep.setLastEventTime(curTime);
+                                thisTempStep.setLastEventAction(1);
+                                thisTempStep.setDayTriggerTimes(thisTempStep.getDayTriggerTimes()+1);
+                            }
+                        }
+                    }else {//触发一个新的事件
+                        thisTempStep.setLastCompareSampleTime(sampleRecordTm);
+                        thisTempStep.setLastCompareSampleResult(1);
+                        thisTempStep.setLastEventId("新事件ID");
+                        thisTempStep.setLastEventTime(curTime);
+                        thisTempStep.setLastEventAction(1);
+                        thisTempStep.setDayTriggerTimes(thisTempStep.getDayTriggerTimes()+1);
+                        //[!!!]do not change the FirstMatchSampleTime[!!!]
+                    }
+                }else {//之前有预警事件
+                    if (thisTempStep.getLastEventAction() >= 2){//之前的预警事件已处理,则可认为进行重新计数
+                        thisTempStep.setLastCompareSampleTime(sampleRecordTm);
+                        thisTempStep.setLastCompareSampleResult(1);
+                        thisTempStep.setFirstMatchSampleTime(sampleRecordTm);
+                        if (triggerEventPeriodSwitch <= 1){//触发事件
+                            thisTempStep.setLastEventId("新事件ID");
+                            thisTempStep.setLastEventTime(curTime);
+                            thisTempStep.setLastEventAction(1);
+                            thisTempStep.setDayTriggerTimes(thisTempStep.getDayTriggerTimes()+1);
+                        }else {
+                            thisTempStep.setLastEventId("");
+                            thisTempStep.setLastEventTime(0L);
+                        }
+                    }else {//之前的预警事件未处理,则更新预警事件的样本截止时刻
+                        thisTempStep.setLastCompareSampleTime(sampleRecordTm);
+                        thisTempStep.setLastCompareSampleResult(1);
+                        eventId2NewEndUTC.put(thisTempStep.getLastEventId(), sampleRecordTm);
+                    }
+                }
+            }
+
+        }while (false);
+        return code;
     }
 }

+ 1 - 0
src/main/java/com/shkpr/service/warncore/commtools/TimeTool.java

@@ -8,6 +8,7 @@ import java.util.*;
 public class TimeTool {
     public static final long MS_HTTP_REQ_TIMEOUT = 120*1000;  //两分钟的毫秒数
     public static final long MS_ONE_HALF_MIN = 90*1000;  //一分半钟的毫秒数
+    public static final long MS_ONE_SEC = 1000;       //一秒钟的毫秒数
     public static final long MS_ONE_MIN = 60*1000;       //一分钟的毫秒数
     public static final long MIN_ONE_DAY = 24*60;        //一天中的分
     public static final long SEC_ONE_DAY = 24*60*60;     //一天中的秒

+ 5 - 2
src/main/java/com/shkpr/service/warncore/dto/OrdWarnPlanDetail.java

@@ -13,8 +13,11 @@ public class OrdWarnPlanDetail {
     private String ownerId = "";
     private String ownerMainType = "";
     private String ownerSubType = "";
+    private String owner = "";
     private int level = 0;
-    private int thresholdPeriod = 0;
+    private int threshold = 0;//连续x次触发就报警(单位:次数)
+    private int frequency = 0;//分析频率
+    private String frequencyUnit = "";//分析频率的单位(m/h/d/n/y)
     private int sendway = 3;
     private long lastCompareSampleTime = 0L;
     private int lastCompareSampleResult = 0;
@@ -27,7 +30,7 @@ public class OrdWarnPlanDetail {
     private String doPeriodUnit = "";
     private String doPickWay = "";
     private String doDb = "";
-    private String doTable = "";
+    private String doTime = "";
     private String ending = "";
     private int dayTriggerTimes = 0;
     private int dayTriggerUpperTimes = -1;

+ 1 - 0
src/main/java/com/shkpr/service/warncore/dto/OrdWarnPlanTempStep.java

@@ -20,6 +20,7 @@ public class OrdWarnPlanTempStep {
     private int lastEventAction = 1;//最近一次触发产生事件的处理阶段(1--待处理;2--已处理)
     private long conditionMinUTC = 0L;//触发规则列表中第一个时段的起始时刻
     private int dayTriggerTimes = 0;//今日触发事件的个数
+    private boolean doForTodayBefore = false;//是否只分析今日之前的数据
 
     public OrdWarnPlanTempStep() {
     }

+ 1 - 1
src/main/java/com/shkpr/service/warncore/dto/OrdWarnRuleCondition.java

@@ -12,7 +12,7 @@ public class OrdWarnRuleCondition {
     private String method = "";//对比字段方法
     private String threshold = "";//对比字段待对比阀值
     private String type = "";//对比字段的取值类型
-    private String tag = "";//对比字段的数据返回标签
+    private String format = "";//实际查询字段@实际返回字段
 
     public OrdWarnRuleCondition() {
     }

+ 19 - 0
src/main/java/com/shkpr/service/warncore/dto/SiteStatsDataItem.java

@@ -0,0 +1,19 @@
+package com.shkpr.service.warncore.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+
+@Getter
+@Setter
+public class SiteStatsDataItem {
+    private String uid = "";
+    private String field = "";
+    private String tag = "";
+    private int code = 1;
+    private ArrayList<KeyValue> report = null;
+
+    public SiteStatsDataItem() {
+    }
+}

+ 16 - 0
src/main/java/com/shkpr/service/warncore/dto/SiteStatsDataResult.java

@@ -0,0 +1,16 @@
+package com.shkpr.service.warncore.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+
+@Getter
+@Setter
+public class SiteStatsDataResult {
+    private int total = 0;
+    private ArrayList<SiteStatsDataItem> data = null;
+
+    public SiteStatsDataResult() {
+    }
+}

+ 61 - 0
src/main/java/com/shkpr/service/warncore/jsonbean/JPOrdWarnEventInfo.java

@@ -0,0 +1,61 @@
+package com.shkpr.service.warncore.jsonbean;
+
+import com.global.base.tools.FastJsonUtil;
+import com.shkpr.service.warncore.dto.OrdWarnPlanDetail;
+import com.shkpr.service.warncore.dto.OrdWarnPlanRules;
+import com.shkpr.service.warncore.dto.OrdWarnPlanTempStep;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class JPOrdWarnEventInfo {
+    private String uid = "";
+    private String title = "";
+    private String itemKey = "";
+    private String planId = "";
+    private String ownerSrc = "";
+    private String ownerId = "";
+    private String ownerMainType = "";
+    private String ownerSubType = "";
+    private String owner = "";
+    private int level = 1;
+    private int action = 1;
+    private int status = 1;
+    private String gis = "";
+    private String address = "";
+    private String content = "";
+    private long fromTime = 0L;
+    private long toTime = 0L;
+    private String rules = "";
+    private long limitTime = 0L;
+    private String ending = "";
+    private String creatorId = "";
+    private String followerId = "";
+    private long createTime = 0L;
+    private long updateTime = 0L;
+    private int sendway = 3;
+
+    public JPOrdWarnEventInfo() {
+    }
+
+    public JPOrdWarnEventInfo(OrdWarnPlanDetail planDetail, List<OrdWarnPlanRules> rules, OrdWarnPlanTempStep thisTempStep, long eventTime){
+        this.itemKey = planDetail.getItemKey();
+        this.planId = planDetail.getUid();
+        this.ownerSrc = planDetail.getOwnerSrc();
+        this.ownerId = planDetail.getOwnerId();
+        this.ownerMainType = planDetail.getOwnerMainType();
+        this.ownerSubType = planDetail.getOwnerSubType();
+        this.owner = planDetail.getOwner();
+        this.sendway = planDetail.getSendway();
+
+        this.fromTime = thisTempStep.getFirstMatchSampleTime();
+        this.toTime = thisTempStep.getLastCompareSampleTime();
+        this.rules = FastJsonUtil.toJSON(rules);
+        this.limitTime = 0L;
+        this.createTime = eventTime;
+        this.updateTime = eventTime;
+    }
+}

+ 2 - 2
src/main/resources/application.properties

@@ -120,8 +120,8 @@ cron.refresh.timer.clock=0 0-5 0 * * ?
 cron.clear.local.cache=0 15 0 * * ?
 #\u6BCF\u5206\u949F\u7684\u7B2C20\u79D2\u6267\u884C\u4E00\u6B21
 cron.check.minute.warn=20 0/1 * * * ?
-#\u6BCF\u4E2A\u6574\u70B9\u7684\u7B2C30\u5206\u949F\u6267\u884C\u4E00\u6B21
-cron.check.hour.warn=0 30 * * * ?
+#\u6BCF\u4E2A\u6574\u70B9\u7684\u7B2C5\u5206\u949F\u6267\u884C\u4E00\u6B21
+cron.check.hour.warn=0 5 * * * ?
 #\u6BCF\u592900:30:00\u6267\u884C\u4E00\u6B21
 cron.check.day.warn=0 30 0 * * ?