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.TypeHint;
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.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
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);
env.getConfig().setAutoWatermarkInterval(1000); // 设置水位线生成间隔
// 创建Kafka消费者
KafkaSource<String> kafkaConsumer = KafkaUtils.getKafkaConsumer(
"realdata_minute",
"minutedata_uledataanomalyanalysis",
OffsetsInitializer.latest()
);
// 修改Watermark策略为有界乱序
DataStreamSource<String> kafkaDS = env.fromSource(
kafkaConsumer,
WatermarkStrategy.<String>forBoundedOutOfOrderness(Duration.ofMinutes(1))
.withTimestampAssigner((event, timestamp) -> {
try {
JSONObject json = JSON.parseObject(event);
return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(json.getString("times")).getTime();
} catch (ParseException e) {
return System.currentTimeMillis(); // 使用当前时间作为回退
}
}),
"realdata_uledataanomalyanalysis"
);
kafkaDS.print("分钟数据流");
// 解析JSON并拆分每个tag的数据
SingleOutputStreamOperator<JSONObject> splitStream = kafkaDS
.map(JSON::parseObject)
.returns(TypeInformation.of(JSONObject.class)) // 显式指定返回类型
.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");
// 创建标签值数据流(修复类型擦除问题)
DataStream<Map<String, Object>> tagValueStream = splitStream
.map(json -> {
Map<String, Object> valueMap = new HashMap<>();
valueMap.put("tag", json.getString("tag"));
// 根据数据类型选择合适的值
valueMap.put("value",
"436887485805570949".equals(json.getString("datatype")) ?
json.getDouble("ontime") : json.getDouble("avg"));
return valueMap;
})
.returns(new TypeHint<Map<String, Object>>() {}) // 显式指定返回类型
.name("Tag-Value-Stream");
// 合并配置流和标签值流(修复类型擦除问题)
DataStream<Object> broadcastStream = configDataStream
.map(config -> (Object) config)
.returns(TypeInformation.of(Object.class)) // 显式指定返回类型
.union(
tagValueStream.map(tagValue -> (Object) tagValue)
.returns(TypeInformation.of(Object.class)) // 显式指定返回类型
);
// 广播合并流(使用两个状态描述符)
BroadcastStream<Object> finalBroadcastStream = broadcastStream
.broadcast(Descriptors.configStateDescriptor, Descriptors.tagValuesDescriptor);
// 按tag分组并连接广播流
KeyedStream<JSONObject, String> keyedStream = splitStream
.keyBy(json -> json.getString("tag"));
BroadcastConnectedStream<JSONObject, Object> connectedStream =
keyedStream.connect(finalBroadcastStream);
// 异常检测处理
SingleOutputStreamOperator<JSONObject> anomalyStream = connectedStream
.process(new OptimizedAnomalyDetectionFunction())
.name("Anomaly-Detection");
anomalyStream.print("异常检测结果");
// 获取侧输出流(离线检测结果)并打印
DataStream<String> offlineCheckStream = anomalyStream.getSideOutput(OptimizedAnomalyDetectionFunction.OFFLINE_CHECK_TAG);
offlineCheckStream.print("离线检测结果");
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 final MapStateDescriptor<String, Double> tagValuesDescriptor =
new MapStateDescriptor<>(
"tagValuesBroadcastState",
BasicTypeInfo.STRING_TYPE_INFO,
BasicTypeInfo.DOUBLE_TYPE_INFO);
}
// 优化后的异常检测函数
public static class OptimizedAnomalyDetectionFunction extends KeyedBroadcastProcessFunction<String, JSONObject, Object, 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 MapState<String, Long> offlineTimerState; // 离线检测定时器状态 (修复点1)
private transient SimpleDateFormat timeFormat;
// 日志频率控制
private transient long lastSyncLogTime = 0;
// 侧输出标签用于离线检测
public 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(30))
.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);
// 初始化离线检测定时器状态 (修复点1)
MapStateDescriptor<String, Long> timerDesc = new MapStateDescriptor<>(
"offlineTimerState",
BasicTypeInfo.STRING_TYPE_INFO,
BasicTypeInfo.LONG_TYPE_INFO
);
timerDesc.enableTimeToLive(ttlConfig);
offlineTimerState = getRuntimeContext().getMapState(timerDesc);
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;
}
// 清理无效状态
List<String> keysToRemove = new ArrayList<>();
for (String encode : stateMap.keys()) {
boolean found = false;
for (ULEParamConfig cfg : configs) {
if (cfg.encode.equals(encode)) {
found = true;
break;
}
}
if (!found) {
System.out.println("清理过期状态: " + encode);
keysToRemove.add(encode);
}
}
for (String encode : keysToRemove) {
stateMap.remove(encode);
}
double value = 0;
boolean valueSet = false;
// 检查该tag是否需要离线检测 (修复点2)
boolean hasOnlineConfig = false;
long minDuration = Long.MAX_VALUE;
for (ULEParamConfig config : configs) {
if (config.isonline == 1) {
hasOnlineConfig = true;
minDuration = Math.min(minDuration, config.duration);
}
}
// 管理离线检测定时器 (修复点3)
if (hasOnlineConfig) {
// 删除现有定时器
Long currentTimer = offlineTimerState.get(tag);
if (currentTimer != null) {
ctx.timerService().deleteEventTimeTimer(currentTimer);
}
// 注册新定时器(使用最小duration)
long offlineTimeout = eventTime + minDuration * 60 * 1000;
ctx.timerService().registerEventTimeTimer(offlineTimeout);
offlineTimerState.put(tag, offlineTimeout);
// 重置离线状态(数据到达表示恢复)
for (ULEParamConfig config : configs) {
if (config.isonline == 1) {
AnomalyState state = getOrCreateState(config.encode);
AnomalyStatus status = state.getStatus(6);
if (status.reported) {
// 数据恢复,发送恢复事件
reportAnomaly(6, 0, 0.0, timeStr, config, out);
status.reset();
stateMap.put(config.encode, state);
}
}
}
}
// 遍历配置项进行异常检测
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);
// 处理异常类型
checkConstantValueAnomaly(config, value, timeStr, state, out); // 1. 恒值检测
checkZeroValueAnomaly(config, value, timeStr, state, out); // 2. 零值检测
checkThresholdAnomaly(config, value, timeStr, state, out); // 3. 上阈值, 4. 下阈值
checkSyncAnomaly(config, value, timeStr, state, configCollection, ctx, out); // 5. 同步检测
// 保存状态
stateMap.put(config.encode, state);
}
}
@Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<JSONObject> out) throws Exception {
String tag = ctx.getCurrentKey();
Long lastEventTime = lastDataTimeMap.get(tag);
// 获取配置
ConfigCollection configCollection = getBroadcastConfig(ctx);
if (configCollection == null) return;
List<ULEParamConfig> configs = configCollection.tagToConfigs.get(tag);
if (configs == null) return;
// 检查所有需要离线检测的配置项 (修复点4)
boolean hasOnlineConfig = false;
for (ULEParamConfig config : configs) {
if (config.isonline == 1) {
hasOnlineConfig = true;
AnomalyState state = getOrCreateState(config.encode);
AnomalyStatus status = state.getStatus(6); // 6表示离线异常
// 检查是否超时
if (lastEventTime != null &&
(timestamp - lastEventTime) >= config.duration * 60 * 1000) {
if (!status.reported) {
String triggerTime = timeFormat.format(new Date(timestamp));
reportAnomaly(6, 1, 0.0, triggerTime, config, out);
status.reported = true;
// 输出到侧输出流
ctx.output(OFFLINE_CHECK_TAG,
String.format("离线异常: tag=%s, encode=%s, 最后数据时间=%s, 超时时间=%s",
config.tag, config.encode,
lastEventTime != null ? timeFormat.format(new Date(lastEventTime)) : "N/A",
triggerTime));
}
} else {
// 数据已恢复,重置状态
if (status.reported) {
reportAnomaly(6, 0, 0.0, timeFormat.format(new Date()), config, out);
status.reset();
}
}
stateMap.put(config.encode, state);
}
}
// 重新注册定时器(如果tag仍然存在)(修复点5)
if (hasOnlineConfig) {
long newTimeout = timestamp + TimeUnit.MINUTES.toMillis(1); // 每分钟检查一次
ctx.timerService().registerEventTimeTimer(newTimeout);
offlineTimerState.put(tag, newTimeout);
} else {
offlineTimerState.remove(tag);
}
}
// 恒值检测 - 异常类型1
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());
}
}
// 零值检测 - 异常类型2
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());
}
}
// 阈值检测 - 异常类型3(上阈值)和4(下阈值)
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());
}
}
// 同步检测 - 异常类型5
private void checkSyncAnomaly(ULEParamConfig config, double currentValue, String timeStr,
AnomalyState state, ConfigCollection configCollection,
ReadOnlyContext ctx, Collector<JSONObject> out) {
if (config.issync != 1 || config.syncparaencode == null || config.syncparaencode.isEmpty()) {
return;
}
try {
// 1. 通过encode获取关联配置
ULEParamConfig relatedConfig = configCollection.encodeToConfig.get(config.syncparaencode);
if (relatedConfig == null) {
if (System.currentTimeMillis() - lastSyncLogTime > 60000) {
System.out.println("同步检测: 未找到关联配置, encode=" + config.syncparaencode);
lastSyncLogTime = System.currentTimeMillis();
}
return;
}
// 2. 获取关联配置的tag
String relatedTag = relatedConfig.tag;
if (relatedTag == null || relatedTag.isEmpty()) {
if (System.currentTimeMillis() - lastSyncLogTime > 60000) {
System.out.println("同步检测: 关联配置没有tag, encode=" + config.syncparaencode);
lastSyncLogTime = System.currentTimeMillis();
}
return;
}
// 3. 从广播状态获取关联值
ReadOnlyBroadcastState<String, Double> tagValuesState =
ctx.getBroadcastState(Descriptors.tagValuesDescriptor);
Double relatedValue = tagValuesState.get(relatedTag);
if (relatedValue == null) {
if (System.currentTimeMillis() - lastSyncLogTime > 60000) {
System.out.println("同步检测: 关联值未初始化, tag=" + relatedTag);
lastSyncLogTime = System.currentTimeMillis();
}
return;
}
// 4. 同步检测逻辑
AnomalyStatus status = state.getStatus(5);
Date timestamp = timeFormat.parse(timeStr);
// 根据业务需求调整同步异常判断逻辑
boolean isAnomaly = (currentValue >= 0.99) && (Math.abs(relatedValue) < 0.01);
// 记录调试信息
if (System.currentTimeMillis() - lastSyncLogTime > 60000) {
System.out.printf("同步检测: %s (%.4f) vs %s (%.4f) -> %b%n",
config.tag, currentValue, relatedTag, relatedValue, isAnomaly);
lastSyncLogTime = System.currentTimeMillis();
}
// 5. 处理异常状态
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(5, 1, currentValue, timeStr, config, out);
status.reported = true;
}
}
} else {
if (status.reported) {
reportAnomaly(5, 0, currentValue, timeStr, config, out);
status.reset();
} else if (status.startTime != null) {
status.startTime = null;
}
}
} catch (ParseException e) {
System.err.println("同步检测时间解析错误: " + config.encode + " - " + e.getMessage());
} 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(Object broadcastElement, Context ctx, Collector<JSONObject> out) throws Exception {
// 处理配置更新
if (broadcastElement instanceof ConfigCollection) {
ConfigCollection newConfig = (ConfigCollection) broadcastElement;
BroadcastState<Void, ConfigCollection> configState =
ctx.getBroadcastState(Descriptors.configStateDescriptor);
// 获取旧配置
ConfigCollection oldConfig = configState.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);
}
}
}
// 更新广播状态
configState.put(null, newConfig);
System.out.println("广播配置更新完成, 配置项: " + newConfig.encodeToConfig.size());
}
// 处理标签值更新
else if (broadcastElement instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> tagValue = (Map<String, Object>) broadcastElement;
String tag = (String) tagValue.get("tag");
Double value = (Double) tagValue.get("value");
if (tag != null && value != null) {
BroadcastState<String, Double> tagValuesState =
ctx.getBroadcastState(Descriptors.tagValuesDescriptor);
tagValuesState.put(tag, value);
// System.out.println("更新标签值: " + tag + " = " + value);
}
}
}
// 检查报警是否启用
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++) { // 包括1-6所有异常类型
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:7630,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\classpath1753622630.jar com.tongchuang.realtime.mds.ULEDataanomalyanalysis
已连接到目标 VM, 地址: ''127.0.0.1:7630',传输: '套接字''
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 个参数
配置加载完成,检查点时间: Mon Aug 04 16:21:14 CST 2025
广播配置更新完成, 配置项: 30
分钟数据流> {"times":"2025-08-04 16:21","datas":{"DA-LT-5BT0001":{"ontime":3037.4404,"avg":3077.54,"min":3005.2964,"max":3135.881},"DA-LT-6BT008":{"ontime":198.4506,"avg":198.5478,"min":197.0177,"max":199.7854},"DA-LT-5BT0005":{"ontime":402.36,"avg":402.44,"min":402.3,"max":402.9},"DA-LT-5BT0004":{"ontime":1214.5,"avg":1214.445,"min":1214.0,"max":1214.8},"DA-LT-6BT004":{"ontime":1161.2792,"avg":1160.9088,"min":1160.5784,"max":1161.2792},"DA-LT-6BT005":{"ontime":414.5838,"avg":413.8847,"min":413.5434,"max":414.5838},"DA-LT-5BT0008":{"ontime":185.76,"avg":185.0393,"min":184.14,"max":186.14},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":131.2875,"avg":131.565,"min":130.6875,"max":133.4125},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1212.0,"avg":1212.1667,"min":1212.0,"max":1213.0},"DA-LT-6BT001":{"ontime":175613.78,"avg":174877.3988,"min":173555.9,"max":175931.95},"DA-LT-4BT0005":{"ontime":299.1875,"avg":299.7167,"min":299.1875,"max":301.3125},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":347.71,"avg":322.291,"min":289.95,"max":350.66},"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":125349.98,"avg":125412.9004,"min":124370.07,"max":126346.016}}}
同步检测: DA-DB195-RH-B-0201 (1.0000) vs DA-NY-LG1ZL-2-001 (0.0000) -> true
分钟数据流> {"times":"2025-08-04 16:22","datas":{"DA-LT-5BT0001":{"ontime":3041.0771,"avg":3072.9736,"min":3028.683,"max":3123.0447},"DA-LT-6BT008":{"ontime":197.0373,"avg":196.8917,"min":195.6044,"max":197.4495},"DA-LT-5BT0005":{"ontime":402.96,"avg":403.963,"min":402.96,"max":405.0},"DA-LT-5BT0004":{"ontime":1214.1,"avg":1213.68,"min":1213.2001,"max":1214.2001},"DA-LT-6BT004":{"ontime":1160.6451,"avg":1160.5345,"min":1160.445,"max":1160.6451},"DA-LT-6BT005":{"ontime":413.5827,"avg":412.9968,"min":412.0712,"max":413.5827},"DA-LT-5BT0008":{"ontime":186.12,"avg":186.4123,"min":185.64,"max":188.18},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":131.75,"avg":130.3521,"min":129.1,"max":131.75},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1212.0,"avg":1211.45,"min":1211.0,"max":1212.0},"DA-LT-6BT001":{"ontime":174958.58,"avg":174779.7565,"min":173817.05,"max":175997.95},"DA-LT-4BT0005":{"ontime":300.25,"avg":299.2271,"min":297.875,"max":300.25},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":331.25,"avg":321.6138,"min":275.13,"max":379.05},"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":126701.664,"avg":125684.668,"min":124417.31,"max":126701.664}}}
异常检测结果> {"abnormaltype":2,"paracode":"EP000022","datavalue":0.0,"tag":"DA-NY-LG1ZL-2-001","triggertime":"2025-08-04 16:22","statusflag":1}
异常检测结果> {"abnormaltype":4,"paracode":"EP000022","datavalue":0.0,"tag":"DA-NY-LG1ZL-2-001","triggertime":"2025-08-04 16:22","statusflag":1}
异常检测结果> {"abnormaltype":4,"paracode":"EP000001","datavalue":1.0,"tag":"DA-DB195-RH-B-0201","triggertime":"2025-08-04 16:22","statusflag":1}
异常检测结果> {"abnormaltype":5,"paracode":"EP000001","datavalue":1.0,"tag":"DA-DB195-RH-B-0201","triggertime":"2025-08-04 16:22","statusflag":1}
分钟数据流> {"times":"2025-08-04 16:23","datas":{"DA-LT-5BT0001":{"ontime":3044.751,"avg":3069.1905,"min":3008.8462,"max":3128.2627},"DA-LT-6BT008":{"ontime":195.6829,"avg":195.4408,"min":195.0744,"max":195.7418},"DA-LT-5BT0005":{"ontime":404.94,"avg":405.705,"min":404.94,"max":406.56},"DA-LT-5BT0004":{"ontime":1213.3,"avg":1213.6267,"min":1213.2001,"max":1213.9},"DA-LT-6BT004":{"ontime":1160.5117,"avg":1160.5178,"min":1160.445,"max":1160.5784},"DA-LT-6BT005":{"ontime":412.0712,"avg":411.3963,"min":410.6972,"max":412.0712},"DA-LT-5BT0008":{"ontime":187.58,"avg":188.0983,"min":186.38,"max":189.72},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":129.1,"avg":127.8775,"min":126.85,"max":129.4375},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1211.0,"avg":1210.1333,"min":1210.0,"max":1211.0},"DA-LT-6BT001":{"ontime":175726.77,"avg":175410.6785,"min":173584.17,"max":176879.33},"DA-LT-4BT0005":{"ontime":298.0,"avg":297.3938,"min":296.75,"max":298.4375},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":306.47,"avg":318.4022,"min":288.74,"max":349.25},"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":126455.56,"avg":127003.1363,"min":125744.39,"max":128161.19}}}
异常检测结果> {"abnormaltype":1,"paracode":"EP000022","datavalue":0.0,"tag":"DA-NY-LG1ZL-2-001","triggertime":"2025-08-04 16:23","statusflag":1}
异常检测结果> {"abnormaltype":1,"paracode":"EP000001","datavalue":1.0,"tag":"DA-DB195-RH-B-0201","triggertime":"2025-08-04 16:23","statusflag":1}
同步检测: DA-DB195-RH-B-0201 (1.0000) vs DA-NY-LG1ZL-2-001 (0.0000) -> true
分钟数据流> {"times":"2025-08-04 16:24","datas":{"DA-LT-5BT0001":{"ontime":3111.352,"avg":3073.2331,"min":3020.7065,"max":3119.5767},"DA-LT-6BT008":{"ontime":195.2314,"avg":194.6716,"min":193.4844,"max":195.4277},"DA-LT-5BT0005":{"ontime":406.56,"avg":406.781,"min":406.5,"max":407.22},"DA-LT-5BT0004":{"ontime":1213.9,"avg":1213.85,"min":1213.5,"max":1214.0},"DA-LT-6BT004":{"ontime":1160.5784,"avg":1160.2836,"min":1160.178,"max":1160.5784},"DA-LT-6BT005":{"ontime":410.7364,"avg":410.1293,"min":408.9895,"max":410.9131},"DA-LT-5BT0008":{"ontime":189.84,"avg":189.193,"min":188.48,"max":189.98},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":127.225,"avg":126.9273,"min":126.1875,"max":128.375},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1210.0,"avg":1209.7667,"min":1209.0,"max":1210.0},"DA-LT-6BT001":{"ontime":174950.36,"avg":175419.8677,"min":174526.08,"max":176501.6},"DA-LT-4BT0005":{"ontime":297.125,"avg":296.1365,"min":295.0625,"max":297.9375},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":331.64,"avg":313.9772,"min":244.04,"max":366.26},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":126926.016,"avg":127288.5532,"min":125888.73,"max":128539.445},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0}}}
分钟数据流> {"times":"2025-08-04 16:25","datas":{"DA-LT-5BT0001":{"ontime":3068.1875,"avg":3084.6569,"min":3029.6409,"max":3132.9768},"DA-LT-6BT008":{"ontime":193.4844,"avg":193.0935,"min":192.3459,"max":193.504},"DA-LT-5BT0005":{"ontime":407.16,"avg":407.241,"min":406.68,"max":407.82},"DA-LT-5BT0004":{"ontime":1213.7001,"avg":1213.3367,"min":1212.8,"max":1213.7001},"DA-LT-6BT004":{"ontime":1160.2113,"avg":1160.4494,"min":1160.2113,"max":1160.6451},"DA-LT-6BT005":{"ontime":408.9699,"avg":408.4026,"min":406.7125,"max":409.0287},"DA-LT-5BT0008":{"ontime":189.08,"avg":189.1157,"min":188.56,"max":189.66},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":126.55,"avg":125.8396,"min":124.975,"max":126.675},"DA-LT-4BT0007":{"ontime":170.1,"avg":169.9971,"min":169.9,"max":170.1},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1210.0,"avg":1210.2833,"min":1210.0,"max":1211.0},"DA-LT-6BT001":{"ontime":175928.02,"avg":175488.7758,"min":174117.22,"max":176299.47},"DA-LT-4BT0005":{"ontime":295.25,"avg":295.1146,"min":294.375,"max":295.875},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":336.0,"avg":307.7993,"min":277.32,"max":336.0},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":127632.9,"avg":127259.8896,"min":126023.78,"max":128512.48},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0}}}
同步检测: DA-DB195-RH-B-0201 (1.0000) vs DA-NY-LG1ZL-2-001 (0.0000) -> true
加载配置: 30 个参数
配置加载完成,检查点时间: Mon Aug 04 16:26:15 CST 2025
广播配置更新完成, 配置项: 30
分钟数据流> {"times":"2025-08-04 16:26","datas":{"DA-LT-5BT0001":{"ontime":3089.0852,"avg":3081.6447,"min":3023.4312,"max":3131.394},"DA-LT-6BT008":{"ontime":193.4255,"avg":190.9974,"min":190.3045,"max":193.4255},"DA-LT-5BT0005":{"ontime":407.64,"avg":407.753,"min":407.58,"max":407.94},"DA-LT-6BT004":{"ontime":1160.6451,"avg":1160.7808,"min":1160.5784,"max":1161.1123},"DA-LT-5BT0004":{"ontime":1212.8,"avg":1212.5433,"min":1212.3,"max":1212.9},"DA-LT-6BT005":{"ontime":406.6929,"avg":404.4842,"min":403.6111,"max":406.6929},"DA-LT-5BT0008":{"ontime":189.48,"avg":191.0483,"min":189.48,"max":193.24},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":125.7875,"avg":126.7077,"min":125.4,"max":128.525},"DA-LT-4BT0007":{"ontime":170.1,"avg":169.5867,"min":167.8,"max":170.4},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1211.0,"avg":1210.9833,"min":1210.0,"max":1211.0},"DA-LT-6BT001":{"ontime":173767.36,"avg":174096.6812,"min":173192.05,"max":175292.27},"DA-LT-4BT0005":{"ontime":295.1875,"avg":295.5802,"min":295.0,"max":296.3125},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":296.59,"avg":298.6618,"min":269.42,"max":327.57},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":126023.78,"avg":126936.1062,"min":126023.78,"max":128062.195},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0}}}
同步检测: DA-DB195-RH-B-0201 (1.0000) vs DA-NY-LG1ZL-2-001 (0.0000) -> true
分钟数据流> {"times":"2025-08-04 16:27","datas":{"DA-LT-5BT0001":{"ontime":3078.3193,"avg":3074.8627,"min":3028.1882,"max":3144.5798},"DA-LT-6BT008":{"ontime":190.4026,"avg":189.0279,"min":187.8116,"max":190.4026},"DA-LT-5BT0005":{"ontime":407.58,"avg":405.809,"min":404.52,"max":407.58},"DA-LT-6BT004":{"ontime":1161.1123,"avg":1161.5489,"min":1161.0455,"max":1162.1802},"DA-LT-5BT0004":{"ontime":1213.0,"avg":1212.945,"min":1212.7001,"max":1213.2001},"DA-LT-6BT005":{"ontime":403.8074,"avg":404.5788,"min":403.5326,"max":405.3777},"DA-LT-5BT0008":{"ontime":193.22,"avg":190.887,"min":187.94,"max":193.22},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":128.3625,"avg":129.4944,"min":128.3625,"max":130.7625},"DA-LT-4BT0007":{"ontime":167.9,"avg":168.3533,"min":167.0,"max":169.2},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1211.0,"avg":1210.0333,"min":1210.0,"max":1211.0},"DA-LT-6BT001":{"ontime":174390.52,"avg":173943.3158,"min":172872.81,"max":175370.92},"DA-LT-4BT0005":{"ontime":295.5625,"avg":297.4156,"min":295.5625,"max":303.3125},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":321.92,"avg":305.068,"min":263.8899,"max":346.09},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":127858.77,"avg":126108.6027,"min":124724.13,"max":127858.77},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0}}}
异常检测结果> {"abnormaltype":3,"paracode":"EP100010","datavalue":173943.3158,"tag":"DA-LT-6BT001","triggertime":"2025-08-04 16:27","statusflag":1}
异常检测结果> {"abnormaltype":3,"paracode":"EP000010","datavalue":173943.3158,"tag":"DA-LT-6BT001","triggertime":"2025-08-04 16:27","statusflag":1}
异常检测结果> {"abnormaltype":3,"paracode":"EP000002","datavalue":126108.6027,"tag":"DA-LT-4BT0001","triggertime":"2025-08-04 16:27","statusflag":1}
分钟数据流> {"times":"2025-08-04 16:28","datas":{"DA-LT-5BT0001":{"ontime":3082.3467,"avg":3070.6012,"min":3015.203,"max":3126.656},"DA-LT-6BT008":{"ontime":187.9686,"avg":188.8153,"min":187.9097,"max":190.7167},"DA-LT-5BT0005":{"ontime":404.58,"avg":405.2197,"min":404.52,"max":405.72},"DA-LT-6BT004":{"ontime":1162.1467,"avg":1162.5732,"min":1162.1467,"max":1162.9476},"DA-LT-5BT0004":{"ontime":1213.0,"avg":1212.5797,"min":1212.2001,"max":1213.0},"DA-LT-6BT005":{"ontime":404.9851,"avg":405.6479,"min":404.7496,"max":407.3603},"DA-LT-5BT0008":{"ontime":187.94,"avg":187.4739,"min":186.82,"max":187.94},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":129.2875,"avg":129.897,"min":128.9375,"max":130.5875},"DA-LT-4BT0007":{"ontime":169.1,"avg":168.7357,"min":168.4,"max":169.1},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1210.0,"avg":1209.0847,"min":1209.0,"max":1210.0},"DA-LT-6BT001":{"ontime":174846.1,"avg":174846.2295,"min":173931.02,"max":176264.19},"DA-LT-4BT0005":{"ontime":297.6875,"avg":298.3242,"min":297.5,"max":299.25},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":254.28,"avg":285.6975,"min":252.32,"max":312.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":125919.79,"avg":126324.2331,"min":125535.38,"max":128088.09}}}
同步检测: DA-DB195-RH-B-0201 (1.0000) vs DA-NY-LG1ZL-2-001 (0.0000) -> true
分钟数据流> {"times":"2025-08-04 16:29","datas":{"DA-LT-5BT0001":{"ontime":3114.428,"avg":3079.4239,"min":3031.606,"max":3132.4033},"DA-LT-6BT008":{"ontime":190.7167,"avg":191.5594,"min":190.4026,"max":193.4648},"DA-LT-5BT0005":{"ontime":405.66,"avg":405.757,"min":405.18,"max":405.96},"DA-LT-6BT004":{"ontime":1162.8809,"avg":1163.4343,"min":1162.8809,"max":1163.9487},"DA-LT-5BT0004":{"ontime":1212.2001,"avg":1211.8517,"min":1211.6,"max":1212.2001},"DA-LT-6BT005":{"ontime":407.4388,"avg":407.1944,"min":406.0255,"max":407.5762},"DA-LT-5BT0008":{"ontime":187.9,"avg":187.9337,"min":187.56,"max":189.02},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":128.9375,"avg":129.4512,"min":128.3375,"max":131.275},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1209.0,"avg":1209.0,"min":1209.0,"max":1209.0},"DA-LT-6BT001":{"ontime":174624.12,"avg":175485.3962,"min":174422.5,"max":179850.77},"DA-LT-4BT0005":{"ontime":298.4375,"avg":298.5146,"min":297.6875,"max":300.5625},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":298.83,"avg":289.549,"min":256.32,"max":324.0},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":127162.22,"avg":126424.0733,"min":125390.0,"max":127284.26},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0}}}
分钟数据流> {"times":"2025-08-04 16:30","datas":{"DA-LT-5BT0001":{"ontime":3079.0293,"avg":3082.0171,"min":3030.803,"max":3146.9097},"DA-LT-6BT008":{"ontime":191.1093,"avg":190.489,"min":190.1474,"max":191.1093},"DA-LT-5BT0005":{"ontime":405.18,"avg":404.955,"min":403.92,"max":405.48},"DA-LT-6BT004":{"ontime":1163.9487,"avg":1164.2807,"min":1163.882,"max":1164.5828},"DA-LT-5BT0004":{"ontime":1211.9,"avg":1211.845,"min":1211.6,"max":1212.1},"DA-LT-6BT005":{"ontime":406.0255,"avg":405.9211,"min":404.9851,"max":407.3014},"DA-LT-5BT0008":{"ontime":189.02,"avg":187.4583,"min":186.96,"max":189.02},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":129.0125,"avg":129.5408,"min":128.75,"max":131.6},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1209.0,"avg":1209.0,"min":1209.0,"max":1209.0},"DA-LT-6BT001":{"ontime":179878.38,"avg":183907.156,"min":179878.38,"max":186153.8},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0005":{"ontime":298.3125,"avg":299.3135,"min":298.3125,"max":301.5},"DA_DB195_RH_R_0281":{"ontime":290.75,"avg":276.7118,"min":246.3,"max":309.64},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":125779.055,"avg":125754.8013,"min":124004.805,"max":126982.71},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0}}}
同步检测: DA-DB195-RH-B-0201 (1.0000) vs DA-NY-LG1ZL-2-001 (0.0000) -> true
加载配置: 30 个参数
配置加载完成,检查点时间: Mon Aug 04 16:31:15 CST 2025
广播配置更新完成, 配置项: 30
分钟数据流> {"times":"2025-08-04 16:31","datas":{"DA-LT-5BT0001":{"ontime":3114.7764,"avg":3081.8365,"min":3019.1914,"max":3128.7803},"DA-LT-6BT008":{"ontime":190.5793,"avg":191.6599,"min":190.5793,"max":192.0319},"DA-LT-5BT0005":{"ontime":403.98,"avg":403.115,"min":402.48,"max":403.98},"DA-LT-6BT004":{"ontime":1164.6161,"avg":1165.0488,"min":1164.516,"max":1165.5171},"DA-LT-5BT0004":{"ontime":1211.6,"avg":1211.3583,"min":1210.8,"max":1211.8},"DA-LT-6BT005":{"ontime":407.2817,"avg":407.8526,"min":407.2817,"max":408.165},"DA-LT-5BT0008":{"ontime":187.1,"avg":185.9303,"min":184.26,"max":187.18},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":130.7375,"avg":131.5027,"min":130.3875,"max":132.575},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1209.0,"avg":1209.0,"min":1209.0,"max":1209.0},"DA-LT-6BT001":{"ontime":185764.62,"avg":185297.1227,"min":183230.88,"max":186811.4},"DA-LT-4BT0005":{"ontime":299.9375,"avg":300.5354,"min":299.6875,"max":301.5},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":254.66,"avg":289.7815,"min":254.31,"max":317.79},"DA-DB195-RH-B-0200":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0001":{"ontime":124901.74,"avg":125146.3463,"min":124115.77,"max":125648.84},"DA-DB195-RH-B-0201":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0}}}
异常检测结果> {"abnormaltype":1,"paracode":"EP000004","datavalue":1209.0,"tag":"DA-LT-4BT0004","triggertime":"2025-08-04 16:31","statusflag":1}
异常检测结果> {"abnormaltype":1,"paracode":"EP000018","datavalue":1209.0,"tag":"DA-LT-4BT0004","triggertime":"2025-08-04 16:31","statusflag":1}
分钟数据流> {"times":"2025-08-04 16:32","datas":{"DA-LT-5BT0001":{"ontime":3040.7458,"avg":3076.3954,"min":3035.3533,"max":3126.1702},"DA-LT-6BT008":{"ontime":191.7374,"avg":191.2954,"min":190.6971,"max":192.6207},"DA-LT-5BT0005":{"ontime":403.02,"avg":402.402,"min":401.1,"max":403.2},"DA-LT-6BT004":{"ontime":1165.4836,"avg":1165.8358,"min":1165.4503,"max":1166.2512},"DA-LT-5BT0004":{"ontime":1210.9,"avg":1210.7933,"min":1210.5,"max":1211.1},"DA-LT-6BT005":{"ontime":407.8117,"avg":406.8695,"min":405.9666,"max":407.8117},"DA-LT-5BT0008":{"ontime":184.38,"avg":184.1247,"min":183.1,"max":184.8},"DA-NY-LG1ZL-2-001":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA-LT-4BT0008":{"ontime":132.4375,"avg":131.1617,"min":129.95,"max":132.4375},"DB5701P250A00_101":{"ontime":1.0,"avg":1.0,"min":1.0,"max":1.0},"DA-LT-4BT0004":{"ontime":1209.0,"avg":1209.0,"min":1209.0,"max":1209.0},"DA-LT-6BT001":{"ontime":184554.66,"avg":184063.7695,"min":182927.33,"max":185175.73},"DA-LT-4BT0005":{"ontime":300.9375,"avg":300.9042,"min":299.75,"max":301.6875},"DA-NY-LG2ZL-2-003":{"ontime":0.0,"avg":0.0,"min":0.0,"max":0.0},"DA_DB195_RH_R_0281":{"ontime":291.06,"avg":293.2653,"min":255.49,"max":333.63},"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":125390.39,"avg":124370.5613,"min":123141.69,"max":125400.2}}}
同步检测: DA-DB195-RH-B-0201 (1.0000) vs DA-NY-LG1ZL-2-001 (0.0000) -> true
离线监测未实现,请分析原因,并生成完整修复后代码。
最新发布