New file |
| | |
| | | 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.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.OptionalDouble; |
| | | 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 ForecastService forecastService; |
| | | |
| | | private static 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); |
| | | |
| | | Forecast forecast = new Forecast(); |
| | | Map<String, Object> forecastMap = new HashMap<>(); |
| | | for (Object obj : cityCodes) { |
| | | Integer cityCode = Integer.parseInt(obj.toString()); |
| | | |
| | | forecast.setCityCode(cityCode); |
| | | |
| | | //预测 |
| | | List<CityWeatherForecast> cityWeatherForecasts = 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) { |
| | | 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)); |
| | | forecastService.save(forecast); |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | 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(); |
| | | } |
| | | |
| | | } |