feiyu02
2025-08-14 dac47617b37ccfb834cd73ce0ee725e1101de214
src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt
@@ -2,10 +2,10 @@
import com.flightfeather.uav.biz.FactorFilter
import com.flightfeather.uav.biz.dataanalysis.model.ExceptionTag
import com.flightfeather.uav.biz.sourcetrace.model.RemainException
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
/**
@@ -34,17 +34,20 @@
    protected var lastData: BaseRealTimeData? = null
    // 最新的一组异常,记录单因子异常
    protected val latestExceptions = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>()
    val latestExceptions = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>()
    /**
     * 最新的一组合并异常,根据配置参数从[latestExceptions]单因子异常中,合并异常
     */
    protected val latestCombinedExc = mutableListOf<List<Pair<FactorFilter.SelectedFactor, T>>>()
    // 记录需要延迟数据周期进行合并的异常
    val remainingExceptions = mutableListOf<RemainException<T>>()
    /**
     * 异常结果
     */
    protected val result = mutableListOf<Y>()
    val result = mutableListOf<Y>()
    /**
     * 不适用于此异常类型的监测因子
@@ -150,7 +153,10 @@
        }
        lastData = data
        mergeExceptionResult()
        removeSingleFactor(data)
        val fittedComb = checkDelayedExceptions(data)
        mergeExceptionResult(data, fittedComb)
        onNewResult(result)
        clearExceptions(data)
    }
@@ -277,54 +283,175 @@
    }
    /**
     * 合并异常
     * 将不在关联关系中的监测因子异常存储,并剔除
     */
    open fun mergeExceptionResult() {
    fun removeSingleFactor(data: BaseRealTimeData) {
        if (latestExceptions.isEmpty()) return
        // 查找不在因子关联组合中的异常因子
        val sfList = latestExceptions.filter {
            config.factorFilter.combination.find { c -> c.find { f -> f == it.first.main } != null } == null
        }
        // 生成对应的异常结果,并初始化该异常
        sfList.forEach {
            result.add(newResult(listOf(it)))
            it.second.refreshWithNextException(data)
        }
        // 剔除
        latestExceptions.removeAll(sfList)
    }
    /**
     * 检查延迟的待合并异常与当前异常是否能匹配
     * 1. 将遗留的超过等待数据周期的异常存储
     * 2. 将匹配成功的合并异常存储,同时将关联关系标记为已匹配
     * 3. 保留依旧未合并成功并且可继续等待的异常
     * @return 被匹配成功的关联关系
     */
    fun checkDelayedExceptions(data: BaseRealTimeData): List<List<FactorType>> {
        if (latestExceptions.isEmpty()) return emptyList()
        // 被匹配成功的监测因子关联关系
        val fittedComb = mutableListOf<List<FactorType>>()
        // 遗留的进入下一个数据周期做判断的待合并异常集合
        val leftExc = mutableListOf<RemainException<T>>()
        // 成功匹配的合并异常集合
        val combinedExc = mutableListOf<List<Pair<FactorFilter.SelectedFactor, T>>>()
        // 本次数据周期中,被匹配成功的异常集合
        val exceps = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>()
        remainingExceptions.forEach {
            // 检查本次数据周期的异常中,是否包含因子关联关系中的异常
            val combRes = matchCombFactor(it.combination, latestExceptions)
            val res = combRes.second
            // 判断本次数据周期中找到的因子和已有的因子是否满足关联关系
            val findFactors = mutableListOf<FactorType>()
            res.forEach {r -> findFactors.add(r.first.main) }
            it.exceptions.forEach {r -> findFactors.add(r.first.main) }
            val isFitAll = findFactors.distinct() == it.combination
            // 如果已经没有缺失的异常因子,则可合并为组合异常
            if (isFitAll) {
                fittedComb.add(it.combination)
                // 将查找结果添加至已有异常集合中
                it.addExceptions(res)
//                // 记录被匹配成功的异常
//                res.forEach { r->
//                    if (exceps.find { e -> e.second == r.second } == null) {
//                        exceps.add(r)
//                    }
//                }
                // 将合并异常存储
                combinedExc.add(it.exceptions)
            }
            // 否则留作下次数据周期再判定存入待合并异常集合
            else {
                it.period++
                // 当待合并的异常等待数据周期大于设定值时,不再等待,直接输出异常
                if (it.period > config.maxDelayPeriod) {
                    result.add(newResult(it.exceptions))
                    return@forEach
                } else {
                    fittedComb.add(it.combination)
                    // 将查找结果添加至已有异常集合中
                    it.addExceptions(res)
//                    // 记录被匹配成功的异常
//                    res.forEach { r->
//                        if (exceps.find { e -> e.second == r.second } == null) {
//                            exceps.add(r)
//                        }
//                    }
                    leftExc.add(it)
                }
            }
        }
        // 存储合并异常
        combinedExc.forEach {
            result.add(newResult(it))
        }
//        // 将被匹配成功的异常刷新,并从本次数据周期的异常集合中移除
//        exceps.forEach { r-> r.second.refreshWithNextException(data) }
//        latestExceptions.removeAll(exceps)
        // 保留未匹配的组合
        remainingExceptions.clear()
        remainingExceptions.addAll(leftExc)
        return fittedComb
    }
    /**
     * 合并异常
     * @param data 当前监测数据
     * @param fittedComb 在遗留的异常[remainingExceptions]判断中,已经进行匹配判断的关联关系,将不再进行匹配
     */
    open fun mergeExceptionResult(data: BaseRealTimeData, fittedComb: List<List<FactorType>>) {
        if (latestExceptions.isEmpty()) return
        val combinedExc = mutableListOf<List<Pair<FactorFilter.SelectedFactor, T>>>()
        // 遍历所有的因子组合
        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
                }
            }
            /**
             * 跳过已经在[checkDelayedExceptions]中判断过的关联关系
             */
            if (fittedComb.indexOf(c) >= 0) return@forEach
            val combRes = matchCombFactor(c, latestExceptions)
            val res = combRes.second
            val exist = combRes.first
            // 如果组合内的所有因子都存在异常,则存储为合并异常
            if (exist) {
                // 将合并异常从单个异常集合中去除
                res.forEach { r ->
                    latestExceptions.removeIf { e -> e.first.main == r.first.main }
                }
                // 将合并异常存储
                latestCombinedExc.add(res)
                combinedExc.add(res)
            }
            // 否则将异常的深拷贝版本存入待合并异常集合
            // TODO 2025.8.4: 后续添加当关联的监测因子累计异常计数接近阈值时,才存入集合的逻辑
            else if (res.isNotEmpty()) {
                remainingExceptions.add(RemainException(res, c))
            }
        }
        // 存储异常结果
        latestExceptions.forEach {
            result.add(newResult(listOf(it)))
        }
        latestCombinedExc.forEach {
        // 存储合并异常
        combinedExc.forEach {
            result.add(newResult(it))
        }
    }
    /**
     * 匹配关联异常因子
     * @param comb 关联因子关系
     * @param exceptions 各监测因子异常集合
     * @return exist表示是否找到关联关系[comb]中所有的因子,res表示找到的结果
     */
    private fun matchCombFactor(
        comb: List<FactorType>,
        exceptions: List<Pair<FactorFilter.SelectedFactor, T>>,
    ): Pair<Boolean, MutableList<Pair<FactorFilter.SelectedFactor, T>>> {
        val res = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>()
        var exist = true
        // 查看组合内的所有因子是否都同时出现异常
        comb.forEach { f ->
            val r = exceptions.find { e ->
                e.first.main == f
            }
            if (r != null) {
                res.add(r)
            } else {
                exist = false
            }
        }
        return exist to res
    }
    abstract fun onNewResult(result: List<Y>)
    /**
     * 在异常生成结果后,进行初始化
     */
    private fun clearExceptions(data: BaseRealTimeData) {
        // 此时latestExceptions中应该包含的依旧是本次数据周期内的所有异常
        latestExceptions.forEach {
            it.second.refreshWithNextException(data)
        }
        latestExceptions.clear()
        latestCombinedExc.forEach {
            it.forEach { e ->
                e.second.refreshWithNextException(data)
            }
        }
        latestCombinedExc.clear()
        result.clear()
    }