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 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 = 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); 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
        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(); 
 | 
    } 
 | 
  
 | 
} 
 |