package com.moral.api.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.moral.api.config.properties.SpecialCitiesProperties; import com.moral.api.entity.CityAqi; import com.moral.api.entity.CityAqiDaily; import com.moral.api.entity.CityAqiMonthly; import com.moral.api.entity.CityAqiYearly; import com.moral.api.entity.Forecast; import com.moral.api.entity.Organization; import com.moral.api.entity.SysArea; import com.moral.api.mapper.CityAqiMapper; import com.moral.api.mapper.ForecastMapper; import com.moral.api.pojo.dto.cityAQI.CityPollutionLevel; import com.moral.api.pojo.dto.cityAQI.ConcentrationAndPercent; import com.moral.api.pojo.form.aqi.AirQualityComparisonForm; import com.moral.api.pojo.vo.cityAQI.AirQualityComparisonVO; import com.moral.api.service.CityAqiDailyService; import com.moral.api.service.CityAqiMonthlyService; import com.moral.api.service.CityAqiService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.moral.api.service.CityAqiYearlyService; import com.moral.api.service.OrganizationService; import com.moral.api.service.SysAreaService; import com.moral.constant.Constants; import com.moral.constant.RedisConstants; import com.moral.pojo.AQI; import com.moral.util.AQIUtils; import com.moral.util.AmendUtils; import com.moral.util.ComprehensiveIndexUtils; import com.moral.util.DateUtils; import com.moral.util.MathUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import java.text.DecimalFormat; import java.util.*; import java.util.stream.Collectors; import java.util.stream.DoubleStream; /** *

* 城市aqi实测小时数据表 服务实现类 *

* * @author moral * @since 2021-09-28 */ @Service public class CityAqiServiceImpl extends ServiceImpl implements CityAqiService { @Autowired private CityAqiMapper cityAqiMapper; @Autowired private ForecastMapper forecastMapper; @Autowired private RedisTemplate redisTemplate; @Autowired private SysAreaService sysAreaService; @Autowired private CityAqiDailyService cityAqiDailyService; @Autowired private CityAqiMonthlyService cityAqiMonthlyService; @Autowired private CityAqiYearlyService cityAqiYearlyService; @Autowired private SpecialCitiesProperties specialCitiesProperties; @Override public List> measuredCompareForecastOfO3(Map params) { String regionCode = params.get("regionCode").toString(); String time = params.get("time").toString(); //预测数据 QueryWrapper forecastQueryWrapper = new QueryWrapper<>(); forecastQueryWrapper.select("time", "value") .eq("city_code", regionCode) .likeRight("time", time); List> forecastData = forecastMapper.selectMaps(forecastQueryWrapper); //实测数据 QueryWrapper cityAqiQueryWrapper = new QueryWrapper<>(); cityAqiQueryWrapper.select("time", "value") .eq("city_code", regionCode) .likeRight("time", time); List> measuredData = cityAqiMapper.selectMaps(cityAqiQueryWrapper); List> result = new ArrayList<>(); for (int i = 0; i < 48; i++) { Map map = new HashMap<>(); if (i % 2 == 0) { map.put("type", "预测"); Date d = DateUtils.addHours(DateUtils.getDate(time), i / 2); map.put("time", DateUtils.dateToDateString(d, DateUtils.yyyy_MM_dd_HH_EN)); for (Map forecastDatum : forecastData) { Date date = (Date) forecastDatum.get("time"); String value = forecastDatum.get("value").toString(); Map data = JSONObject.parseObject(value, Map.class); Object o3 = data.get("O3"); if (i == DateUtils.getHour(date) * 2) { if (!ObjectUtils.isEmpty(o3)) { map.put("O3", o3); } } } } else { map.put("type", "实测"); Date d = DateUtils.addHours(DateUtils.getDate(time), (i - 1) / 2); map.put("time", DateUtils.dateToDateString(d, DateUtils.yyyy_MM_dd_HH_EN)); for (Map measuredDatum : measuredData) { Date date = (Date) measuredDatum.get("time"); String value = measuredDatum.get("value").toString(); Map data = JSONObject.parseObject(value, Map.class); Object o3 = data.get("O3"); if (i == (DateUtils.getHour(date) * 2 + 1)) { if (!ObjectUtils.isEmpty(o3)) { map.put("O3", o3); } } } } result.add(map); } return result; } @Override public Map queryCityAqiByRegionCode(Integer regionCode) { Map value = (Map) redisTemplate.opsForHash().get(RedisConstants.CITY_AQI, String.valueOf(regionCode)); if (value == null) value = queryCityAqiByRegionCodeFromDB(regionCode); //如果地区码是县级市则转换到市级在进行查询 if (value == null) { String regionCodeStr = String.valueOf(regionCode); String end = regionCodeStr.substring(regionCodeStr.length() - 2, regionCodeStr.length()); if (!end.equals(00)) { regionCodeStr = regionCodeStr.substring(0, regionCodeStr.length() - 2); regionCodeStr += "00"; regionCode = Integer.parseInt(regionCodeStr); value = (Map) redisTemplate.opsForHash().get(RedisConstants.CITY_AQI, String.valueOf(regionCode)); if (value == null) value = queryCityAqiByRegionCodeFromDB(regionCode); } else { return null; } } //根据AQI计算污染等级 if (value == null || value.get("AQI") == null) return null; Integer aqi = Integer.parseInt(value.get("AQI").toString()); String category = AQIUtils.classOfPollutionByAqi(aqi); value.put("category", category); return value; } @Override public Map query24HoursAqiByRegionCode(Integer regionCode) { //查询最新一条数据,用于获取最新的时间 QueryWrapper lastDataWrapper = new QueryWrapper<>(); lastDataWrapper.eq("city_code", regionCode); lastDataWrapper.orderByDesc("time"); lastDataWrapper.last(true, "limit 1"); CityAqi cityAqi = cityAqiMapper.selectOne(lastDataWrapper); if (cityAqi == null) return null; //算出前24小时的时间点 Date endDate = cityAqi.getTime(); Date startDate = DateUtils.addHours(endDate, -23); //查询数据 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.between("time", startDate, endDate); wrapper.eq("city_code", regionCode); List cityAqis = cityAqiMapper.selectList(wrapper); //如果数据不足24小时则补全 if (cityAqis.size() != 24) { Map dateCityAqiMap = new HashMap<>(); cityAqis.forEach(value -> dateCityAqiMap.put(value.getTime(), value)); for (int i = 0; i < 24; i++) { Date date = DateUtils.addHours(startDate, i); CityAqi cityAqi1 = dateCityAqiMap.get(date); if (cityAqi1 == null) { CityAqi newCityAqi = new CityAqi(); newCityAqi.setTime(date); cityAqis.add(newCityAqi); } } //按照时间进行排序 cityAqis.sort(Comparator.comparing(CityAqi::getTime)); } //封装返回数据,map的key为yyyy-MM-dd HH:mm格式的时间,value为aqi的数值 Map result = new LinkedHashMap<>(); for (CityAqi aqi : cityAqis) { String key = DateUtils.dateToDateString(aqi.getTime(), "yyyy-MM-dd HH:mm"); String allDataJson = aqi.getValue(); if (allDataJson == null) { result.put(key, ""); continue; } Map allDataMap = JSON.parseObject(allDataJson, Map.class); Object aqiData = allDataMap.get("AQI"); if (aqiData == null) result.put(key, ""); else result.put(key, aqiData); } return result; } @Override public Map queryTodayAqiAndPollutant(Integer regionCode) { //获取今天的9点时间 Date startDate = new Date(DateUtils.getTodayTime()); Date endDate = new Date(); //查询当天数据 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.between("time", startDate, endDate); wrapper.eq("city_code", regionCode); wrapper.select("DISTINCT city_code,time,value"); List cityAqis = cityAqiMapper.selectList(wrapper); //计算平均数 Map sixParamAvg = calculate6ParamAvg(cityAqis); //计算累计aqi和首要污染物 Map result = new HashMap<>(); AQI aqi = AQIUtils.hourlyAQI(sixParamAvg); result.put("aqi", aqi.getAQIValue()); result.put("pollutant", aqi.getPrimaryPollutantNames()); //结果集添加时间 CityAqi lastCityAqi = cityAqis.get(cityAqis.size() - 1); String time = DateUtils.dateToDateString(lastCityAqi.getTime(), "HH:mm"); result.put("time", time); return result; } @Override public List> rankingDetails(Map params) { List> result = new ArrayList<>(); int regionCode = Integer.parseInt(params.get("regionCode").toString()); String type = params.get("type").toString(); String time = null; if (!ObjectUtils.isEmpty(params.get("time"))) { time = params.get("time").toString(); } String start = null; String end = null; if (!ObjectUtils.isEmpty(params.get("start")) || !ObjectUtils.isEmpty(params.get("end"))) { start = params.get("start").toString(); end = params.get("end").toString(); } String cityType = params.get("cityType").toString(); String s = String.valueOf(regionCode); //获取当前省,市code Integer curProvinceCode = Integer.parseInt(s.substring(0, 2) + "0000"); Integer curCityCode = Integer.parseInt(s.substring(0, 4) + "00"); QueryWrapper areaWrapper = new QueryWrapper<>(); List sysAreas; if ("28".equals(cityType)) { //获取2+26城市 sysAreas = specialCitiesProperties.getTwentyEightCities(); } else { if ("province".equals(cityType)) { //获取省内所有市 areaWrapper.select("area_code", "area_name").eq("parent_code", curProvinceCode); } else { //获取市内所有县区 areaWrapper.select("area_code", "area_name").eq("parent_code", curCityCode); } sysAreas = sysAreaService.list(areaWrapper); } switch (type) { case "today": result = accumulatedTodayRank(sysAreas); break; case "hour": time = new StringBuilder(time).replace(10, 11, " ").toString() + ":00:00"; result = hourRank(sysAreas, time); break; case "day": time = time + " 00:00:00"; result = dayRank(sysAreas, time); break; case "month": time = time + "-01 00:00:00"; result = monthRank(sysAreas, time); break; case "year": time = time + "-01-01 00:00:00"; result = yearRank(sysAreas, time); break; case "custom": start = start + " 00:00:00"; end = end + " :00:00"; result = customRank(sysAreas, start, end); break; default: break; } return result; } /** * @param sysAreas 所要获取城市集合 * @return 功能:今日累计排名 */ private List> accumulatedTodayRank(List sysAreas) { List regionCodes = sysAreas.stream() .map(SysArea::getAreaCode) .collect(Collectors.toList()); List> result = new ArrayList<>(); List sensors = Arrays.asList("PM2_5", "PM10", "SO2", "NO2", "CO", "O3"); Date now = new Date(); String today = DateUtils.dateToDateString(now, DateUtils.yyyy_MM_dd_EN); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.select("city_code", "value") .ge("time", today) .in("city_code", regionCodes); List> cumulativeData = cityAqiMapper.selectMaps(wrapper); //按city_code分组 Map>> data = cumulativeData.parallelStream().collect(Collectors.groupingBy(o -> Integer.parseInt(o.get("city_code").toString()))); data.forEach((cityCode, value) -> { List doubles = new ArrayList<>(); for (Map objectMap : value) { Object o = JSONObject.parseObject((String) objectMap.get("value"), Map.class).get("O3_8H"); if (!ObjectUtils.isEmpty(o)) { double v = Double.parseDouble(o.toString()); doubles.add(v); } } Map dataMap = new HashMap<>(); sensors.forEach(sensor -> { OptionalDouble optionalDouble = value.parallelStream().flatMapToDouble(v -> { Map sensorValue = JSONObject.parseObject((String) v.get("value"), Map.class); Object o = sensorValue.get(sensor); if (ObjectUtils.isEmpty(o)) { return null; } double aDouble = Double.parseDouble(o.toString()); return DoubleStream.of(aDouble); }).average(); if (optionalDouble.isPresent()) { //银行家算法修约 double sciCal = AmendUtils.sciCal(optionalDouble.getAsDouble(), 0); if ("CO".equals(sensor)) { sciCal = AmendUtils.sciCal(optionalDouble.getAsDouble(), 1); } dataMap.put(sensor, sciCal); } }); //今日累计O3_8H计算,取每小时O3——8H最大值 if (!ObjectUtils.isEmpty(doubles)) { dataMap.put("O3_8H", Collections.max(doubles)); } //今日累计aqi,首要污染物计算 Map sixParamMap = new HashMap<>(); sixParamMap.put(Constants.SENSOR_CODE_PM25, dataMap.get("PM2_5")); sixParamMap.put(Constants.SENSOR_CODE_PM10, dataMap.get("PM10")); sixParamMap.put(Constants.SENSOR_CODE_SO2, dataMap.get("SO2")); sixParamMap.put(Constants.SENSOR_CODE_NO2, dataMap.get("NO2")); sixParamMap.put(Constants.SENSOR_CODE_CO, dataMap.get("CO")); sixParamMap.put(Constants.SENSOR_CODE_O3, dataMap.get("O3")); AQI aqi = AQIUtils.dailyAQI(sixParamMap); dataMap.put("AQI", aqi.getAQIValue()); List primaryPollutantNames = aqi.getPrimaryPollutantNames(); String primaryPollutant = ""; if (!ObjectUtils.isEmpty(primaryPollutantNames)) { primaryPollutant = primaryPollutantNames.stream().map(String::valueOf).collect(Collectors.joining(",")); } dataMap.put("primaryPollutant", primaryPollutant); //今日累计综合指数计算,O3分综指用O3_8H计算 Map compositeIndexMap = new HashMap<>(dataMap); compositeIndexMap.put("O3", compositeIndexMap.get("O3_8H")); Double compositeIndex = ComprehensiveIndexUtils.dailyData(compositeIndexMap); dataMap.put("compositeIndex", compositeIndex); //城市名 for (SysArea sysArea : sysAreas) { if (cityCode.equals(sysArea.getAreaCode())) { dataMap.put("cityName", sysArea.getAreaName()); break; } } result.add(dataMap); }); return result; } /** * @param sysAreas 所要获取城市集合 * @param time 所要获取数据的时间 2021-11-04 13:00:00 * @return 功能:小时排名 */ private List> hourRank(List sysAreas, String time) { List regionCodes = sysAreas.stream() .map(SysArea::getAreaCode) .collect(Collectors.toList()); List> result = new ArrayList<>(); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.select("value") .eq("time", time) .in("city_code", regionCodes); List> hourData = cityAqiMapper.selectMaps(wrapper); for (Map hourDatum : hourData) { Map value = JSONObject.parseObject((String) hourDatum.get("value"), Map.class); List primaryPollutantNames = (List) value.get("primaryPollutant"); String primaryPollutant = ""; if (!ObjectUtils.isEmpty(primaryPollutantNames)) { primaryPollutant = primaryPollutantNames.stream().map(String::valueOf).collect(Collectors.joining(",")); } value.put("primaryPollutant", primaryPollutant); value.remove("pubtime"); value.remove("rank"); result.add(value); } return result; } /** * @param sysAreas 所要获取城市集合 * @param time 所要获取数据的时间 2021-11-04 00:00:00 * @return 功能:日排名 */ private List> dayRank(List sysAreas, String time) { List regionCodes = sysAreas.stream() .map(SysArea::getAreaCode) .collect(Collectors.toList()); List> result = new ArrayList<>(); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.select("city_code", "value") .eq("time", time) .in("city_code", regionCodes); List> dayData = cityAqiDailyService.listMaps(wrapper); for (Map dayDatum : dayData) { Map value = JSONObject.parseObject((String) dayDatum.get("value"), Map.class); List primaryPollutantNames = (List) value.get("primaryPollutant"); String primaryPollutant = ""; if (!ObjectUtils.isEmpty(primaryPollutantNames)) { primaryPollutant = primaryPollutantNames.stream().map(String::valueOf).collect(Collectors.joining(",")); } value.put("primaryPollutant", primaryPollutant); //城市名 for (SysArea sysArea : sysAreas) { if (dayDatum.get("city_code").equals(sysArea.getAreaCode())) { value.put("cityName", sysArea.getAreaName()); break; } } result.add(value); } return result; } /** * @param sysAreas 所要获取城市集合 * @param time 所要获取数据的时间 2021-11-01 00:00:00 每月1号 * @return 功能:月排名 */ private List> monthRank(List sysAreas, String time) { List regionCodes = sysAreas.stream() .map(SysArea::getAreaCode) .collect(Collectors.toList()); //需要均值计算的因子 List sensors = Arrays.asList("PM2_5", "PM10", "SO2", "NO2"); List> result = new ArrayList<>(); //如果部是本月,实时计算,其他直接从city_aqi_monthly获取 if (!time.substring(0, 7).equals(DateUtils.dateToDateString(new Date(), DateUtils.yyyy_MM_EN))) { QueryWrapper cityAqiMonthlyQueryWrapper = new QueryWrapper<>(); for (Integer regionCode : regionCodes) { cityAqiMonthlyQueryWrapper.clear(); cityAqiMonthlyQueryWrapper.select("value") .eq("city_code", regionCode) .eq("time", time); CityAqiMonthly cityAqiMonthly = cityAqiMonthlyService.getOne(cityAqiMonthlyQueryWrapper); if (cityAqiMonthly == null) { continue; } String value = cityAqiMonthly.getValue(); Map resultMap = JSONObject.parseObject(value, Map.class); //城市名 for (SysArea sysArea : sysAreas) { if (regionCode.equals(sysArea.getAreaCode())) { resultMap.put("cityName", sysArea.getAreaName()); break; } } } return result; } QueryWrapper cityAqiDailyQueryWrapper = new QueryWrapper<>(); cityAqiDailyQueryWrapper.select("city_code", "value") .ge("time", time) .in("city_code", regionCodes); List> thisMonthData = cityAqiDailyService.listMaps(cityAqiDailyQueryWrapper); //按city_code分组 Map>> thisMonthMap = thisMonthData.parallelStream() .collect(Collectors.groupingBy(o -> Integer.parseInt(o.get("city_code").toString()))); thisMonthMap.forEach((cityCode, value) -> { Map resultMap = new HashMap<>(); Map params = new HashMap<>(); List> temp = new ArrayList<>(); for (Map map : value) { Map sensorsValue = JSONObject.parseObject(map.get("value").toString(), Map.class); Map tempMap = new HashMap<>(); tempMap.put(Constants.SENSOR_CODE_CO, sensorsValue.get("CO")); tempMap.put(Constants.SENSOR_CODE_O3, sensorsValue.get("O3")); Map hashMap = new HashMap<>(); hashMap.put("value", JSONObject.toJSONString(tempMap)); temp.add(hashMap); } params.put("data", temp); //1. CO 95百分位计算并修约 Map coAvgOfWeekOrMonth = AmendUtils.getCOAvgOfWeekOrMonth(params); if (!ObjectUtils.isEmpty(coAvgOfWeekOrMonth)) { resultMap.put("CO", coAvgOfWeekOrMonth.get(Constants.SENSOR_CODE_CO)); } //2. O3 90百分位计算并修约 Map o3AvgOfWeekOrMonth = AmendUtils.getO3AvgOfWeekOrMonth(params); if (!ObjectUtils.isEmpty(o3AvgOfWeekOrMonth)) { resultMap.put("O3", o3AvgOfWeekOrMonth.get(Constants.SENSOR_CODE_O3)); } sensors.forEach(sensor -> { OptionalDouble optionalDouble = value.parallelStream().flatMapToDouble(v -> { Map sensorValue = JSONObject.parseObject((String) v.get("value"), Map.class); Object o = sensorValue.get(sensor); if (ObjectUtils.isEmpty(o)) { return null; } double aDouble = Double.parseDouble(o.toString()); return DoubleStream.of(aDouble); }).average(); if (optionalDouble.isPresent()) { //银行家算法修约 double sciCal = AmendUtils.sciCal(optionalDouble.getAsDouble(), 0); resultMap.put(sensor, sciCal); } }); //本月综指计算 Double compositeIndex = ComprehensiveIndexUtils.dailyData(resultMap); resultMap.put("compositeIndex", compositeIndex); //前端O3用O3_8H显示 resultMap.put("O3_8H", resultMap.remove("O3")); //本月综指同上月对比 Date lastMonth = DateUtils.addMonths(DateUtils.getDate(time), -1); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("value") .eq("city_code", cityCode) .eq("time", DateUtils.dateToDateString(lastMonth)); //获取上月数据 CityAqiMonthly lastCityAqiMonthly = cityAqiMonthlyService.getOne(queryWrapper); String monthContrast = ""; if (lastCityAqiMonthly != null) { Map map = JSONObject.parseObject(lastCityAqiMonthly.getValue(), Map.class); double lastCompositeIndex = Double.parseDouble(map.get("compositeIndex").toString()); DecimalFormat decimalFormat = new DecimalFormat("0.00%"); monthContrast = decimalFormat.format((compositeIndex - lastCompositeIndex) / lastCompositeIndex); } resultMap.put("monthContrast", monthContrast); //城市名 for (SysArea sysArea : sysAreas) { if (cityCode.equals(sysArea.getAreaCode())) { resultMap.put("cityName", sysArea.getAreaName()); break; } } result.add(resultMap); }); return result; } /** * @param sysAreas 所要获取城市集合 * @param time 所要获取数据的时间 2021-11-01 00:00:00 每年1月1号 * @return 功能:年排名 */ private List> yearRank(List sysAreas, String time) { List regionCodes = sysAreas.stream() .map(SysArea::getAreaCode) .collect(Collectors.toList()); //需要均值计算的因子 List sensors = Arrays.asList("PM2_5", "PM10", "SO2", "NO2"); List> result = new ArrayList<>(); //如果是本月,实时计算,其他直接从city_aqi_monthly获取 if (!time.substring(0, 4).equals(DateUtils.dateToDateString(new Date(), DateUtils.yyyy))) { QueryWrapper cityAqiYearlyQueryWrapper = new QueryWrapper<>(); for (Integer regionCode : regionCodes) { cityAqiYearlyQueryWrapper.clear(); cityAqiYearlyQueryWrapper.select("value") .eq("city_code", regionCode) .eq("time", time); CityAqiYearly cityAqiYearly = cityAqiYearlyService.getOne(cityAqiYearlyQueryWrapper); if (cityAqiYearly == null) { continue; } String value = cityAqiYearly.getValue(); Map resultMap = JSONObject.parseObject(value, Map.class); //城市名 for (SysArea sysArea : sysAreas) { if (regionCode.equals(sysArea.getAreaCode())) { resultMap.put("cityName", sysArea.getAreaName()); break; } } result.add(resultMap); } return result; } QueryWrapper cityAqiDailyQueryWrapper = new QueryWrapper<>(); cityAqiDailyQueryWrapper.select("city_code", "value") .ge("time", time) .in("city_code", regionCodes); List> thisMonthData = cityAqiDailyService.listMaps(cityAqiDailyQueryWrapper); //按city_code分组 Map>> thisYearMap = thisMonthData.parallelStream() .collect(Collectors.groupingBy(o -> Integer.parseInt(o.get("city_code").toString()))); thisYearMap.forEach((cityCode, value) -> { Map resultMap = new HashMap<>(); Map params = new HashMap<>(); List> temp = new ArrayList<>(); for (Map map : value) { Map sensorsValue = JSONObject.parseObject(map.get("value").toString(), Map.class); Map tempMap = new HashMap<>(); tempMap.put(Constants.SENSOR_CODE_CO, sensorsValue.get("CO")); tempMap.put(Constants.SENSOR_CODE_O3, sensorsValue.get("O3")); Map hashMap = new HashMap<>(); hashMap.put("value", JSONObject.toJSONString(tempMap)); temp.add(hashMap); } params.put("data", temp); //1. CO 95百分位计算并修约 Map coAvgOfWeekOrMonth = AmendUtils.getCOAvgOfWeekOrMonth(params); if (!ObjectUtils.isEmpty(coAvgOfWeekOrMonth)) { resultMap.put("CO", coAvgOfWeekOrMonth.get(Constants.SENSOR_CODE_CO)); } //2. O3 90百分位计算并修约 Map o3AvgOfWeekOrMonth = AmendUtils.getO3AvgOfWeekOrMonth(params); if (!ObjectUtils.isEmpty(o3AvgOfWeekOrMonth)) { resultMap.put("O3", o3AvgOfWeekOrMonth.get(Constants.SENSOR_CODE_O3)); } sensors.forEach(sensor -> { OptionalDouble optionalDouble = value.parallelStream().flatMapToDouble(v -> { Map sensorValue = JSONObject.parseObject((String) v.get("value"), Map.class); Object o = sensorValue.get(sensor); if (ObjectUtils.isEmpty(o)) { return null; } double aDouble = Double.parseDouble(o.toString()); return DoubleStream.of(aDouble); }).average(); if (optionalDouble.isPresent()) { //银行家算法修约 double sciCal = AmendUtils.sciCal(optionalDouble.getAsDouble(), 0); resultMap.put(sensor, sciCal); } }); //本年综指计算 Double compositeIndex = ComprehensiveIndexUtils.dailyData(resultMap); resultMap.put("compositeIndex", compositeIndex); //前端O3用O3_8H显示 resultMap.put("O3_8H", resultMap.remove("O3")); //本年综指同去年对比 String lastYear = DateUtils.getDateAddYear(time.substring(0, 4), -1); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("value") .eq("city_code", cityCode) .eq("time", lastYear); //获取去年数据 CityAqiYearly lastCityAqiYearly = cityAqiYearlyService.getOne(queryWrapper); String yearContrast = ""; if (lastCityAqiYearly != null) { Map map = JSONObject.parseObject(lastCityAqiYearly.getValue(), Map.class); double lastCompositeIndex = Double.parseDouble(map.get("compositeIndex").toString()); DecimalFormat decimalFormat = new DecimalFormat("0.00%"); yearContrast = decimalFormat.format((compositeIndex - lastCompositeIndex) / lastCompositeIndex); } resultMap.put("yearContrast", yearContrast); //城市名 for (SysArea sysArea : sysAreas) { if (cityCode.equals(sysArea.getAreaCode())) { resultMap.put("cityName", sysArea.getAreaName()); break; } } result.add(resultMap); }); return result; } /** * @param sysAreas 所要获取城市集合 * @param start 所要获取数据的开始时间,精确到日,2021-11-03 00:00:00 * @param end 所要获取数据的结束时间,精确到日,2021-11-25 00:00:00 * @return 功能:自定义排名 */ private List> customRank(List sysAreas, String start, String end) { List regionCodes = sysAreas.stream() .map(SysArea::getAreaCode) .collect(Collectors.toList()); //需要均值计算的因子 List sensors = Arrays.asList("PM2_5", "PM10", "SO2", "NO2"); List> result = new ArrayList<>(); QueryWrapper cityAqiDailyQueryWrapper = new QueryWrapper<>(); cityAqiDailyQueryWrapper.select("city_code", "value") .ge("time", start) .le("time", end) .in("city_code", regionCodes); List> thisMonthData = cityAqiDailyService.listMaps(cityAqiDailyQueryWrapper); //按city_code分组 Map>> customMap = thisMonthData.parallelStream() .collect(Collectors.groupingBy(o -> Integer.parseInt(o.get("city_code").toString()))); customMap.forEach((cityCode, value) -> { Map resultMap = new HashMap<>(); Map params = new HashMap<>(); List> temp = new ArrayList<>(); for (Map map : value) { Map sensorsValue = JSONObject.parseObject(map.get("value").toString(), Map.class); Map tempMap = new HashMap<>(); tempMap.put(Constants.SENSOR_CODE_CO, sensorsValue.get("CO")); tempMap.put(Constants.SENSOR_CODE_O3, sensorsValue.get("O3")); Map hashMap = new HashMap<>(); hashMap.put("value", JSONObject.toJSONString(tempMap)); temp.add(hashMap); } params.put("data", temp); //1. CO 95百分位计算并修约 Map coAvgOfWeekOrMonth = AmendUtils.getCOAvgOfWeekOrMonth(params); if (!ObjectUtils.isEmpty(coAvgOfWeekOrMonth)) { resultMap.put("CO", coAvgOfWeekOrMonth.get(Constants.SENSOR_CODE_CO)); } //2. O3 90百分位计算并修约 Map o3AvgOfWeekOrMonth = AmendUtils.getO3AvgOfWeekOrMonth(params); if (!ObjectUtils.isEmpty(o3AvgOfWeekOrMonth)) { resultMap.put("O3", o3AvgOfWeekOrMonth.get(Constants.SENSOR_CODE_O3)); } sensors.forEach(sensor -> { OptionalDouble optionalDouble = value.parallelStream().flatMapToDouble(v -> { Map sensorValue = JSONObject.parseObject((String) v.get("value"), Map.class); Object o = sensorValue.get(sensor); if (ObjectUtils.isEmpty(o)) { return null; } double aDouble = Double.parseDouble(o.toString()); return DoubleStream.of(aDouble); }).average(); if (optionalDouble.isPresent()) { //银行家算法修约 double sciCal = AmendUtils.sciCal(optionalDouble.getAsDouble(), 0); resultMap.put(sensor, sciCal); } }); //自定义综指计算 Double compositeIndex = ComprehensiveIndexUtils.dailyData(resultMap); resultMap.put("compositeIndex", compositeIndex); //前端O3用O3_8H显示 resultMap.put("O3_8H", resultMap.remove("O3")); //城市名 for (SysArea sysArea : sysAreas) { if (cityCode.equals(sysArea.getAreaCode())) { resultMap.put("cityName", sysArea.getAreaName()); break; } } result.add(resultMap); }); return result; } /** * @Description: 从数据库查询数据 * @Param: [regionCode] * @return: java.util.Map * @Author: 陈凯裕 * @Date: 2021/10/28 */ private Map queryCityAqiByRegionCodeFromDB(Integer regionCode) { QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("city_code", regionCode); wrapper.orderByDesc("time"); wrapper.last(true, "limit 1"); CityAqi cityAqi = cityAqiMapper.selectOne(wrapper); if (cityAqi == null) return null; String value = cityAqi.getValue(); redisTemplate.opsForHash().put(RedisConstants.CITY_AQI, regionCode, value); return JSON.parseObject(value, Map.class); } @Override public Map provincialRanking(Integer regionCode) { //结果集 Map result = new HashMap<>(); Date now = new Date(); //昨日 Date yesterday = DateUtils.dataToTimeStampTime(DateUtils.getDateOfDay(now, -1), DateUtils.yyyy_MM_dd_EN); String dateString = DateUtils.dateToDateString(yesterday, DateUtils.yyyy_MM_dd_HH_mm_ss_EN); String s = String.valueOf(regionCode); //获取省,市code Integer provinceCode = Integer.parseInt(s.substring(0, 2) + "0000"); Integer cityCode = Integer.parseInt(s.substring(0, 4) + "00"); //获取省内所有city_code QueryWrapper wrapper = new QueryWrapper<>(); wrapper.select("area_code").eq("parent_code", provinceCode); List cityCodes = sysAreaService.listObjs(wrapper); List> ranks = new ArrayList<>(); for (Object code : cityCodes) { Map rankMap = new HashMap<>(); rankMap.put("cityCode", code); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("value").eq("city_code", code).eq("time", dateString); //1.昨日数据 CityAqiDaily one = cityAqiDailyService.getOne(queryWrapper); if (!ObjectUtils.isEmpty(one)) { String value = one.getValue(); Map valueMap = JSONObject.parseObject(value, Map.class); rankMap.put("AQI", valueMap.get("AQI")); } //2.本月累计综合指数计算,截止到昨日 queryWrapper.clear(); //开始时间:本月1号,结束时间:昨日 Date start = DateUtils.addMonths(DateUtils.getFirstDayOfLastMonth(), 1); queryWrapper.select("value").eq("city_code", code).ge("time", start).le("time", yesterday); List listMonth = cityAqiDailyService.list(queryWrapper); OptionalDouble averageMonth = listMonth.parallelStream().flatMapToDouble(v -> { Map dataValue = JSONObject.parseObject(v.getValue(), Map.class); Double compositeIndex = Double.parseDouble(dataValue.get("compositeIndex").toString()); return DoubleStream.of(compositeIndex); }).average(); if (averageMonth.isPresent()) { //银行家算法修约 double compositeIndexAvgMonth = AmendUtils.sciCal(averageMonth.getAsDouble(), 2); rankMap.put("compositeIndexMonth", compositeIndexAvgMonth); } //3.本年累计综合指数计算,截止到昨日 queryWrapper.clear(); //开始时间:本年1.1号,结束时间:昨日 String yearStart = DateUtils.dateToDateString(now, DateUtils.yyyy); queryWrapper.select("value").eq("city_code", code).ge("time", yearStart).le("time", yesterday); List listYear = cityAqiDailyService.list(queryWrapper); OptionalDouble averageYear = listYear.parallelStream().flatMapToDouble(v -> { Map dataValue = JSONObject.parseObject(v.getValue(), Map.class); Double compositeIndex = Double.parseDouble(dataValue.get("compositeIndex").toString()); return DoubleStream.of(compositeIndex); }).average(); if (averageYear.isPresent()) { //银行家算法修约 double compositeIndexAvgYear = AmendUtils.sciCal(averageYear.getAsDouble(), 2); rankMap.put("compositeIndexYear", compositeIndexAvgYear); } ranks.add(rankMap); } //日排名,按aqi排序 ranks.removeIf(o -> o.get("AQI") == null); sortByField(ranks, "AQI"); //日排名结果 Map dayMap = rankByField(ranks, cityCode, "AQI", cityCodes.size()); if (ObjectUtils.isEmpty(dayMap)) { dayMap.put("rank", null); dayMap.put("size", null); } dayMap.put("AQI", dayMap.remove("value")); result.put("day", dayMap); //月排名,按累计综指排 ranks.removeIf(o -> o.get("compositeIndexMonth") == null); sortByField(ranks, "compositeIndexMonth"); //月排名结果 Map monthMap = rankByField(ranks, cityCode, "compositeIndexMonth", cityCodes.size()); if (ObjectUtils.isEmpty(monthMap)) { monthMap.put("rank", null); monthMap.put("size", null); } monthMap.put("compositeIndex", monthMap.remove("value")); result.put("month", monthMap); //年排名,按累计综指排 sortByField(ranks, "compositeIndexYear"); Map yearMap = rankByField(ranks, cityCode, "compositeIndexYear", cityCodes.size()); if (ObjectUtils.isEmpty(yearMap)) { yearMap.put("rank", null); yearMap.put("size", null); } yearMap.put("compositeIndex", yearMap.remove("value")); result.put("year", yearMap); //时间,昨日 result.put("time", DateUtils.dateToDateString(yesterday, DateUtils.yyyy_MM_dd_EN)); return result; } @Override public List queryAirQualityComparison(AirQualityComparisonForm form) { //取参 Integer regionCode = form.getRegionCode(); String regionType = form.getRegionType(); Date startDate = form.getStartDate(); Date endDate = form.getEndDate(); Date comparisonStartDate = form.getComparisonStartDate(); Date comparisonEndDate = form.getComparisonEndDate(); String dateType = form.getDateType(); //获取城市/区县 List areas = getSysAreasByRegionType(regionType, regionCode); if (ObjectUtils.isEmpty(areas)) return null; List vos = new ArrayList<>(); for (SysArea area : areas) { //获取查询时间和对比时间的6参和综合指数 Map data = getDataByTimeTypeAndRegionCode(dateType, startDate, endDate, area.getAreaCode()); Map comparisonData = getDataByTimeTypeAndRegionCode(dateType, comparisonStartDate, comparisonEndDate, area.getAreaCode()); if (ObjectUtils.isEmpty(data) || ObjectUtils.isEmpty(comparisonData)) continue; //查询优良天数以及重污染天数 CityPollutionLevel days = cityAqiDailyService.calculateDaysByTimeAndSysArea(area, startDate, endDate); CityPollutionLevel comparisonDays = cityAqiDailyService.calculateDaysByTimeAndSysArea(area, comparisonStartDate, comparisonEndDate); int fineDays = days.getExcellentWeatherDays() + days.getGoodWeatherDays(); int serverDays = days.getSeriousWeatherDays() + days.getServerWeatherDays(); int comparisonFineDays = comparisonDays.getExcellentWeatherDays() + comparisonDays.getGoodWeatherDays(); int comparisonServerDays = comparisonDays.getSeriousWeatherDays() + comparisonDays.getServerWeatherDays(); //对比6参和综合指数 Map sixParamAndComIndexResult = contrastSixParamAndComIndex(data, comparisonData); //对比优良天数以及重污染天气数 ConcentrationAndPercent fine = contrastDays(fineDays, comparisonFineDays); ConcentrationAndPercent server = contrastDays(serverDays, comparisonServerDays); //创建返回对象 AirQualityComparisonVO vo = new AirQualityComparisonVO(); vo.setFineDays(fine); vo.setServerDays(server); vo.setCO(sixParamAndComIndexResult.get("CO")); vo.setO3(sixParamAndComIndexResult.get("O3")); vo.setPM25(sixParamAndComIndexResult.get("PM2_5")); vo.setPM10(sixParamAndComIndexResult.get("PM10")); vo.setSO2(sixParamAndComIndexResult.get("SO2")); vo.setNO2(sixParamAndComIndexResult.get("NO2")); vo.setCompositeIndex(sixParamAndComIndexResult.get("compositeIndex")); vo.setCityName(area.getAreaName()); vos.add(vo); } return vos; } /** * @Description: 计算6参和综合指数对比的百分比 * @Param: [data, comparisonData] * @return: java.util.Map * @Author: 陈凯裕 * @Date: 2022/1/17 */ private Map contrastSixParamAndComIndex(Map data, Map comparisonData) { Map result = new HashMap<>(); result.put("CO", contrastParam(Double.parseDouble(data.get("CO").toString()), Double.parseDouble(comparisonData.get("CO").toString()), "CO")); result.put("NO2", contrastParam(Double.parseDouble(data.get("NO2").toString()), Double.parseDouble(comparisonData.get("NO2").toString()), "NO2")); result.put("SO2", contrastParam(Double.parseDouble(data.get("SO2").toString()), Double.parseDouble(comparisonData.get("SO2").toString()), "SO2")); result.put("O3", contrastParam(Double.parseDouble(data.get("O3").toString()), Double.parseDouble(comparisonData.get("O3").toString()), "O3")); result.put("PM2_5", contrastParam(Double.parseDouble(data.get("PM2_5").toString()), Double.parseDouble(comparisonData.get("PM2_5").toString()), "PM2_5")); result.put("PM10", contrastParam(Double.parseDouble(data.get("PM10").toString()), Double.parseDouble(comparisonData.get("PM10").toString()), "PM10")); result.put("compositeIndex", contrastParam(Double.parseDouble(data.get("compositeIndex").toString()), Double.parseDouble(comparisonData.get("compositeIndex").toString()), "compositeIndex")); return result; } /** * @Description: 计算6参和综合指数同比/环比百分比数据 * @Param: [data, comparisonData] * @return: com.moral.api.pojo.dto.cityAQI.ConcentrationAndPercent * @Author: 陈凯裕 * @Date: 2022/1/17 */ private ConcentrationAndPercent contrastParam(Double data, Double comparisonData, String sensor) { double percentD = MathUtils.division(data - comparisonData, comparisonData, 4); String percent = MathUtils.mul(percentD,100d) + "%"; ConcentrationAndPercent concentrationAndPercent = new ConcentrationAndPercent(); concentrationAndPercent.setPercent(percent); if (sensor.equals("CO")) {//CO小数点保留一位 Double CO = AmendUtils.sciCal(data, 1); concentrationAndPercent.setConcentration(CO.toString()); }else if (sensor.equals("compositeIndex")){ concentrationAndPercent.setConcentration(data.toString()); }else{ Double sensorD = AmendUtils.sciCal(data, 0); Integer sensorI = new Double(sensorD).intValue(); concentrationAndPercent.setConcentration(sensorI.toString()); } return concentrationAndPercent; } /** * @Description: 对比天数,返回天数差值 * @Param: [days, comparisonDays] * @return: com.moral.api.pojo.dto.cityAQI.ConcentrationAndPercent * @Author: 陈凯裕 * @Date: 2022/1/17 */ private ConcentrationAndPercent contrastDays(Integer days, Integer comparisonDays) { ConcentrationAndPercent concentrationAndPercent = new ConcentrationAndPercent(); concentrationAndPercent.setConcentration(days.toString()); Integer result = days - comparisonDays; concentrationAndPercent.setPercent(result.toString() + "天"); return concentrationAndPercent; } /** * @Description: 根据时间类型查询对应的6参以及综合指数,自定义时间类型用日数据做均值处理 * @Param: [comparisonType, startDate, endDate, regionCode] * @return: java.util.Map * @Author: 陈凯裕 * @Date: 2022/1/17 */ private Map getDataByTimeTypeAndRegionCode(String TimeType, Date startDate, Date endDate, Integer regionCode) { Map data; if (Constants.MONTH.equals(TimeType) && (!DateUtils.isCurrentMonth(startDate) || !DateUtils.isCurrentYear(startDate))) {//月数据处理 不包括本月 List cityAqis = cityAqiMonthlyService.getCityAqiMonthByRegionCodeAndTime(regionCode, startDate, endDate); if (ObjectUtils.isEmpty(cityAqis)) return null; data = JSON.parseObject(cityAqis.get(0).getValue(), Map.class); } else if (Constants.YEAR.equals(TimeType) && (!DateUtils.isCurrentYear(startDate))) {//年数据处理 不包括本年 List cityAqis = cityAqiYearlyService.getCityAqiYearlyByRegionCodeAndTime(regionCode, startDate, endDate); if (ObjectUtils.isEmpty(cityAqis)) return null; data = JSON.parseObject(cityAqis.get(0).getValue(), Map.class); } else {//自定义数据处理 List cityAqis = cityAqiDailyService.getCityAqiDailyByRegionCodeAndTime(regionCode, startDate, endDate); if (ObjectUtils.isEmpty(cityAqis)) return null; List newCityAqis = new ArrayList<>(); List> dailyDataMaps = new ArrayList<>(); cityAqis.forEach((value) -> { newCityAqis.add(new CityAqi(value)); dailyDataMaps.add(JSON.parseObject(value.getValue(), Map.class)); }); //计算均值 data = calculate6ParamAvg(newCityAqis); //小数点处理 data.put("CO", Double.parseDouble(data.remove(Constants.SENSOR_CODE_CO).toString())); data.put("NO2", Double.parseDouble(data.remove(Constants.SENSOR_CODE_NO2).toString())); data.put("SO2", Double.parseDouble(data.remove(Constants.SENSOR_CODE_SO2).toString())); data.put("O3", Double.parseDouble(data.remove(Constants.SENSOR_CODE_O3).toString())); data.put("PM2_5", Double.parseDouble(data.remove(Constants.SENSOR_CODE_PM25).toString())); data.put("PM10", Double.parseDouble(data.remove(Constants.SENSOR_CODE_PM10).toString())); //计算综合指数 Double compositeIndex = ComprehensiveIndexUtils.dailyData(data); data.put("compositeIndex", compositeIndex); } return data; } //按某字段排序 private void sortByField(List> list, String sortField) { list.sort((o1, o2) -> { double v1 = Double.parseDouble(o1.get(sortField).toString()); double v2 = Double.parseDouble(o2.get(sortField).toString()); if (v1 > v2) { return -1; } else if (v1 < v2) { return 1; } return 0; }); } //排名 private Map rankByField(List> list, Integer cityCode, String rankField, Integer size) { Map result = new HashMap<>(); for (int i = 0; i < list.size(); i++) { Map map = list.get(i); if (cityCode == (int) map.get("cityCode")) { int rank = i + 1; result.put("rank", rank); result.put("size", size); Object value = map.get(rankField); result.put("value", value); break; } } return result; } /** * @Description: 根据类型和地区码获取所有的城市或者区县 * @Param: [regionType, regionCode] * @return: java.util.List * @Author: 陈凯裕 * @Date: 2022/1/14 */ private List getSysAreasByRegionType(String regionType, Integer regionCode) { List areas; if (regionType.equals(Constants.TWENTY_EIGHT_CITIES)) { SpecialCitiesProperties properties = new SpecialCitiesProperties(); areas = properties.getTwentyEightCities(); } else { areas = sysAreaService.getChildren(regionCode); } return areas; } /** * @Description: 计算6参平均值 * @Param: [cityAqiList] * @return: java.util.Map * 返回值key为sensorCode,value为值 * @Author: 陈凯裕 * @Date: 2021/11/2 */ private Map calculate6ParamAvg(List cityAqiList) { Double co = calculateSensorAvg(cityAqiList, "CO"); Double pm2_5 = calculateSensorAvg(cityAqiList, "PM2_5"); Double pm10 = calculateSensorAvg(cityAqiList, "PM10"); Double so2 = calculateSensorAvg(cityAqiList, "SO2"); Double no2 = calculateSensorAvg(cityAqiList, "NO2"); Double o3 = calculateSensorAvg(cityAqiList, "O3"); Map result = new HashMap<>(); result.put(Constants.SENSOR_CODE_CO, co); result.put(Constants.SENSOR_CODE_NO2, no2); result.put(Constants.SENSOR_CODE_SO2, so2); result.put(Constants.SENSOR_CODE_O3, o3); result.put(Constants.SENSOR_CODE_PM25, pm2_5); result.put(Constants.SENSOR_CODE_PM10, pm10); return result; } /** * @Description: 计算因子的平均值 * @Param: [cityAqiList, sensor] * ,sensor是要计算的因子名称 * @return: java.lang.Double * @Author: 陈凯裕 * @Date: 2021/11/2 */ private Double calculateSensorAvg(List cityAqiList, String sensor) { Double sum = 0d; int num = 0; for (CityAqi cityAqi : cityAqiList) { String value = cityAqi.getValue(); if (value == null) continue; Map valueMap = JSON.parseObject(value, Map.class); Object sensorValueObject = valueMap.get(sensor); if (sensorValueObject == null) continue; Double sensorValue = Double.valueOf(sensorValueObject.toString()); sum = MathUtils.add(sum, sensorValue); num++; } if (num == 0) return null; Double avg = MathUtils.division(sum, num, 2); return avg; } }