package com.iailab.module.model.mcs.pre.service.impl;
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.iailab.framework.common.pojo.PageResult;
|
import com.iailab.framework.common.service.impl.BaseServiceImpl;
|
import com.iailab.framework.common.util.date.DateUtils;
|
import com.iailab.module.data.api.point.DataPointApi;
|
import com.iailab.module.data.api.point.dto.ApiPointDTO;
|
import com.iailab.module.data.api.point.dto.ApiPointValueDTO;
|
import com.iailab.module.data.api.point.dto.ApiPointValueQueryDTO;
|
import com.iailab.module.data.enums.DataPointFreqEnum;
|
import com.iailab.module.model.api.mcs.dto.MmPredictInfluenceFactorHandleReqVO;
|
import com.iailab.module.model.mcs.pre.dao.MmPredictInfluenceFactorDao;
|
import com.iailab.module.model.mcs.pre.entity.MmPredictInfluenceFactorConfigEntity;
|
import com.iailab.module.model.mcs.pre.entity.MmPredictInfluenceFactorResultEntity;
|
import com.iailab.module.model.mcs.pre.enums.InfluenceFactorPatternEnum;
|
import com.iailab.module.model.mcs.pre.service.MmItemResultJsonService;
|
import com.iailab.module.model.mcs.pre.service.MmPredictInfluenceFactorResultService;
|
import com.iailab.module.model.mcs.pre.service.MmPredictInfluenceFactorService;
|
import com.iailab.module.model.mcs.pre.vo.MmPredictInfluenceFactorConfigVO;
|
import com.iailab.module.model.mcs.pre.vo.MmPredictInfluenceFactorHandleVO;
|
import com.iailab.module.model.mcs.pre.vo.MmPredictInfluenceFactorPageReqVO;
|
import com.iailab.module.model.mcs.pre.vo.MmPredictInfluenceFactorVO;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.CollectionUtils;
|
|
import java.math.BigDecimal;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
@Slf4j
|
@Service
|
public class MmPredictInfluenceFactorServiceImpl extends BaseServiceImpl<MmPredictInfluenceFactorDao, MmPredictInfluenceFactorConfigEntity> implements MmPredictInfluenceFactorService {
|
|
@Autowired
|
private MmItemResultJsonService mmItemResultJsonService;
|
|
@Autowired
|
private DataPointApi dataPointApi;
|
|
@Autowired
|
private MmPredictInfluenceFactorResultService influenceFactorResultService;
|
|
@Override
|
public PageResult<MmPredictInfluenceFactorConfigVO> page(MmPredictInfluenceFactorPageReqVO params) {
|
IPage<MmPredictInfluenceFactorConfigVO> page = baseDao.selectPage(params);
|
return new PageResult<>(page.getRecords(), page.getTotal());
|
}
|
|
@Override
|
public MmPredictInfluenceFactorConfigVO getInfo(String id) {
|
return baseDao.getInfo(id);
|
}
|
|
@Override
|
public void create(MmPredictInfluenceFactorConfigVO vo) {
|
MmPredictInfluenceFactorConfigEntity entity = new MmPredictInfluenceFactorConfigEntity();
|
String configId = UUID.randomUUID().toString();
|
entity.setId(configId);
|
entity.setOutputId(vo.getOutputId());
|
entity.setPattern(vo.getPattern());
|
entity.setIsEnable(vo.getIsEnable());
|
entity.setCreateTime(new Date());
|
baseDao.insert(entity);
|
|
// 添加因素
|
if (CollectionUtils.isEmpty(vo.getInfluenceFactors())) {
|
return;
|
}
|
List<MmPredictInfluenceFactorVO> influenceFactors = vo.getInfluenceFactors();
|
influenceFactors.forEach(e -> {
|
e.setId(UUID.randomUUID().toString());
|
e.setConfigId(configId);
|
});
|
|
baseDao.insertInfluenceFactor(influenceFactors);
|
}
|
|
@Override
|
public void update(MmPredictInfluenceFactorConfigVO vo) {
|
MmPredictInfluenceFactorConfigEntity entity = new MmPredictInfluenceFactorConfigEntity();
|
entity.setId(vo.getId());
|
entity.setOutputId(vo.getOutputId());
|
entity.setPattern(vo.getPattern());
|
entity.setIsEnable(vo.getIsEnable());
|
baseDao.updateById(entity);
|
|
// 删除因素
|
baseDao.deleteInfluenceFactor(vo.getId());
|
// 添加因素
|
if (CollectionUtils.isEmpty(vo.getInfluenceFactors())) {
|
return;
|
}
|
List<MmPredictInfluenceFactorVO> influenceFactors = vo.getInfluenceFactors();
|
influenceFactors.forEach(e -> {
|
if (StringUtils.isBlank(e.getId())) {
|
e.setId(UUID.randomUUID().toString());
|
}
|
e.setConfigId(vo.getId());
|
});
|
|
baseDao.insertInfluenceFactor(influenceFactors);
|
|
}
|
|
@Override
|
public void delete(String id) {
|
// 删除因素
|
baseDao.deleteById(id);
|
}
|
|
@Override
|
public void influenceFactorHandle(MmPredictInfluenceFactorHandleReqVO reqVO) {
|
// 影响时间
|
Date influenceTime = new Date(reqVO.getInfluenceTime());
|
// 判断影响时间一定是历史时间
|
if (influenceTime.after(new Date())) {
|
log.info("计算影响因素失败:影响时间大于当前时间");
|
return;
|
}
|
// 查询所有影响因素
|
Map<String, Object> params = new HashMap<>();
|
params.put("isEnable",1);
|
List<MmPredictInfluenceFactorHandleVO> influenceFactorConfigs = baseDao.selectList(params);
|
|
// 根据统计方式分组
|
Map<String, List<MmPredictInfluenceFactorHandleVO>> patternMap = influenceFactorConfigs.stream().collect(Collectors.groupingBy(MmPredictInfluenceFactorHandleVO::getPattern));
|
List<MmPredictInfluenceFactorResultEntity> resultList = new ArrayList<>(influenceFactorConfigs.size());
|
for (Map.Entry<String, List<MmPredictInfluenceFactorHandleVO>> entry : patternMap.entrySet()) {
|
List<MmPredictInfluenceFactorHandleVO> influenceFactors = entry.getValue();
|
// 缓存 因素预测项id-结果,相同因素预测项id只用计算一次
|
HashMap<String,Double> values = new HashMap<>();
|
switch (InfluenceFactorPatternEnum.fromCode(entry.getKey())) {
|
case ACCUMULATE:
|
for (MmPredictInfluenceFactorHandleVO influenceFactor : influenceFactors) {
|
Double value = influenceFactorAccumulateCalculate(influenceFactor, values, influenceTime);
|
if (value == null) {
|
continue;
|
}
|
MmPredictInfluenceFactorResultEntity resultEntity = new MmPredictInfluenceFactorResultEntity();
|
resultEntity.setFactorId(influenceFactor.getId());
|
resultEntity.setTime(influenceTime);
|
resultEntity.setValue(value);
|
resultList.add(resultEntity);
|
}
|
break;
|
case ACCURACY:
|
for (MmPredictInfluenceFactorHandleVO influenceFactor : influenceFactors) {
|
Double value = influenceFactorAccuracyCalculate(influenceFactor, values, influenceTime);
|
if (value == null) {
|
continue;
|
}
|
MmPredictInfluenceFactorResultEntity resultEntity = new MmPredictInfluenceFactorResultEntity();
|
resultEntity.setFactorId(influenceFactor.getId());
|
resultEntity.setTime(influenceTime);
|
resultEntity.setValue(value);
|
resultList.add(resultEntity);
|
}
|
break;
|
default:
|
}
|
}
|
if (CollectionUtils.isEmpty(resultList)) {
|
return;
|
}
|
influenceFactorResultService.insert(resultList);
|
|
}
|
|
@Override
|
public List<MmPredictInfluenceFactorVO> getListByOutId(String outId) {
|
List<MmPredictInfluenceFactorVO> list = baseDao.getListByOutId(outId);
|
return list;
|
}
|
|
private Double influenceFactorAccuracyCalculate(MmPredictInfluenceFactorHandleVO influenceFactor, HashMap<String, Double> values, Date influenceTime) {
|
if (values.containsKey(influenceFactor.getFactorOutputId())) {
|
return values.get(influenceFactor.getFactorOutputId());
|
}
|
// 根据 预测长度 和 预测粒度 推算预测时间
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(influenceTime);
|
calendar.add(Calendar.SECOND,-1 * influenceFactor.getPredictlength() * influenceFactor.getGranularity());
|
Date predictTime = calendar.getTime();
|
// 获取result_json,预测历史数据
|
List<Object[]> predictData = mmItemResultJsonService.getData(influenceFactor.getFactorOutputId(), predictTime, DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
|
if (CollectionUtils.isEmpty(predictData)) {
|
return null;
|
}
|
// 获取真实测点历史值
|
ApiPointValueQueryDTO queryDTO = new ApiPointValueQueryDTO();
|
ApiPointDTO point = dataPointApi.getInfoById(influenceFactor.getPointid());
|
queryDTO.setPointNo(point.getPointNo());
|
queryDTO.setStart(predictTime);
|
queryDTO.setEnd(influenceTime);
|
List<ApiPointValueDTO> dataList = dataPointApi.queryPointHistoryValue(queryDTO);
|
if (CollectionUtils.isEmpty(dataList)) {
|
return null;
|
}
|
dataList = completionData(influenceFactor.getPredictlength(),dataList,predictTime,influenceTime,point.getMinfreqid());
|
Map<String, Double> dataMap = dataList.stream().collect(Collectors.toMap(e -> DateUtils.format(e.getT(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND), ApiPointValueDTO::getV, (e1, e2) -> e1));
|
// 计算精确度误差
|
int sum = 0;
|
for (int i = 0; i < predictData.size(); i++) {
|
Object[] objects = predictData.get(i);
|
if (dataMap.containsKey(objects[0].toString())) {
|
double abs = Math.abs(new BigDecimal(objects[1].toString()).subtract(BigDecimal.valueOf(dataMap.get(objects[0].toString()))).doubleValue());
|
if (abs > influenceFactor.getDeviationValue()) {
|
sum++;
|
}
|
}
|
}
|
|
double value = BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(predictData.size()), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
|
|
values.put(influenceFactor.getFactorOutputId(),value);
|
return value;
|
}
|
|
private Double influenceFactorAccumulateCalculate(MmPredictInfluenceFactorHandleVO influenceFactor, HashMap<String, Double> values,Date influenceTime) {
|
if (values.containsKey(influenceFactor.getFactorOutputId())) {
|
return values.get(influenceFactor.getFactorOutputId());
|
}
|
// 根据 预测长度 和 预测粒度 推算预测时间
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(influenceTime);
|
calendar.add(Calendar.SECOND,-1 * influenceFactor.getPredictlength() * influenceFactor.getGranularity());
|
Date predictTime = calendar.getTime();
|
// 获取result_json,预测历史数据
|
double[] predictData = mmItemResultJsonService.getSimpleData(influenceFactor.getFactorOutputId(), predictTime, influenceFactor.getPredictlength());
|
if (predictData == null || predictData.length == 0) {
|
return null;
|
}
|
// 获取真实测点历史值
|
ApiPointValueQueryDTO queryDTO = new ApiPointValueQueryDTO();
|
ApiPointDTO point = dataPointApi.getInfoById(influenceFactor.getPointid());
|
queryDTO.setPointNo(point.getPointNo());
|
queryDTO.setStart(predictTime);
|
queryDTO.setEnd(influenceTime);
|
List<ApiPointValueDTO> dataList = dataPointApi.queryPointHistoryValue(queryDTO);
|
if (CollectionUtils.isEmpty(dataList)) {
|
return null;
|
}
|
dataList = completionData(influenceFactor.getPredictlength(),dataList,predictTime,influenceTime,point.getMinfreqid());
|
// 计算累计量误差
|
double value = Math.abs(dataList.stream().mapToDouble(ApiPointValueDTO::getV).sum() - Arrays.stream(predictData).sum());
|
|
values.put(influenceFactor.getFactorOutputId(),value);
|
return value;
|
}
|
|
private List<ApiPointValueDTO> completionData(int length, List<ApiPointValueDTO> dataList, Date startTime, Date endTime, String minfreqid) {
|
if (CollectionUtils.isEmpty(dataList) || length == dataList.size()) {
|
return dataList;
|
} else if (length < dataList.size()) {
|
return dataList.subList(dataList.size() - length, dataList.size());
|
}
|
|
List<ApiPointValueDTO> result = new ArrayList<>();
|
long start = startTime.getTime();
|
long end = endTime.getTime();
|
long oneMin = 1000L * DataPointFreqEnum.getEumByCode(minfreqid).getValue();
|
long mins = (end - start) / oneMin;
|
|
//找出缺少项
|
Map<Long, Double> sourceDataMap = new HashMap<>(dataList.size());
|
for (ApiPointValueDTO pv : dataList) {
|
sourceDataMap.put(pv.getT().getTime(), pv.getV());
|
}
|
|
Map<Long, Double> dataMap = new LinkedHashMap<>();
|
for (int i = 0; i < mins; i++) {
|
Long key = start + oneMin * i;
|
Double value = sourceDataMap.get(key);
|
dataMap.put(key, value);
|
}
|
|
//补充缺少项
|
int k = 0;
|
Map.Entry<Long, Double> lastItem = null;
|
for (Map.Entry<Long, Double> item : dataMap.entrySet()) {
|
if (k == 0 && item.getValue() == null) {
|
item.setValue(getFirstValue(dataMap));
|
} else if (item.getValue() == null) {
|
item.setValue(lastItem.getValue());
|
}
|
k++;
|
lastItem = item;
|
|
ApiPointValueDTO dataEntity = new ApiPointValueDTO();
|
dataEntity.setT(new Date(item.getKey()));
|
dataEntity.setV(item.getValue());
|
result.add(dataEntity);
|
}
|
return result;
|
}
|
|
private Double getFirstValue(Map<Long, Double> dataMap) {
|
for (Map.Entry<Long, Double> item : dataMap.entrySet()) {
|
if (item.getValue() != null) {
|
return item.getValue();
|
}
|
}
|
return 0.0;
|
}
|
}
|