package com.moral.api.service.impl;
|
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.moral.api.entity.CityAqi;
|
import com.moral.api.entity.CityConfigWeatherForecast;
|
import com.moral.api.entity.CityWeather;
|
import com.moral.api.entity.CityWeatherForecast;
|
import com.moral.api.entity.Forecast;
|
import com.moral.api.mapper.ForecastMapper;
|
import com.moral.api.service.CityAqiService;
|
import com.moral.api.service.CityConfigWeatherForecastService;
|
import com.moral.api.service.CityWeatherForecastService;
|
import com.moral.api.service.CityWeatherService;
|
import com.moral.api.service.ForecastService;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.moral.constant.Constants;
|
import com.moral.util.AmendUtils;
|
import com.moral.util.DateUtils;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.ObjectUtils;
|
|
import java.util.*;
|
import java.util.function.Supplier;
|
import java.util.stream.Collectors;
|
import java.util.stream.DoubleStream;
|
import java.util.stream.Stream;
|
|
/**
|
* <p>
|
* 预测小时数据 服务实现类
|
* </p>
|
*
|
* @author moral
|
* @since 2021-12-31
|
*/
|
@Service
|
public class ForecastServiceImpl extends ServiceImpl<ForecastMapper, Forecast> implements ForecastService {
|
|
@Autowired
|
private CityWeatherForecastService cityWeatherForecastService;
|
|
@Autowired
|
private CityConfigWeatherForecastService cityConfigWeatherForecastService;
|
|
@Autowired
|
private CityWeatherService cityWeatherService;
|
|
@Autowired
|
private CityAqiService cityAqiService;
|
|
@Autowired
|
private ForecastMapper forecastMapper;
|
|
private static final Map<String, Integer> weatherScore = new HashMap<>();
|
|
static {
|
weatherScore.put("晴", 100);
|
weatherScore.put("雾", 90);
|
weatherScore.put("多云", 80);
|
weatherScore.put("霾", 70);
|
weatherScore.put("阴", 60);
|
weatherScore.put("扬沙", 60);
|
weatherScore.put("浮尘", 60);
|
weatherScore.put("阵雨", 45);
|
weatherScore.put("雷阵雨", 40);
|
weatherScore.put("雷阵雨转小雨", 30);
|
weatherScore.put("阵雨转小雨", 30);
|
weatherScore.put("小雨", 20);
|
weatherScore.put("雨", 10);
|
weatherScore.put("雷阵雨转中雨", 5);
|
weatherScore.put("雷阵雨转大雨", 4);
|
weatherScore.put("中雨", 0);
|
weatherScore.put("大雨", 0);
|
weatherScore.put("暴雨", 0);
|
weatherScore.put("小雪", 0);
|
weatherScore.put("中雪", 0);
|
weatherScore.put("大雪", 0);
|
weatherScore.put("暴雪", 0);
|
weatherScore.put("雨夹雪", 0);
|
}
|
|
@Override
|
public void forecastO3() {
|
Date nextDay = DateUtils.addDays(new Date(), 1);
|
String nextTime = DateUtils.dateToDateString(nextDay, DateUtils.yyyy_MM_dd_EN);
|
//根据最近一个月历史数据来预测
|
Date start = DateUtils.addMonths(DateUtils.getDate(nextTime), -1);
|
|
//获取要预测的城市
|
QueryWrapper<CityConfigWeatherForecast> cityConfigWeatherForecastQueryWrapper = new QueryWrapper<>();
|
cityConfigWeatherForecastQueryWrapper.select("city_code")
|
.eq("is_delete", Constants.NOT_DELETE);
|
List<Object> cityCodes = cityConfigWeatherForecastService.listObjs(cityConfigWeatherForecastQueryWrapper);
|
|
|
//获取预测日逐小时气象数据
|
QueryWrapper<CityWeatherForecast> cityWeatherForecastQueryWrapper = new QueryWrapper<>();
|
cityWeatherForecastQueryWrapper.likeRight("time", nextTime)
|
.in("city_code", cityCodes);
|
List<CityWeatherForecast> forecasts = cityWeatherForecastService.list(cityWeatherForecastQueryWrapper);
|
Map<Integer, List<CityWeatherForecast>> cityForecast = forecasts.stream()
|
.collect(Collectors.groupingBy(CityWeatherForecast::getCityCode));
|
|
|
//获取近两个月历史气象数据
|
QueryWrapper<CityWeather> cityWeatherQueryWrapper = new QueryWrapper<>();
|
cityWeatherQueryWrapper.ge("time", start)
|
.in("city_code", cityCodes);
|
List<CityWeather> historyWeather = cityWeatherService.list(cityWeatherQueryWrapper);
|
Map<Integer, List<CityWeather>> cityHistoryWeather = historyWeather.stream()
|
.collect(Collectors.groupingBy(CityWeather::getCityCode));
|
|
//获取近两个月历史aqi数据
|
QueryWrapper<CityAqi> cityAqiQueryWrapper = new QueryWrapper<>();
|
cityAqiQueryWrapper.ge("time", start)
|
.in("city_code", cityCodes);
|
List<CityAqi> historyAqi = cityAqiService.list(cityAqiQueryWrapper);
|
Map<Integer, List<CityAqi>> cityHistoryAqi = historyAqi.stream()
|
.collect(Collectors.groupingBy(CityAqi::getCityCode));
|
|
//获取前后一小时map
|
Map<Date, List<Integer>> hours = DateUtils.getBeforeAndAfterHourDate(nextDay);
|
|
List<Forecast> forecastList = new ArrayList<>();
|
|
Map<String, Object> forecastMap = new HashMap<>();
|
for (Object obj : cityCodes) {
|
Integer cityCode = Integer.parseInt(obj.toString());
|
|
//预测
|
List<CityWeatherForecast> cityWeatherForecasts = Objects.isNull(cityForecast.get(cityCode))?new ArrayList<>():cityForecast.get(cityCode);
|
|
//获取城市历史气象数据
|
List<CityWeather> cityWeathers = cityHistoryWeather.get(cityCode);
|
//获取城市历史aqi数据
|
List<CityAqi> cityAqis = cityHistoryAqi.get(cityCode);
|
Map<Date, List<CityAqi>> cityAqiMap = cityAqis.stream()
|
.collect(Collectors.groupingBy(CityAqi::getTime));
|
|
Map<Date, List<Map<String, Object>>> cityHistoryMap = new HashMap<>();
|
|
for (Map.Entry<Date, List<Integer>> dateListEntry : hours.entrySet()) {
|
Date date = dateListEntry.getKey();
|
List<Integer> hourList = dateListEntry.getValue();
|
List<Map<String, Object>> hourWeatherData = new ArrayList<>();
|
for (CityWeather cityWeather : cityWeathers) {
|
Date cityWeatherTime = cityWeather.getTime();
|
int dataHour = DateUtils.getHour(cityWeatherTime);
|
if (hourList.contains(dataHour)) {
|
Map<String, Object> valueMap = JSONObject.parseObject(cityWeather.getValue(), Map.class);
|
List<CityAqi> o = cityAqiMap.get(cityWeatherTime);
|
if (!ObjectUtils.isEmpty(o)) {
|
String value = o.get(0).getValue();
|
Map<String, Object> aqiMap = JSONObject.parseObject(value, Map.class);
|
valueMap.put("O3", aqiMap.get("O3"));
|
hourWeatherData.add(valueMap);
|
}
|
}
|
}
|
cityHistoryMap.put(date, hourWeatherData);
|
}
|
|
for (CityWeatherForecast cityWeatherForecast : cityWeatherForecasts) {
|
Forecast forecast = new Forecast();
|
forecast.setCityCode(cityCode);
|
Date time = cityWeatherForecast.getTime();
|
Map<String, Object> value = JSONObject.parseObject(cityWeatherForecast.getValue(), Map.class);
|
String weather = value.get("text").toString();
|
Integer forecastScore = weatherScore.get(weather);
|
int min;
|
if (forecastScore >= 80) {
|
min = 80;
|
} else if (forecastScore >= 40) {
|
min = 40;
|
} else {
|
min = 0;
|
}
|
//气象
|
List<Map<String, Object>> weatherMaps = cityHistoryMap.get(time);
|
|
//根据天气分数筛选
|
weatherMaps.removeIf(o -> {
|
Integer historyScore = weatherScore.get(o.get("text").toString());
|
return historyScore < min;
|
});
|
int size = weatherMaps.size();
|
Double tempAvg = calculateAvg(weatherMaps, "temp");
|
Double o3Avg = calculateAvg(weatherMaps, "O3");
|
Double sum1 = calculateProduct(weatherMaps, "temp", "O3");
|
Double sum2 = calculateProduct(weatherMaps, "temp", "temp");
|
double b = (sum1 - size * tempAvg * o3Avg) / (sum2 - size * tempAvg * tempAvg);
|
double a = o3Avg - b * tempAvg;
|
double tempForecast = Double.parseDouble(value.get("temp").toString());
|
double o3Forecast = b * tempForecast + a;
|
|
forecast.setTime(cityWeatherForecast.getTime());
|
|
if (!Double.isNaN(o3Forecast)) {
|
forecastMap.put("O3", AmendUtils.sciCal(o3Forecast, 0));
|
forecast.setValue(JSONObject.toJSONString(forecastMap));
|
forecastList.add(forecast);
|
}
|
}
|
}
|
if(forecastList.size()>0){
|
forecastMapper.insertForecast(forecastList);
|
}
|
|
}
|
|
private Double calculateAvg(List<Map<String, Object>> list, String param) {
|
Supplier<Stream<Map<String, Object>>> supplier = list::stream;
|
DoubleStream doubleStream = supplier.get()
|
.flatMapToDouble(value -> {
|
String sensorValue = value.get(param).toString();
|
double paramValue = Double.parseDouble(sensorValue);
|
return DoubleStream.of(paramValue);
|
});
|
Double result = null;
|
OptionalDouble optionalDouble = doubleStream.average();
|
if (optionalDouble.isPresent()) {
|
result = optionalDouble.getAsDouble();
|
}
|
return result;
|
|
}
|
|
private Double calculateProduct(List<Map<String, Object>> list, String param1, String param2) {
|
Supplier<Stream<Map<String, Object>>> supplier = list::stream;
|
DoubleStream doubleStream = supplier.get()
|
.flatMapToDouble(value -> {
|
String sensorValue1 = value.get(param1).toString();
|
String sensorValue2 = value.get(param2).toString();
|
double paramValue1 = Double.parseDouble(sensorValue1);
|
double paramValue2 = Double.parseDouble(sensorValue2);
|
return DoubleStream.of(paramValue1 * paramValue2);
|
});
|
return doubleStream.sum();
|
}
|
|
}
|