feiyu02
2023-11-13 7ecdc67dfb92b63bdc742e5c95d62bf9774cbd7f
1. 新增风险值的计算逻辑;
已修改4个文件
已添加4个文件
419 ■■■■■ 文件已修改
src/main/java/com/flightfeather/monitor/MonitorApplication.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisController.kt 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskAnalysis.kt 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskMonthAnalysis.kt 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/domain/ds1/repository/RiskValueRep.kt 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisControllerTest.kt 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/MonitorApplication.java
@@ -2,6 +2,7 @@
import com.flightfeather.monitor.scheduledtasks.TaskController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -14,7 +15,12 @@
    @Bean
    public ApplicationRunner runner() {
         return args -> taskController.run();
        return new ApplicationRunner() {
            @Override
            public void run(ApplicationArguments args) throws Exception {
//                taskController.run();
            }
        };
    }
    public static void main(String[] args) {
src/main/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisController.kt
@@ -1,7 +1,109 @@
package com.flightfeather.monitor.analysis.dust;
package com.flightfeather.monitor.analysis.dust
import com.flightfeather.monitor.analysis.dust.risk.*
import com.flightfeather.monitor.domain.ds1.repository.*
import com.flightfeather.monitor.enumration.dust.DeviceStatus
import com.flightfeather.monitor.utils.DateUtil
import org.springframework.stereotype.Component
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
/**
 * æ•°æ®é£Žé™©åˆ†æžæŽ§åˆ¶å™¨
 */
public class RiskAnalysisController {
}
@Component
class RiskAnalysisController(
    private val dustExceptionSettingRep: DustExceptionSettingRep,
    private val riskValueRep: RiskValueRep,
    private val dustSiteStatusRep: DustSiteStatusRep,
    private val dustSiteDataRep: DustSiteDataRep,
    private val dustExceptionDataRep: DustExceptionDataRep,
    private val dustStatisticValueRep: DustStatisticsValueRep,
) {
    private var running1 = false
    private var running2 = false
    private var taskDaily: DustRiskAnalysis? = null
    private var taskMonthly: DustRiskMonthAnalysis? = null
    fun init() {
        dustExceptionSettingRep.findLatestSetting("金山区")?.let {
            taskDaily = DustRiskAnalysis(it)
            taskMonthly = DustRiskMonthAnalysis(it)
        }
    }
    fun autoRunDaily() {
        val data = riskValueRep.findLatestData("day")
        val yesterday = LocalDate.now().minusDays(1)
        if (data == null) {
            runDaily(yesterday)
        } else {
            val date = LocalDateTime.ofInstant(data.lst.toInstant(), ZoneId.systemDefault())
            val sT = if (date.hour == 0 && date.minute == 0 && date.second == 0) {
                date.toLocalDate()
            } else {
                date.plusDays(1).toLocalDate()
            }
            val du = DateUtil.findDurationDate(sT, yesterday)
            du.forEach {
                runDaily(it)
            }
        }
    }
    fun autoRunMonthly() {
        val data = riskValueRep.findLatestData("month")
        val lastMonth = LocalDate.now().minusMonths(1).withDayOfMonth(1)
        if (data == null) {
            runMonthly(lastMonth)
        } else {
            val date = LocalDateTime.ofInstant(data.lst.toInstant(), ZoneId.systemDefault())
            val sT = date.plusMonths(1).toLocalDate()
            val du = DateUtil.findDurationMonth(sT, lastMonth)
            du.forEach {
                runMonthly(it)
            }
        }
    }
    fun runDaily(date: LocalDate) {
        running1 = true
        taskDaily?.init()
        // èŽ·å–æ‰€æœ‰å½“å‰ä¸Šçº¿å’Œåœè¿çš„è®¾å¤‡
        dustSiteStatusRep.select(listOf(DeviceStatus.ONLINE, DeviceStatus.STOP)).forEach { s ->
            s?.let {
                taskDaily?.roundInit()
                val dustSiteDataList = dustSiteDataRep.select(s.mnCode, date)
                val dustExceptionDataList = dustExceptionDataRep.select(s.mnCode, date)
                val dustStatisticValueList = dustStatisticValueRep.select(s.mnCode, date)
                if (dustStatisticValueList.isEmpty()) return@forEach
                taskDaily?.roundCal(dustStatisticValueList[0]!!, dustSiteDataList, dustExceptionDataList)
            }
        }
        // æ‰€æœ‰åˆ†æžç»“果入库
        if (taskDaily?.resultList?.isNotEmpty() == true) {
            riskValueRep.insert(taskDaily?.resultList!!)
        }
        running1 = false
    }
    fun runMonthly(date: LocalDate) {
        running2 = true
        taskMonthly?.init()
        dustSiteStatusRep.select(listOf(DeviceStatus.ONLINE, DeviceStatus.STOP)).forEach { s ->
            s?.let {
                taskMonthly?.roundInit()
                val riskValueList = riskValueRep.select(s.mnCode, date)
                taskMonthly?.roundCal(riskValueList)
            }
        }
        // æ‰€æœ‰åˆ†æžç»“果入库
        if (taskMonthly?.resultList?.isNotEmpty() == true) {
            riskValueRep.insert(taskMonthly?.resultList!!)
        }
        running2 = false
    }
}
src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskAnalysis.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,133 @@
package com.flightfeather.monitor.analysis.dust.risk
import com.flightfeather.monitor.domain.ds1.entity.*
import com.flightfeather.monitor.enumration.dust.ExceptionType
/**
 * æ‰¬å°˜ç›‘测数据风险分析基类
 */
class DustRiskAnalysis(val config: DustExceptionSetting) {
    //分析结果
    val resultList = mutableListOf<RiskValue>()
    /**
     * åˆå§‹åŒ–
     */
    fun init() {
        resultList.clear()
    }
    /**
     * æ¯è½®æ¬¡çš„初始化
     */
    fun roundInit() {
        resultList.add(RiskValue())
    }
    /**
     * æ¯è½®æ¬¡çš„风险值计算
     */
    fun roundCal(data: DustStatisticsValue, list: List<DustSiteData?>, dList: List<DustExceptionData?>) {
        if (resultList.isEmpty()) throw IllegalStateException("结果集resultList不能为空!")
        val res = resultList.last()
        riskOnlineRate(res, data)
        riskValidRate(res, data)
        riskExceedRate(res, list)
        riskExceptionRepetitionRate(res, dList)
        riskExceptionType(res, dList)
        onDone(res)
    }
    /**
     * åœ¨çº¿çŽ‡é£Žé™©å€¼
     */
    fun riskOnlineRate(riskValue: RiskValue, data: DustStatisticsValue) {
        val dayOnline = data.dayOnline.substring(0, data.dayOnline.lastIndex).toDouble() / 100
        riskValue.onlineRisk = 1 - dayOnline
    }
    /**
     * æœ‰æ•ˆçŽ‡é£Žé™©å€¼
     */
    fun riskValidRate(riskValue: RiskValue, data: DustStatisticsValue) {
        val dayValid = data.dayValid.substring(0, data.dayValid.lastIndex).toDouble() / 100
        riskValue.validRisk = 1 - dayValid
    }
    /**
     * è¶…标风险值
     */
    fun riskExceedRate(riskValue: RiskValue, list: List<DustSiteData?>) {
        // æ—¥è¶…标次数/7(大于1mg/m³,小于2mg/m³)
        var v1 = 0
        // æ—¥è¶…标次数/2(大于2mg/m³)
        var v2 = 0
        // æ—¥ä¸´è¿‘超标次数/7
        var v3 = 0
        list.forEach {d ->
            if (d == null) return@forEach
            when {
                d.dustValue >= 2.0 -> v2++
                d.dustValue >= 1.0 && d.dustValue < 2.0 -> v1++
                d.dustValue >= config.nearExceedLowValue && d.dustValue < config.nearExceedHighValue -> v3++
            }
        }
        // å’Œçš„æœ€å¤§å€¼ä¸º3最小值为0,上述之和除以3,结果最大值为1最小值为0,即为日超标风险值
        val r = (v1 + v2 + v3) / 3.0
        riskValue.exceedRisk = if (r > 1) 1.0 else r
    }
    /**
     * å…¸åž‹å¼‚常复现率
     */
    fun riskExceptionRepetitionRate(riskValue: RiskValue, list: List<DustExceptionData?>) {
        //1、针对量级突变异常、临近超标异常、单日超标次数临界异常的指定时段(如24小时内)重复出现概率来综合判定典型异常复现率;
        //2、日量级突变异常复现率(E4):(N4-1)/4, æœ€å¤§ä¸º1,最小为0
        //3、日临近超标异常复现率(E5):(N5-1)/3, æœ€å¤§ä¸º1,最小为0
        //4、日超标次数临界异常复现率(E6):(N6-1)/2, æœ€å¤§ä¸º1,最小为0
        //5、日典型异常复现率: å–E4、E5、E6的和,最大为1,最小为0
        //6、月典型异常复现率:当月内各日典型异常复现率的和/当月天数,最大为1,最小为0
        var v1 = 0
        var v2 = 0
        var v3 = 0
        list.forEach { d->
            if (d == null) return@forEach
            when (d.exceptionType) {
                ExceptionType.TYPE4.value -> v1++
                ExceptionType.TYPE5.value -> v2++
                ExceptionType.TYPE6.value -> v3++
            }
        }
        val e1 = upperLimit((v1 - 1) / 4.0)
        val e2 = upperLimit((v2 - 1) / 3.0)
        val e3 = upperLimit((v3 - 1) / 2.0)
        riskValue.typicalExceptionRepetitionRate = upperLimit(e1 + e2 + e3)
    }
    /**
     * å¼‚常类型聚集率
     */
    fun riskExceptionType(riskValue: RiskValue, list: List<DustExceptionData?>) {
        // æ—¥å¼‚常类型聚集率:当日出现的不同异常类型个数/6,最大为1,最小为0
        //2、月异常类型聚集率:当月内各日异常类型聚集率的和/当月天数,最大为1,最小为0
        // å…¶ä»–时段以此类推,数据超低、长时间无波动等两类异常暂不纳入分析,若纳入分析则分母为8
        val exceptionTypes = mutableListOf<Int>()
        list.forEach { d ->
            if (d == null) return@forEach
            if (!exceptionTypes.contains(d.exceptionType)) {
                if (d.exceptionType != ExceptionType.TYPE1.value && d.exceptionType != ExceptionType.TYPE3.value) {
                    exceptionTypes.add(d.exceptionType)
                }
            }
        }
        riskValue.exceptionTypeAggregation = exceptionTypes.size / 6.0
    }
    fun onDone(riskValue: RiskValue) {
        riskValue.type = "day"
    }
    private fun upperLimit(d:Double):Double = if (d > 1) 1.0  else d
}
src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskMonthAnalysis.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
package com.flightfeather.monitor.analysis.dust.risk
import com.flightfeather.monitor.domain.ds1.entity.*
class DustRiskMonthAnalysis(val config: DustExceptionSetting) {
    //分析结果
    val resultList = mutableListOf<RiskValue>()
    /**
     * åˆå§‹åŒ–
     */
    fun init() {
        resultList.clear()
    }
    /**
     * æ¯è½®æ¬¡çš„初始化
     */
    fun roundInit() {
        resultList.add(RiskValue())
    }
    /**
     * æ¯è½®æ¬¡çš„风险值计算
     */
    fun roundCal(list: List<RiskValue?>) {
        if (resultList.isEmpty()) throw IllegalStateException("结果集resultList不能为空!")
        val res = resultList.last()
        riskOnlineRate(res, list)
        riskValidRate(res, list)
        riskExceedRate(res, list)
        riskExceptionRepetitionRate(res, list)
        riskExceptionType(res, list)
        onDone(res)
    }
    fun riskOnlineRate(riskValue: RiskValue, list: List<RiskValue?>) {
        riskValue.onlineRisk = avg(list) { it.onlineRisk }
    }
    fun riskValidRate(riskValue: RiskValue, list: List<RiskValue?>) {
        riskValue.validRisk = avg(list) { it.validRisk }
    }
    fun riskExceedRate(riskValue: RiskValue, list: List<RiskValue?>) {
        riskValue.exceedRisk = avg(list) { it.exceedRisk }
    }
    fun riskExceptionRepetitionRate(riskValue: RiskValue, list: List<RiskValue?>) {
        riskValue.typicalExceptionRepetitionRate = avg(list) { it.typicalExceptionRepetitionRate }
    }
    fun riskExceptionType(riskValue: RiskValue, list: List<RiskValue?>) {
        riskValue.exceptionTypeAggregation = avg(list) { it.exceptionTypeAggregation }
    }
    fun onDone(riskValue: RiskValue) {
        riskValue.type = "month"
    }
    private fun avg(list: List<RiskValue?>, onNext: (value: RiskValue) -> Double): Double {
        var total = .0
        var count = 0
        list.forEach {
            if (it == null) return@forEach
            total += onNext(it)
            count++
        }
        return if (count == 0) .0 else total / count
    }
}
src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt
@@ -43,4 +43,14 @@
    fun insert(list: List<DustExceptionData>): Int {
        return dustExceptionDataMapper.insertList(list)
    }
    fun select(mnCode: String, date: LocalDate): List<DustExceptionData?> {
        val s = date.atStartOfDay()
        val e = s.plusDays(1).minusSeconds(1)
        return dustExceptionDataMapper.selectByExample(Example(DustExceptionData::class.java).apply {
            createCriteria().andBetween("beginTime", s, e)
                .andEqualTo("mnCode", mnCode)
            orderBy("beginTime")
        })
    }
}
src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt
@@ -1,5 +1,6 @@
package com.flightfeather.monitor.domain.ds1.repository
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionData
import com.flightfeather.monitor.domain.ds1.entity.DustStatisticsValue
import com.flightfeather.monitor.domain.ds1.mapper.DustStatisticsValueMapper
import com.github.pagehelper.PageHelper
@@ -45,12 +46,17 @@
    }
    fun monthlyStatics(date: LocalDate) {
        val s = date.atStartOfDay()
        val s = date.withDayOfMonth(1).atStartOfDay()
        val e = s.plusMonths(1).minusSeconds(1)
        val d = Duration.between(s, e).toDays() + 1
        val dataCount = d * 96
        dustStatisticsValueMapper.monthlyStatics(s, e, dataCount.toInt())
    }
    fun select(mnCode: String, date: LocalDate): List<DustStatisticsValue?> {
        return dustStatisticsValueMapper.selectByExample(Example(DustStatisticsValue::class.java).apply {
            createCriteria().andEqualTo("lst", date)
                .andEqualTo("mnCode", mnCode)
        })
    }
}
src/main/java/com/flightfeather/monitor/domain/ds1/repository/RiskValueRep.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.flightfeather.monitor.domain.ds1.repository
import com.flightfeather.monitor.domain.ds1.entity.RiskValue
import com.flightfeather.monitor.domain.ds1.mapper.RiskValueMapper
import com.github.pagehelper.PageHelper
import org.springframework.stereotype.Repository
import tk.mybatis.mapper.entity.Example
import java.time.LocalDate
@Repository
class RiskValueRep(private val riskValueMapper: RiskValueMapper) {
    /**
     * èŽ·å–æœ€æ–°ä¸€æ¡è®°å½•
     */
    fun findLatestData(type: String): RiskValue? {
        val p = PageHelper.startPage<RiskValue>(1, 1)
        riskValueMapper.selectByExample(Example(RiskValue::class.java).apply {
            createCriteria().andEqualTo("type", type)
            orderBy("lst").desc()
        })
        return if (p.isNotEmpty()) {
            p[0]
        } else {
            null
        }
    }
    fun insert(list: List<RiskValue>): Int {
        return riskValueMapper.insertList(list)
    }
    fun select(mnCode: String, date: LocalDate): List<RiskValue?> {
        val s = date.withDayOfMonth(1).atStartOfDay()
        val e = s.plusMonths(1).minusSeconds(1)
        return riskValueMapper.selectByExample(Example(RiskValue::class.java).apply {
            createCriteria().andEqualTo("mnCode", mnCode)
                .andBetween("lst", s, e)
        })
    }
}
src/test/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisControllerTest.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package com.flightfeather.monitor.analysis.dust
import com.flightfeather.monitor.utils.DateUtil
import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.context.junit4.SpringRunner
import java.time.LocalDate
@RunWith(SpringRunner::class)
@ExtendWith(SpringExtension::class)
@SpringBootTest
class RiskAnalysisControllerTest {
    @Autowired
    lateinit var riskAnalysisController: RiskAnalysisController
    @Test
    fun autoRunDaily() {
        val s = LocalDate.of(2023, 10, 1)
        val e = LocalDate.of(2023, 10, 31)
        val du = DateUtil.findDurationDate(s, e)
        du.forEach {
            riskAnalysisController.runDaily(it)
        }
    }
    @Test
    fun autoRunMonthly() {
        riskAnalysisController.autoRunMonthly()
    }
}