feiyu02
2025-07-21 38d72198bfcced01ed9513b978163e5cd1d84625
src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt
@@ -1,122 +1,338 @@
package com.flightfeather.uav.biz.dataanalysis
import com.flightfeather.uav.biz.dataanalysis.model.DataAnalysisConfig
import com.flightfeather.uav.biz.FactorFilter
import com.flightfeather.uav.biz.dataanalysis.model.ExceptionTag
import com.flightfeather.uav.domain.entity.BaseRealTimeData
import com.flightfeather.uav.lightshare.eunm.ExceptionStatusType
import com.flightfeather.uav.socket.eunm.FactorType
import org.springframework.beans.BeanUtils
import java.time.Duration
/**
 * 连续类型的异常分析基类,适用于当前数据与相邻数据之间有关联关系的情况
 */
abstract class BaseExceptionContinuous(config: DataAnalysisConfig) : BaseExceptionAnalysis(config) {
abstract class BaseExceptionContinuous<T : ExceptionTag, V : BaseAnalysisConfig, Y : BaseExceptionResult>(
    config: V, private val tagClz: Class<T>,
) : BaseExceptionAnalysis<V, Y>(config) {
    enum class JudgeMethod(val des: String) {
        M1("在一定的空间和时间范围内,数据累计出现N次异常后,认为该异常成立"),
        M2("要求数据不间断连续出现N次异常后,认为该异常成立"),
    }
    companion object {
        // 记录异常数据段时,分别向起始前和末尾后额外记录的数据个数偏移量
        private const val OFFSET = 10
    }
    // 起始数据下标
    protected var sIndex = mutableListOf<Int>()
    protected val tagMap = mutableMapOf<FactorType, T>()
    // 起始数据对象
    protected var startData = mutableListOf<BaseRealTimeData?>()
    // 末尾数据下标
    protected var eIndex = mutableListOf<Int>()
    // 起始数据与末尾数据间隔
    open var durationCount = 1
    // 末尾数据对象
    protected var lastData: BaseRealTimeData? = null
    // 异常数据段
    protected var exceptionData = mutableListOf<MutableList<BaseRealTimeData>>()
    // 起始数据与末尾数据间隔
    open var durationCount = 1
    protected var existException = mutableListOf<Boolean>()
    // 最新的一组异常,记录单因子异常
    protected val latestExceptions = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>()
    /**
     * 判断是否满足异常条件
     * 最新的一组合并异常,根据配置参数从[latestExceptions]单因子异常中,合并异常
     */
    abstract fun judgeException(p: BaseRealTimeData?, n: BaseRealTimeData): List<Boolean>
    protected val latestCombinedExc = mutableListOf<List<Pair<FactorFilter.SelectedFactor, T>>>()
    /**
     * 判断异常出现的连续时长是否满足条件
     * 异常结果
     */
    abstract fun judgeDuration(sIndex: Int, eIndex: Int): Boolean
    protected val result = mutableListOf<Y>()
    /**
     * 不适用于此异常类型的监测因子
     */
    open var excludedFactor: List<FactorType> = emptyList()
    abstract var judgeMethod: JudgeMethod
    /**
     * 立即判断:当出现异常时,缓存异常数据的同时,立即对已有异常进行判断是否满足异常结果要求
     */
    open fun immeExcCheck(tag: T, factorType: FactorType): Boolean {
        return false
    }
    /**
     * 判断相邻数据是否连续
     */
    open fun isContinuous(d1: BaseRealTimeData?, d2: BaseRealTimeData?): Boolean {
        if (d1 == null || d2 == null) return true
        val t1 = d1.dataTime
        val t2 = d2.dataTime
        return Duration.between(t1?.toInstant(), t2?.toInstant()).toMillis() <= (20 * 1000)
    }
    /**
     * 判断数据量级在异常判断的范围内
     * 默认所有量级都在异常判断的范围内
     */
    open fun judgeDataScale(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> {
        val res = mutableMapOf<FactorType, Boolean>()
        config.factorFilter.mainList().forEach { f -> res[f] = true }
        return res
    }
    /**
     * 判断前后数据是否满足异常条件
     */
    abstract fun judgeException(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean>
    /**
     * 判断异常出现的连续个数是否满足条件
     * @param tag 异常数据对象
     */
    abstract fun judgeExceptionCount(tag: T, factorType: FactorType?): Boolean
    /**
     * 判断监测因子是否出现异常
     */
    open fun judge(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> {
        val jds = judgeDataScale(p, n)
        val jex = judgeException(p, n)
        val res = mutableMapOf<FactorType, Boolean>()
        jds.forEach { (t, u) ->
            res[t] = u && jex[t] ?: false
        }
        return res
    }
    /**
     * 异常数据的截取判断
     * @return
     */
    open fun needCut(tag: T, hasException: Boolean?, data: BaseRealTimeData): Boolean {
        // 默认判断条件为 当异常不再重复出现时
        return tag.exceptionExisted && hasException == false
    }
    override fun init() {
        super.init()
        lastData = null
        repeat(config.factorCount) {
            startData.add(null)
            sIndex.add(0)
            eIndex.add(-1)
            existException.add(false)
            exceptionData.add(mutableListOf())
        tagMap.clear()
        config.factorFilter.mainList().forEach { f ->
            tagMap[f] = tagClz.newInstance()
        }
    }
    override fun onNextData(data: BaseRealTimeData) {
        val isContinue = isContinuous(lastData, data)
        val hasException = judgeException(lastData, data)
        repeat(config.factorCount) { i ->
            eIndex[i]++
            // 起始数据
            if (lastData == null) {
                refreshAfterCheckResult(i, data)
            }
            // 判断相邻数据是否连续并且是否满足异常判断
            if (!isContinue) {
                checkResult()
                // 数据不连续时,记录异常情况
                if (eIndex[i] - sIndex[i] >= durationCount) {
                    refreshAfterCheckResult(i, data)
        val hasException = judge(lastData, data)
        config.factorFilter.selectedList.forEach { s ->
            val f = s.main
            // 排除此异常类型不适用的监测因子
            if (excludedFactor.contains(f)) return@forEach
            tagMap[f]?.let {
                it.eIndex++
                // 起始数据
                it.endData = data
                if (it.startData == null) {
                    it.refreshWithNextException(data)
                }
            } else {
                if (hasException[i]) {
                    existException[i] = true
                    exceptionData[i].add(data)
                } else {
                    // 异常不再重复出现时,记录异常情况
                    checkResult()
                    if (eIndex[i] - sIndex[i] >= durationCount) {
                        refreshAfterCheckResult(i, data)
                    }
                // 按照不同的方式进行异常判断
                when (judgeMethod) {
                    JudgeMethod.M1 -> judgeMethod1(hasException, f, it, data, s)
                    JudgeMethod.M2 -> judgeMethod2(isContinue, hasException, f, it, data, s)
                }
                it.addHistoryData(data)
            }
        }
        lastData = data
        mergeExceptionResult()
        clearExceptions(data)
    }
    override fun onDone() {
        checkResult()
        checkResult(exceptionStatus = ExceptionStatusType.Ended)
    }
    fun refreshAfterCheckResult(i:Int, data: BaseRealTimeData) {
        sIndex[i] = eIndex[i]
        startData[i] = data
        exceptionData[i].clear()
        exceptionData[i].add(data)
    /**
     * 数据异常判断方式一
     * 在一定的空间和时间范围内,数据累计出现N次异常后,认为该异常成立
     */
    private fun judgeMethod1(
        hasException: MutableMap<FactorType, Boolean>,
        f: FactorType,
        tag: T,
        data: BaseRealTimeData,
        s: FactorFilter.SelectedFactor,
    ) {
        // 出现异常
        if (hasException[f] == true) {
            // 判断数据在空间和时间变化上是否超出限定范围,若超出则删除遗留的异常记录,刷新起始点数据
            if (needCut(tag, hasException[f], data)) {
                tag.refreshWithNextException(data)
            }
            // 记录异常数据
            tag.addExceptionData(data)
            // 当立即判断通过时,形成异常结果
            if (immeExcCheck(tag, f)) {
                recordException(s, tag, data)
            }
        }
        // 数据正常,并且没有历史异常数据时,刷新起始点数据
        else if (!tag.exceptionExisted) {
            tag.refreshWithNextException(data)
        }
    }
    /**
     * 数据异常判断方式二
     * 要求数据不间断连续出现N次异常后,认为该异常成立
     */
    private fun judgeMethod2(
        isContinue: Boolean,
        hasException: MutableMap<FactorType, Boolean>,
        f: FactorType,
        tag: T,
        data: BaseRealTimeData,
        s: FactorFilter.SelectedFactor,
    ) {
        // 当相邻数据时间不连续时,刷新起始点数据,移除历史异常记录
        if (!isContinue) {
            tag.refreshWithNextException(data)
        }
        // 出现异常
        else if (hasException[f] == true) {
            // 有异常出现时,记录异常数据
            tag.addExceptionData(data)
            // 当立即判断通过时,形成异常结果
            if (immeExcCheck(tag, f)) {
                recordException(s, tag, data)
            }
        }
        // 数据正常,刷新起始点数据,移除历史异常记录
        else {
            tag.refreshWithNextException(data)
        }
    }
    /**
     * 异常结束,记录异常
     * 判断已有的异常数据是否满足异常条件,满足则记录,不满足则略过
     */
    fun recordException(factor: FactorFilter.SelectedFactor, tag: T, data: BaseRealTimeData) {
        checkResult(factor, ExceptionStatusType.Ended)
//        tag.refreshWithNextException(data)
    }
    /**
     * 检查连续异常结束时,是否符合异常存储条件
     */
    open fun checkResult(index: Int? = null) {
        if (index != null) {
            if (existException[index] && judgeDuration(sIndex[index], eIndex[index])) {
                startData[index]?.let {
                    resultList.add(newResult(it, lastData, index, exceptionData[index]))
                }
                existException[index] = false
    open fun checkResult(
        factor: FactorFilter.SelectedFactor? = null,
        exceptionStatus: ExceptionStatusType = ExceptionStatusType.InProgress,
    ) {
        val tag = tagMap[factor?.main]
        if (factor != null && tag != null) {
            if (tag.exceptionExisted && judgeExceptionCount(tag, factor.main)) {
                onNewException(tag, factor, exceptionStatus)
            }
        } else {
            repeat(config.factorCount) { i ->
                if (existException[i] && judgeDuration(sIndex[i], eIndex[i])) {
                    startData[i]?.let {
                        resultList.add(newResult(it, lastData, i, exceptionData[i]))
                    }
                    existException[i] = false
            config.factorFilter.selectedList.forEach { f ->
                val tag1 = tagMap[f.main] ?: return@forEach
                if (tag1.exceptionExisted && judgeExceptionCount(tag1, f.main)) {
                    onNewException(tag1, f, exceptionStatus)
                }
            }
        }
    }
    /**
     * 新增或更新一条异常
     */
    open fun onNewException(tag: T, factor: FactorFilter.SelectedFactor, exceptionStatus: ExceptionStatusType) {
        if (tag.startData == null) return
//        val ex = newResult(tag.startData!!, tag.endData, factor, tag.exceptionData)
//        val ex = newResult(tag, factor)
//            .apply { status = exceptionStatus.value }
//        // 异常已创建时,更新异常信息
//        if (tag.exceptionCreated) {
//            // 将最新的异常的guid赋值给ex
//            val lastEx = tag.exceptionResult.last()
//            ex.guid = lastEx.guid
//            tag.exceptionResult.removeLast()
//            tag.exceptionResult.add(ex)
//        }
//        // 异常未创建时,新建异常信息
//        else {
//            tag.exceptionResult.add(ex)
//            tag.exceptionCreated = true
//        }
//        val tagClone = tagClz.newInstance()
//        BeanUtils.copyProperties(tag, tagClone)
        latestExceptions.add(factor to tag)
    }
    /**
     * 合并异常
     */
    open fun mergeExceptionResult() {
        // 遍历所有的因子组合
        config.factorFilter.combination.forEach { c ->
            val res = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>()
            var exist = true
            // 查看组合内的所有因子是否都同时出现异常
            c.forEach { f ->
                val r = latestExceptions.find { e ->
                    e.first.main == f
                }
                if (r != null) {
                    res.add(r)
                } else {
                    exist = false
                }
            }
            // 如果组合内的所有因子都存在异常,则存储为合并异常
            if (exist) {
                // 将合并异常从单个异常集合中去除
                res.forEach { r ->
                    latestExceptions.removeIf { e -> e.first.main == r.first.main }
                }
                // 将合并异常存储
                latestCombinedExc.add(res)
            }
        }
        // 存储异常结果
        latestExceptions.forEach {
            result.add(newResult(listOf(it)))
        }
        latestCombinedExc.forEach {
            result.add(newResult(it))
        }
    }
    private fun clearExceptions(data: BaseRealTimeData) {
        latestExceptions.forEach {
            it.second.refreshWithNextException(data)
        }
        latestExceptions.clear()
        latestCombinedExc.forEach {
            it.forEach { e ->
                e.second.refreshWithNextException(data)
            }
        }
        latestCombinedExc.clear()
        result.clear()
    }
    /**
     * 生成一条异常分析结果
     */
    abstract fun newResult(tag: T, factor: FactorFilter.SelectedFactor): Y
    abstract fun newResult(exceptions: List<Pair<FactorFilter.SelectedFactor, ExceptionTag>>): Y
}