package com.tongchuang.realtime.mds;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tongchuang.realtime.bean.ULEParamConfig;
import com.tongchuang.realtime.util.KafkaUtils;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.state.*;
import org.apache.flink.api.common.time.Time;
import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.streaming.api.datastream.*;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.co.KeyedBroadcastProcessFunction;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.apache.flink.util.Collector;
import org.apache.flink.util.OutputTag;
import java.io.Serializable;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class ULEDataanomalyanalysis {
public static void main(String[] args) throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
// 创建Kafka消费者
KafkaSource<String> kafkaConsumer = KafkaUtils.getKafkaConsumer(
"realdata_minute",
"minutedata_uledataanomalyanalysis",
OffsetsInitializer.latest()
);
DataStreamSource<String> kafkaDS = env.fromSource(
kafkaConsumer,
WatermarkStrategy.noWatermarks(),
"realdata_uledataanomalyanalysis"
);
kafkaDS.print("分钟数据流");
// 解析JSON并拆分每个tag的数据
SingleOutputStreamOperator<JSONObject> splitStream = kafkaDS
.map(JSON::parseObject)
.flatMap((JSONObject value, Collector<JSONObject> out) -> {
JSONObject data = value.getJSONObject("datas");
String time = value.getString("times");
for (String tag : data.keySet()) {
JSONObject tagData = data.getJSONObject(tag);
JSONObject newObj = new JSONObject();
newObj.put("time", time);
newObj.put("tag", tag);
newObj.put("ontime", tagData.getDouble("ontime"));
newObj.put("avg", tagData.getDouble("avg"));
out.collect(newObj);
}
})
.returns(TypeInformation.of(JSONObject.class))
.name("Split-By-Tag");
// 每5分钟加载参数配置
DataStream<ConfigCollection> configDataStream = env
.addSource(new MysqlConfigSource())
.setParallelism(1)
.filter(Objects::nonNull)
.name("Config-Source");
// 将配置流转换为广播流
BroadcastStream<ConfigCollection> configBroadcastStream = configDataStream
.broadcast(Descriptors.configStateDescriptor);
// 按tag分组并连接广播流
KeyedStream<JSONObject, String> keyedStream = splitStream
.keyBy(json -> json.getString("tag"));
BroadcastConnectedStream<JSONObject, ConfigCollection> connectedStream =
keyedStream.connect(configBroadcastStream);
// 异常检测处理
SingleOutputStreamOperator<JSONObject> anomalyStream = connectedStream
.process(new OptimizedAnomalyDetectionFunction())
.name("Anomaly-Detection");
anomalyStream.print("异常检测结果");
// anomalyStream.map(JSON::toString).addSink(KafkaUtils.getKafkaSink("minutedata_uleanomaly"));
env.execute("uledataanomalyanalysis");
}
// 配置集合类 - 添加检查点时间
public static class ConfigCollection implements Serializable {
private static final long serialVersionUID = 1L;
public final Map<String, List<ULEParamConfig>> tagToConfigs;
public final Map<String, ULEParamConfig> encodeToConfig;
public final Set<String> allTags;
public final long checkpointTime; // 配置加载的时间戳
public ConfigCollection(Map<String, List<ULEParamConfig>> tagToConfigs,
Map<String, ULEParamConfig> encodeToConfig) {
this.tagToConfigs = new HashMap<>(tagToConfigs);
this.encodeToConfig = new HashMap<>(encodeToConfig);
this.allTags = new HashSet<>(tagToConfigs.keySet());
this.checkpointTime = System.currentTimeMillis(); // 记录配置加载时间
}
}
// MySQL配置源
public static class MysqlConfigSource extends RichSourceFunction<ConfigCollection> {
private volatile boolean isRunning = true;
private final long interval = TimeUnit.MINUTES.toMillis(5);
@Override
public void run(SourceContext<ConfigCollection> ctx) throws Exception {
while (isRunning) {
ConfigCollection newConfig = loadParams();
if (newConfig != null) {
ctx.collect(newConfig);
System.out.println("配置加载完成,检查点时间: " + new Date(newConfig.checkpointTime));
} else {
System.out.println("配置加载失败");
}
Thread.sleep(interval);
}
}
private ConfigCollection loadParams() {
Map<String, List<ULEParamConfig>> tagToConfigs = new HashMap<>(5000);
Map<String, ULEParamConfig> encodeToConfig = new HashMap<>(5000);
String url = "jdbc:mysql://10.51.37.73:3306/eps?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8";
String user = "root";
String password = "6CKIm5jDVsLrahSw";
String query = "SELECT F_tag AS tag, F_enCode AS encode, F_dataTypes AS datatype, " +
"F_isConstantValue AS constantvalue, F_isOnline AS isonline, " +
"F_isSync AS issync, F_syncParaEnCode AS syncparaencode, " +
"F_isZero AS iszero, F_isHigh AS ishigh, F_highThreshold AS highthreshold, " +
"F_isLow AS islow, F_lowThreshold AS lowthreshold, F_duration AS duration " +
"FROM t_equipmentparameter " +
"WHERE F_enabledmark = '1' AND (F_isConstantValue ='1' OR F_isZero= '1' " +
"OR F_isHigh = '1' OR F_isLow = '1' OR F_isOnline = '1' OR F_isSync = '1')";
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
while (rs.next()) {
ULEParamConfig config = new ULEParamConfig();
config.tag = rs.getString("tag");
config.encode = rs.getString("encode");
config.datatype = rs.getString("datatype");
config.constantvalue = rs.getInt("constantvalue");
config.iszero = rs.getInt("iszero");
config.ishigh = rs.getInt("ishigh");
config.highthreshold = rs.getDouble("highthreshold");
config.islow = rs.getInt("islow");
config.lowthreshold = rs.getDouble("lowthreshold");
config.duration = rs.getLong("duration");
config.isonline = rs.getInt("isonline");
config.issync = rs.getInt("issync");
config.syncparaencode = rs.getString("syncparaencode");
// 跳过无效配置
if (config.encode == null || config.encode.isEmpty()) {
System.err.println("忽略无效配置: 空encode");
continue;
}
String tag = config.tag;
tagToConfigs.computeIfAbsent(tag, k -> new ArrayList<>(10)).add(config);
encodeToConfig.put(config.encode, config);
}
System.out.println("加载配置: " + encodeToConfig.size() + " 个参数");
return new ConfigCollection(tagToConfigs, encodeToConfig);
} catch (SQLException e) {
System.err.println("加载参数配置错误:");
e.printStackTrace();
return null;
}
}
@Override
public void cancel() {
isRunning = false;
}
}
// 状态描述符
public static class Descriptors {
public static final MapStateDescriptor<Void, ConfigCollection> configStateDescriptor =
new MapStateDescriptor<>(
"configState",
TypeInformation.of(Void.class),
TypeInformation.of(ConfigCollection.class)
);
}
// 优化后的异常检测函数(无定时器实现)
public static class OptimizedAnomalyDetectionFunction
extends KeyedBroadcastProcessFunction<String, JSONObject, ConfigCollection, JSONObject> {
// 状态管理
private transient MapState<String, AnomalyState> stateMap; // key=encode
private transient MapState<String, Double> lastValuesMap; // key=tag
private transient MapState<String, Long> lastDataTimeMap; // key=tag
private transient ValueState<Long> lastCheckpointState; // 记录该tag上次处理的检查点时间
private transient SimpleDateFormat timeFormat;
// 日志频率控制
private transient long lastSyncLogTime = 0;
// 侧输出标签用于离线检测
private static final OutputTag<String> OFFLINE_CHECK_TAG = new OutputTag<String>("offline-check"){};
@Override
public void open(Configuration parameters) {
// 状态TTL配置(30天自动清理)
StateTtlConfig ttlConfig = StateTtlConfig.newBuilder(Time.days(300))
.setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
.setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
.cleanupFullSnapshot()
.build();
// 初始化异常状态存储(启用TTL)
MapStateDescriptor<String, AnomalyState> stateDesc = new MapStateDescriptor<>(
"anomalyState",
BasicTypeInfo.STRING_TYPE_INFO,
TypeInformation.of(AnomalyState.class)
);
stateDesc.enableTimeToLive(ttlConfig);
stateMap = getRuntimeContext().getMapState(stateDesc);
// 初始化最新值存储(启用TTL)
MapStateDescriptor<String, Double> valuesDesc = new MapStateDescriptor<>(
"lastValuesState",
BasicTypeInfo.STRING_TYPE_INFO,
BasicTypeInfo.DOUBLE_TYPE_INFO
);
valuesDesc.enableTimeToLive(ttlConfig);
lastValuesMap = getRuntimeContext().getMapState(valuesDesc);
// 初始化最后数据时间存储(启用TTL)
MapStateDescriptor<String, Long> timeDesc = new MapStateDescriptor<>(
"lastDataTimeState",
BasicTypeInfo.STRING_TYPE_INFO,
BasicTypeInfo.LONG_TYPE_INFO
);
timeDesc.enableTimeToLive(ttlConfig);
lastDataTimeMap = getRuntimeContext().getMapState(timeDesc);
// 初始化检查点状态(记录上次处理的配置时间)
ValueStateDescriptor<Long> checkpointDesc = new ValueStateDescriptor<>(
"lastCheckpointState",
BasicTypeInfo.LONG_TYPE_INFO
);
checkpointDesc.enableTimeToLive(ttlConfig);
lastCheckpointState = getRuntimeContext().getState(checkpointDesc);
timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
}
@Override
public void processElement(JSONObject data, ReadOnlyContext ctx, Collector<JSONObject> out) throws Exception {
String tag = ctx.getCurrentKey();
String timeStr = data.getString("time");
long eventTime = timeFormat.parse(timeStr).getTime();
// 更新最后数据时间
lastDataTimeMap.put(tag, eventTime);
// 获取广播配置
ConfigCollection configCollection = getBroadcastConfig(ctx);
if (configCollection == null) {
return;
}
List<ULEParamConfig> configs = configCollection.tagToConfigs.get(tag);
if (configs == null || configs.isEmpty()) {
return;
}
// 跟踪已恢复的tag
Set<String> recoveredTags = new HashSet<>();
// ========== 清理无效状态 ==========
Iterator<String> stateKeys = stateMap.keys().iterator();
while (stateKeys.hasNext()) {
String encode = stateKeys.next();
boolean found = false;
for (ULEParamConfig cfg : configs) {
if (cfg.encode.equals(encode)) {
found = true;
break;
}
}
if (!found) {
System.out.println("清理过期状态: " + encode);
stateMap.remove(encode);
}
}
// ========== 检查离线状态(基于配置检查点) ==========
Long lastCP = lastCheckpointState.value();
if (lastCP == null || configCollection.checkpointTime > lastCP) {
// 新配置到达,检查离线状态
for (ULEParamConfig config : configs) {
if (config.isonline == 1) {
// 获取该tag的最后数据时间
Long lastEventTime = lastDataTimeMap.get(tag);
if (lastEventTime == null) {
// 从未收到数据,触发离线报警
AnomalyState state = getOrCreateState(config.encode);
AnomalyStatus status = state.getStatus(5);
if (!status.reported) {
// 使用超时时间点作为触发时间
long timeoutPoint = configCollection.checkpointTime;
String triggerTime = timeFormat.format(new Date(timeoutPoint));
reportAnomaly(5, 1, 0.0, triggerTime, config, out);
status.reported = true;
stateMap.put(config.encode, state);
}
} else {
// 计算超时时间点:检查点时间 - duration
long timeoutPoint = configCollection.checkpointTime - config.duration * 60 * 1000;
if (lastEventTime < timeoutPoint) {
// 触发离线报警
AnomalyState state = getOrCreateState(config.encode);
AnomalyStatus status = state.getStatus(5);
if (!status.reported) {
// 使用超时时间点作为触发时间
String triggerTime = timeFormat.format(new Date(timeoutPoint));
reportAnomaly(5, 1, 0.0, triggerTime, config, out);
status.reported = true;
stateMap.put(config.encode, state);
}
}
}
}
}
// 更新检查点状态
lastCheckpointState.update(configCollection.checkpointTime);
}
double value = 0;
boolean valueSet = false;
// 遍历配置项进行异常检测
for (ULEParamConfig config : configs) {
if (!valueSet) {
value = "436887485805570949".equals(config.datatype) ?
data.getDouble("ontime") : data.getDouble("avg");
lastValuesMap.put(tag, value);
valueSet = true;
}
// 获取或初始化状态
AnomalyState state = getOrCreateState(config.encode);
// ========== 离线恢复检测 ==========
if (config.isonline == 1) {
AnomalyStatus status = state.getStatus(5);
if (status.reported) {
// 设备重新上线,发送恢复事件
if (!recoveredTags.contains(tag)) {
// 使用当前系统时间作为恢复时间
String recoveryTime = timeFormat.format(new Date());
reportAnomaly(5, 0, 0.0, recoveryTime, config, out);
status.reset();
recoveredTags.add(tag); // 标记该tag已恢复
System.out.println("设备 " + tag + " 恢复在线");
}
}
}
// 处理异常类型
checkConstantValueAnomaly(config, value, timeStr, state, out);
checkZeroValueAnomaly(config, value, timeStr, state, out);
checkThresholdAnomaly(config, value, timeStr, state, out);
checkSyncAnomaly(config, value, timeStr, state, configCollection, out);
// 保存状态
stateMap.put(config.encode, state);
}
}
// 恒值检测
private void checkConstantValueAnomaly(ULEParamConfig config, double currentValue,
String timeStr, AnomalyState state,
Collector<JSONObject> out) {
if (config.constantvalue != 1) return;
try {
AnomalyStatus status = state.getStatus(1);
long durationThreshold = config.duration * 60 * 1000;
Date timestamp = timeFormat.parse(timeStr);
if (status.lastValue == null) {
status.lastValue = currentValue;
status.lastChangeTime = timestamp;
return;
}
if (Math.abs(currentValue - status.lastValue) > 0.001) {
status.lastValue = currentValue;
status.lastChangeTime = timestamp;
if (status.reported) {
reportAnomaly(1, 0, currentValue, timeStr, config, out);
}
status.reset();
return;
}
long elapsed = timestamp.getTime() - status.lastChangeTime.getTime();
if (elapsed > durationThreshold) {
if (!status.reported) {
reportAnomaly(1, 1, currentValue, timeStr, config, out);
status.reported = true;
}
}
} catch (Exception e) {
System.err.println("恒值检测错误: " + config.encode + " - " + e.getMessage());
}
}
// 零值检测
private void checkZeroValueAnomaly(ULEParamConfig config, double currentValue,
String timeStr, AnomalyState state,
Collector<JSONObject> out) {
if (config.iszero != 1) return;
try {
AnomalyStatus status = state.getStatus(2);
Date timestamp = timeFormat.parse(timeStr);
boolean isZero = Math.abs(currentValue) < 0.001;
if (isZero) {
if (status.startTime == null) {
status.startTime = timestamp;
} else if (!status.reported) {
long elapsed = timestamp.getTime() - status.startTime.getTime();
if (elapsed >= config.duration * 60 * 1000) {
reportAnomaly(2, 1, currentValue, timeStr, config, out);
status.reported = true;
}
}
} else {
if (status.reported) {
reportAnomaly(2, 0, currentValue, timeStr, config, out);
status.reset();
} else if (status.startTime != null) {
status.startTime = null;
}
}
} catch (Exception e) {
System.err.println("零值检测错误: " + config.encode + " - " + e.getMessage());
}
}
// 阈值检测
private void checkThresholdAnomaly(ULEParamConfig config, double currentValue,
String timeStr, AnomalyState state,
Collector<JSONObject> out) {
try {
if (config.ishigh == 1) {
AnomalyStatus highStatus = state.getStatus(3);
processThresholdAnomaly(highStatus, currentValue, timeStr,
currentValue > config.highthreshold,
config, 3, out);
}
if (config.islow == 1) {
AnomalyStatus lowStatus = state.getStatus(4);
processThresholdAnomaly(lowStatus, currentValue, timeStr,
currentValue < config.lowthreshold,
config, 4, out);
}
} catch (Exception e) {
System.err.println("阈值检测错误: " + config.encode + " - " + e.getMessage());
}
}
private void processThresholdAnomaly(AnomalyStatus status, double currentValue,
String timeStr, boolean isAnomaly,
ULEParamConfig config, int anomalyType,
Collector<JSONObject> out) {
try {
Date timestamp = timeFormat.parse(timeStr);
if (isAnomaly) {
if (status.startTime == null) {
status.startTime = timestamp;
} else if (!status.reported) {
long elapsed = timestamp.getTime() - status.startTime.getTime();
if (elapsed >= config.duration * 60 * 1000) {
reportAnomaly(anomalyType, 1, currentValue, timeStr, config, out);
status.reported = true;
}
}
} else {
if (status.reported) {
reportAnomaly(anomalyType, 0, currentValue, timeStr, config, out);
status.reset();
} else if (status.startTime != null) {
status.startTime = null;
}
}
} catch (Exception e) {
System.err.println("阈值处理错误: " + config.encode + " - " + e.getMessage());
}
}
// 同步检测
private void checkSyncAnomaly(ULEParamConfig config, double currentValue,
String timeStr, AnomalyState state,
ConfigCollection configCollection,
Collector<JSONObject> out) {
if (config.issync != 1 || config.syncparaencode == null) return;
try {
// 日志频率控制:每分钟最多打印一次
long now = System.currentTimeMillis();
if (now - lastSyncLogTime > 60000) {
System.out.println("同步检测 - 当前配置: " + config);
lastSyncLogTime = now;
}
AnomalyStatus status = state.getStatus(6);
Date timestamp = timeFormat.parse(timeStr);
ULEParamConfig relatedConfig = configCollection.encodeToConfig.get(config.syncparaencode);
if (relatedConfig == null) {
if (now - lastSyncLogTime > 60000) {
System.out.println("同步检测: 未找到关联配置, encode=" + config.syncparaencode);
}
return;
}
String relatedTag = null;
for (Map.Entry<String, List<ULEParamConfig>> entry :
configCollection.tagToConfigs.entrySet()) {
for (ULEParamConfig cfg : entry.getValue()) {
if (cfg.encode.equals(relatedConfig.encode)) {
relatedTag = entry.getKey();
break;
}
}
if (relatedTag != null) break;
}
if (relatedTag == null) {
if (now - lastSyncLogTime > 60000) {
System.out.println("同步检测: 未找到关联Tag,关联encode=" + relatedConfig.encode);
}
return;
}
Double relatedValue = lastValuesMap.get(relatedTag);
if (relatedValue == null) {
if (now - lastSyncLogTime > 60000) {
System.out.println("同步检测: 关联值不可用, tag=" + relatedTag);
}
return;
}
if (now - lastSyncLogTime > 60000) {
System.out.println("同步检测 - 关联值: " + relatedValue);
}
System.out.println("同步检测数值: "+currentValue+ "与" + relatedValue);
boolean isAnomaly = (currentValue >= 1.0) &&
(Math.abs(relatedValue) < 0.001);
if (isAnomaly) {
if (status.startTime == null) {
status.startTime = timestamp;
} else if (!status.reported) {
long elapsed = timestamp.getTime() - status.startTime.getTime();
if (elapsed >= config.duration * 60 * 1000) {
reportAnomaly(6, 1, currentValue, timeStr, config, out);
status.reported = true;
}
}
} else {
if (status.reported) {
reportAnomaly(6, 0, currentValue, timeStr, config, out);
status.reset();
} else if (status.startTime != null) {
status.startTime = null;
}
}
} catch (Exception e) {
System.err.println("同步检测错误: " + config.encode + " - " + e.getMessage());
}
}
// 报告异常
private void reportAnomaly(int anomalyType, int statusFlag, double value,
String time, ULEParamConfig config,
Collector<JSONObject> out) {
JSONObject event = new JSONObject();
event.put("tag", config.tag);
event.put("paracode", config.encode);
event.put("abnormaltype", anomalyType);
event.put("statusflag", statusFlag);
event.put("datavalue", value);
event.put("triggertime", time);
out.collect(event);
}
@Override
public void processBroadcastElement(ConfigCollection newConfig, Context ctx,
Collector<JSONObject> out) {
BroadcastState<Void, ConfigCollection> state =
ctx.getBroadcastState(Descriptors.configStateDescriptor);
try {
// 获取旧配置
ConfigCollection oldConfig = state.get(null);
// 处理配置变更:清理不再启用的报警
if (oldConfig != null) {
for (Map.Entry<String, ULEParamConfig> entry : oldConfig.encodeToConfig.entrySet()) {
String encode = entry.getKey();
ULEParamConfig oldCfg = entry.getValue();
// 检查配置是否被删除或禁用
ULEParamConfig newCfg = newConfig.encodeToConfig.get(encode);
if (newCfg == null || !isAlarmEnabled(newCfg, oldCfg)) {
// 发送恢复事件
sendRecoveryEvents(encode, oldCfg, ctx, out);
}
}
}
// 更新广播状态
state.put(null, newConfig);
System.out.println("广播配置更新完成, 配置项: " + newConfig.encodeToConfig.size());
System.out.println("配置摘要: " + newConfig.encodeToConfig.keySet());
// 触发离线检测
for (String tag : newConfig.allTags) {
ctx.output(OFFLINE_CHECK_TAG, tag);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 检查报警是否启用
private boolean isAlarmEnabled(ULEParamConfig newCfg, ULEParamConfig oldCfg) {
// 检查所有报警类型是否被禁用
return (oldCfg.constantvalue == 1 && newCfg.constantvalue == 1) ||
(oldCfg.iszero == 1 && newCfg.iszero == 1) ||
(oldCfg.ishigh == 1 && newCfg.ishigh == 1) ||
(oldCfg.islow == 1 && newCfg.islow == 1) ||
(oldCfg.isonline == 1 && newCfg.isonline == 1) ||
(oldCfg.issync == 1 && newCfg.issync == 1);
}
// 发送恢复事件
private void sendRecoveryEvents(String encode, ULEParamConfig config,
Context ctx, Collector<JSONObject> out) {
try {
AnomalyState state = stateMap.get(encode);
if (state == null) return;
// 遍历所有可能的报警类型
for (int type = 1; type <= 6; type++) {
AnomalyStatus status = state.getStatus(type);
if (status.reported) {
JSONObject recoveryEvent = new JSONObject();
recoveryEvent.put("tag", config.tag);
recoveryEvent.put("paracode", config.encode);
recoveryEvent.put("abnormaltype", type);
recoveryEvent.put("statusflag", 0); // 恢复事件
recoveryEvent.put("datavalue", 0.0);
recoveryEvent.put("triggertime", timeFormat.format(new Date()));
out.collect(recoveryEvent);
status.reset();
}
}
// 更新状态
stateMap.put(encode, state);
} catch (Exception e) {
System.err.println("发送恢复事件失败: " + e.getMessage());
}
}
// ========== 辅助方法 ==========
private ConfigCollection getBroadcastConfig(ReadOnlyContext ctx) throws Exception {
return ctx.getBroadcastState(Descriptors.configStateDescriptor).get(null);
}
private AnomalyState getOrCreateState(String encode) throws Exception {
AnomalyState state = stateMap.get(encode);
if (state == null) {
state = new AnomalyState();
}
return state;
}
}
// 异常状态类
public static class AnomalyState implements Serializable {
private static final long serialVersionUID = 1L;
private final Map<Integer, AnomalyStatus> statusMap = new HashMap<>();
public AnomalyStatus getStatus(int type) {
return statusMap.computeIfAbsent(type, k -> new AnomalyStatus());
}
}
// 异常状态详情
public static class AnomalyStatus implements Serializable {
private static final long serialVersionUID = 1L;
public Date startTime; // 异常开始时间
public Double lastValue; // 用于恒值检测
public Date lastChangeTime; // 值最后变化时间
public boolean reported; // 是否已报告
public void reset() {
startTime = null;
lastValue = null;
lastChangeTime = null;
reported = false;
}
}
}
运行后输出为"C:\Program Files (x86)\Java\jdk1.8.0_102\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:12972,suspend=y,server=n -javaagent:C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2021.2\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath C:\Users\Administrator\AppData\Local\Temp\classpath1208442772.jar com.tongchuang.realtime.mds.ULEDataanomalyanalysis
已连接到目标 VM, 地址: ''127.0.0.1:12972',传输: '套接字''
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/F:/flink/flinkmaven/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.10.0/log4j-slf4j-impl-2.10.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/F:/flink/flinkmaven/repository/org/slf4j/slf4j-log4j12/1.7.25/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
加载配置: 30 个参数
配置加载完成,检查点时间: Sat Aug 02 10:33:47 CST 2025
广播配置更新完成, 配置项: 30
配置摘要: [EP000015, EP000014, EP000013, EP000012, EP000011, EP000010, EP100013, EP100014, EP000019, EP000018, EP100010, EP000017, EP100011, EP000016, EP100012, EP000004, EP000003, EP000002, EP000001, EP000022, EP000021, EP100007, EP000020, EP100008, EP100009, EP000009, EP000008, EP000007, EP000006, EP000005]
分钟数据流> {"times":"2025-08-02 10:33","datas":{"DA-LT-5BT0001":{"ontime":3032.701,"avg":3029.0902,"min":2967.9548,"max":3081.4817},"DA-LT-6BT008":{"ontime":204.3589,"avg":204.2984,"min":203.7112,"max":205.1441},"DA-LT-5BT0005":{"ontime":404.46,"avg":402.804,"min":401.52,"max":404.46},"DA-LT-5BT0004":{"ontime":1211.6,"avg":1211.3917,"min":1211.1,"max":1211.8},"DA-LT-6BT004":{"ontime":1150.3005,"avg":1150.2166,"min":1150.0002,"max":1150.3005},"DA-LT-6BT005":{"ontime":414.7015,"avg":415.3532,"min":414.6034,"max":416.6448},"DA-LT-5BT0008":{"ontime":187.98,"avg":185.5107,"min":183.44,"max":187.98},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":124.5375,"avg":123.8188,"min":123.0125,"max":124.575},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1194.0,"avg":1193.5833,"min":1193.0,"max":1194.0},"DA-LT-6BT001":{"ontime":169956.83,"avg":170024.9657,"min":169116.03,"max":170953.14},"DA-LT-4BT0005":{"ontime":291.9375,"avg":291.4271,"min":290.8125,"max":292.375},"DA-NY-LG2ZL-2-003":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA_DB195_RH_R_0281":{"ontime":306.25,"avg":262.9393,"min":221.92,"max":312.89},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":116559.16,"avg":116370.591,"min":115516.23,"max":117386.0}}}
同步检测 - 当前配置: ULEParamConfig(tag=DA-DB195-RH-B-0201, encode=EP000001, datatype=436887485805570949, constantvalue=1, iszero=1, isonline=1, issync=1, syncparaencode=EP000022, ishigh=1, highthreshold=1000000.0, islow=1, lowthreshold=10.0, duration=1)
分钟数据流> {"times":"2025-08-02 10:34","datas":{"DA-LT-5BT0001":{"ontime":3044.0662,"avg":3026.3841,"min":2971.6023,"max":3084.8152},"DA-LT-6BT008":{"ontime":203.7701,"avg":204.0112,"min":202.8671,"max":205.5956},"DA-LT-5BT0005":{"ontime":401.7,"avg":403.174,"min":401.64,"max":404.7},"DA-LT-6BT004":{"ontime":1150.0337,"avg":1149.9546,"min":1149.8334,"max":1150.1003},"DA-LT-5BT0004":{"ontime":1211.4,"avg":1211.385,"min":1211.1,"max":1211.5},"DA-LT-6BT005":{"ontime":416.743,"avg":418.3673,"min":416.743,"max":419.6481},"DA-LT-5BT0008":{"ontime":183.58,"avg":185.194,"min":183.58,"max":186.7},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":123.55,"avg":123.1927,"min":121.7125,"max":124.275},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1193.0,"avg":1192.7833,"min":1192.0,"max":1193.0},"DA-LT-6BT001":{"ontime":169303.2,"avg":169504.3797,"min":168052.03,"max":170460.97},"DA-NY-LG2ZL-2-003":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0005":{"ontime":291.25,"avg":291.7531,"min":290.9375,"max":292.5625},"DA_DB195_RH_R_0281":{"ontime":280.99,"avg":261.6932,"min":211.92,"max":292.48},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":115516.23,"avg":116851.9389,"min":115516.23,"max":117844.73}}}
异常检测结果> {"abnormaltype":2,"paracode":"EP000022","datavalue":0.0,"tag":"DA-NY-LG1ZL-2-001","triggertime":"2025-08-02 10:34","statusflag":1}
异常检测结果> {"abnormaltype":4,"paracode":"EP000022","datavalue":0.0,"tag":"DA-NY-LG1ZL-2-001","triggertime":"2025-08-02 10:34","statusflag":1}
异常检测结果> {"abnormaltype":4,"paracode":"EP000001","datavalue":1.0,"tag":"DA-DB195-RH-B-0201","triggertime":"2025-08-02 10:34","statusflag":1}
同步检测 - 当前配置: ULEParamConfig(tag=DA-DB195-RH-B-0201, encode=EP000001, datatype=436887485805570949, constantvalue=1, iszero=1, isonline=1, issync=1, syncparaencode=EP000022, ishigh=1, highthreshold=1000000.0, islow=1, lowthreshold=10.0, duration=1)
分钟数据流> {"times":"2025-08-02 10:35","datas":{"DA-LT-5BT0001":{"ontime":3016.8997,"avg":3037.9612,"min":2972.9126,"max":3106.898},"DA-LT-6BT008":{"ontime":205.6152,"avg":206.332,"min":205.5367,"max":207.3229},"DA-LT-5BT0005":{"ontime":404.64,"avg":403.166,"min":401.64,"max":404.7},"DA-LT-6BT004":{"ontime":1149.9669,"avg":1150.1977,"min":1149.9669,"max":1150.3005},"DA-LT-5BT0004":{"ontime":1211.1,"avg":1210.8583,"min":1210.3,"max":1211.4},"DA-LT-6BT005":{"ontime":419.707,"avg":419.6151,"min":418.2348,"max":420.2174},"DA-LT-5BT0008":{"ontime":186.72,"avg":187.9427,"min":186.46,"max":189.04},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":123.0375,"avg":122.8952,"min":121.7375,"max":124.7},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1192.0,"avg":1193.3333,"min":1192.0,"max":1195.0},"DA-LT-6BT001":{"ontime":170427.02,"avg":168471.4588,"min":166389.48,"max":170427.02},"DA-NY-LG2ZL-2-003":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0005":{"ontime":291.9375,"avg":291.9021,"min":291.1875,"max":293.5},"DA_DB195_RH_R_0281":{"ontime":248.36,"avg":252.454,"min":199.25,"max":324.52},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":117625.516,"avg":116292.7307,"min":115580.3,"max":117625.516}}}
异常检测结果> {"abnormaltype":1,"paracode":"EP000022","datavalue":0.0,"tag":"DA-NY-LG1ZL-2-001","triggertime":"2025-08-02 10:35","statusflag":1}
异常检测结果> {"abnormaltype":1,"paracode":"EP000001","datavalue":1.0,"tag":"DA-DB195-RH-B-0201","triggertime":"2025-08-02 10:35","statusflag":1}
分钟数据流> {"times":"2025-08-02 10:36","datas":{"DA-LT-5BT0001":{"ontime":3013.7334,"avg":3014.4453,"min":2960.2983,"max":3078.1865},"DA-LT-6BT008":{"ontime":206.9304,"avg":204.3282,"min":202.8279,"max":206.9304},"DA-LT-5BT0005":{"ontime":401.64,"avg":401.774,"min":400.92,"max":403.26},"DA-LT-6BT004":{"ontime":1150.3005,"avg":1150.0525,"min":1149.7,"max":1150.3005},"DA-LT-5BT0004":{"ontime":1210.5,"avg":1210.3534,"min":1210.2001,"max":1210.6},"DA-LT-6BT005":{"ontime":418.1563,"avg":416.618,"min":415.2315,"max":418.1563},"DA-LT-5BT0008":{"ontime":187.72,"avg":185.7447,"min":184.22,"max":187.76},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":123.7,"avg":123.2238,"min":122.1,"max":126.75},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1195.0,"avg":1195.2667,"min":1194.0,"max":1196.0},"DA-LT-6BT001":{"ontime":166275.03,"avg":166456.7522,"min":164900.14,"max":167463.16},"DA-NY-LG2ZL-2-003":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0005":{"ontime":292.5,"avg":293.0104,"min":292.25,"max":296.25},"DA_DB195_RH_R_0281":{"ontime":235.49,"avg":252.5028,"min":216.1,"max":284.04},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":116126.516,"avg":117106.3396,"min":116126.516,"max":118431.914}}}
同步检测 - 当前配置: ULEParamConfig(tag=DA-DB195-RH-B-0201, encode=EP000001, datatype=436887485805570949, constantvalue=1, iszero=1, isonline=1, issync=1, syncparaencode=EP000022, ishigh=1, highthreshold=1000000.0, islow=1, lowthreshold=10.0, duration=1)
分钟数据流> {"times":"2025-08-02 10:37","datas":{"DA-LT-5BT0001":{"ontime":2992.7327,"avg":3032.7967,"min":2985.2183,"max":3085.9202},"DA-LT-6BT008":{"ontime":204.6337,"avg":202.8861,"min":201.9642,"max":204.6337},"DA-LT-5BT0005":{"ontime":403.32,"avg":402.526,"min":401.16,"max":403.56},"DA-LT-6BT004":{"ontime":1149.7333,"avg":1149.3829,"min":1149.0992,"max":1149.7333},"DA-LT-5BT0004":{"ontime":1210.4,"avg":1210.09,"min":1209.6,"max":1210.5},"DA-LT-6BT005":{"ontime":415.1923,"avg":414.1267,"min":413.0331,"max":415.1923},"DA-LT-5BT0008":{"ontime":185.6,"avg":184.9953,"min":183.94,"max":186.0},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":123.95,"avg":124.3948,"min":122.8875,"max":128.475},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1196.0,"avg":1196.0,"min":1196.0,"max":1196.0},"DA-LT-6BT001":{"ontime":165732.58,"avg":166524.2458,"min":165357.02,"max":167906.17},"DA-NY-LG2ZL-2-003":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0005":{"ontime":293.25,"avg":293.3698,"min":292.0625,"max":297.375},"DA_DB195_RH_R_0281":{"ontime":261.4,"avg":260.1037,"min":234.02,"max":286.84},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":116620.195,"avg":117873.3015,"min":116620.195,"max":120679.77}}}
加载配置: 30 个参数
配置加载完成,检查点时间: Sat Aug 02 10:38:48 CST 2025
广播配置更新完成, 配置项: 30
配置摘要: [EP000015, EP000014, EP000013, EP000012, EP000011, EP000010, EP100013, EP100014, EP000019, EP000018, EP100010, EP000017, EP100011, EP000016, EP100012, EP000004, EP000003, EP000002, EP000001, EP000022, EP000021, EP100007, EP000020, EP100008, EP100009, EP000009, EP000008, EP000007, EP000006, EP000005]
分钟数据流> {"times":"2025-08-02 10:38","datas":{"DA-LT-5BT0001":{"ontime":3062.612,"avg":3035.097,"min":2982.9539,"max":3092.7915},"DA-LT-6BT008":{"ontime":202.9064,"avg":201.214,"min":198.9806,"max":203.0634},"DA-LT-5BT0005":{"ontime":403.08,"avg":403.225,"min":401.94,"max":404.1},"DA-LT-6BT004":{"ontime":1149.1993,"avg":1148.953,"min":1148.6321,"max":1149.1993},"DA-LT-5BT0004":{"ontime":1209.6,"avg":1209.3234,"min":1209.0,"max":1209.7001},"DA-LT-6BT005":{"ontime":412.9938,"avg":411.7755,"min":410.1672,"max":412.9938},"DA-LT-5BT0008":{"ontime":185.16,"avg":185.3383,"min":184.1,"max":186.86},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":123.975,"avg":123.4988,"min":119.725,"max":126.0375},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1196.0,"avg":1196.0,"min":1196.0,"max":1196.0},"DA-LT-6BT001":{"ontime":166290.2,"avg":167078.1903,"min":166165.7,"max":168463.6},"DA-NY-LG2ZL-2-003":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0005":{"ontime":292.875,"avg":292.7188,"min":289.125,"max":294.9375},"DA_DB195_RH_R_0281":{"ontime":252.57,"avg":252.0365,"min":202.7,"max":276.84},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":120679.77,"avg":120591.7229,"min":117235.55,"max":126370.65},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0}}}
同步检测 - 当前配置: ULEParamConfig(tag=DA-DB195-RH-B-0201, encode=EP000001, datatype=436887485805570949, constantvalue=1, iszero=1, isonline=1, issync=1, syncparaencode=EP000022, ishigh=1, highthreshold=1000000.0, islow=1, lowthreshold=10.0, duration=1)
分钟数据流> {"times":"2025-08-02 10:39","datas":{"DA-LT-5BT0001":{"ontime":3069.669,"avg":3049.8551,"min":2990.8599,"max":3111.9912},"DA-LT-6BT008":{"ontime":199.118,"avg":198.0587,"min":195.4866,"max":199.7265},"DA-LT-5BT0005":{"ontime":403.68,"avg":402.704,"min":400.92,"max":404.1},"DA-LT-5BT0004":{"ontime":1209.1,"avg":1208.8834,"min":1208.5,"max":1209.2001},"DA-LT-6BT004":{"ontime":1148.7322,"avg":1148.2083,"min":1147.9314,"max":1148.7322},"DA-LT-6BT005":{"ontime":410.0691,"avg":408.6263,"min":407.1443,"max":410.0691},"DA-LT-5BT0008":{"ontime":184.92,"avg":185.3113,"min":184.46,"max":186.26},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":120.0125,"avg":120.5085,"min":119.3125,"max":122.025},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1196.0,"avg":1196.2167,"min":1196.0,"max":1198.0},"DA-LT-6BT001":{"ontime":167958.2,"avg":167330.2043,"min":166480.9,"max":168000.78},"DA-NY-LG2ZL-2-003":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0005":{"ontime":289.3125,"avg":289.5396,"min":288.3125,"max":290.625},"DA_DB195_RH_R_0281":{"ontime":261.29,"avg":255.3482,"min":226.94,"max":281.97},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":126603.47,"avg":129728.6136,"min":126603.47,"max":133237.16}}}
分析同步分析未实现原因