CheckDataRecode.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package com.jiayue.biz.service.impl;
  2. import com.jiayue.biz.domain.FakeDataRecord;
  3. import lombok.Data;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.joda.time.DateTime;
  6. import org.joda.time.Minutes;
  7. import java.lang.reflect.Field;
  8. import java.math.BigDecimal;
  9. import java.text.ParseException;
  10. import java.text.SimpleDateFormat;
  11. import java.util.*;
  12. import java.util.stream.Collectors;
  13. /**
  14. * 为审核数据的合理性提供历史数据
  15. *
  16. * @author 修唯xiuwei
  17. * @version 3.0
  18. */
  19. @Data
  20. @Slf4j
  21. public class CheckDataRecode {
  22. /***
  23. * 原始值
  24. */
  25. private BigDecimal originalVal;
  26. /***
  27. * 使用值
  28. */
  29. private BigDecimal usedVal;
  30. /**
  31. * 死值开始时间
  32. */
  33. private DateTime deadDataStartTime = DateTime.now();
  34. /**
  35. * 该数据的获取时间
  36. */
  37. private DateTime time;
  38. public static Map<String, Object> map = new HashMap<>();
  39. public List<Map<String, Object>> checkValue(List<Map<String, Object>> allData, String type) {
  40. List<Map<String, Object>> filterData = new ArrayList<>();
  41. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
  42. if (type.equals("rld") || type.equals("station") || type.equals("dat")) {
  43. simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  44. }
  45. if (type.equals("sld")) {
  46. simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmm");
  47. }
  48. try {
  49. for (Map<String, Object> map : allData) {
  50. StringBuilder abnormalType = new StringBuilder();
  51. Long date;
  52. try {
  53. date = simpleDateFormat.parse(map.get("time").toString()).getTime();
  54. } catch (ParseException e) {
  55. date = Long.parseLong(map.get("time").toString());
  56. }
  57. Long time = date;
  58. map.forEach((key, value) -> {
  59. //风速
  60. if (key.contains("ws")) {
  61. int max;
  62. int min;
  63. int change;
  64. if (key.contains("Sta") || key.contains("sta")) {
  65. max = 6;
  66. min = 0;
  67. change = 1;
  68. } else {
  69. max = 40;
  70. min = 0;
  71. change = 20;
  72. }
  73. if (!check(value, max, min, change, key, time).equals("")) {
  74. if (!abnormalType.toString().equals("")) {
  75. abnormalType.append(",");
  76. }
  77. abnormalType.append(check(value, max, min, change, key, time));
  78. }
  79. }
  80. //湿度
  81. if (key.contains("rh")) {
  82. int max;
  83. int min;
  84. int change;
  85. if (key.contains("Sta") || key.contains("sta")) {
  86. max = 6;
  87. min = 0;
  88. change = 1;
  89. } else {
  90. max = 100;
  91. min = 0;
  92. change = 40;
  93. }
  94. if (!check(value, max, min, change, key, time).equals("")) {
  95. if (!abnormalType.toString().equals("")) {
  96. abnormalType.append(",");
  97. }
  98. abnormalType.append(check(value, max, min, change, key, time));
  99. }
  100. }
  101. //温度
  102. if (key.equals("tMax") || key.equals("tAve") || key.equals("tInst") || key.equals("tSta") || key.equals("t_max") || key.equals("t_ave") || key.equals("t_inst") || key.equals("t_sta")) {
  103. int max;
  104. int min;
  105. int change;
  106. if (key.contains("Sta") || key.contains("sta")) {
  107. max = 6;
  108. min = 0;
  109. change = 1;
  110. } else {
  111. max = 50;
  112. min = -50;
  113. change = 10;
  114. }
  115. if (!check(value, max, min, change, key, time).equals("")) {
  116. if (!abnormalType.toString().equals("")) {
  117. abnormalType.append(",");
  118. }
  119. abnormalType.append(check(value, max, min, change, key, time));
  120. }
  121. }
  122. //气压
  123. if (key.contains("pa") && !key.equals("parent_id")) {
  124. int max;
  125. int min;
  126. int change;
  127. if (key.contains("Sta") || key.contains("sta")) {
  128. max = 6;
  129. min = 0;
  130. change = 1;
  131. } else {
  132. max = 1200;
  133. min = 800;
  134. change = 5;
  135. }
  136. //气压低于200被认为是kpa 转hpa
  137. if (new BigDecimal(value.toString()).compareTo(new BigDecimal(200)) < 0) {
  138. value = new BigDecimal(value.toString()).multiply(new BigDecimal(10)).toString();
  139. }
  140. if (!check(value, max, min, change, key, time).equals("")) {
  141. if (!abnormalType.toString().equals("")) {
  142. abnormalType.append(",");
  143. }
  144. abnormalType.append(check(value, max, min, change, key, time));
  145. }
  146. }
  147. });
  148. if (!abnormalType.toString().equals("")) {
  149. map.put("abnormalData", "1");
  150. map.put("abnormalType", abnormalType.toString());
  151. }
  152. filterData.add(map);
  153. }
  154. Map<String, Object> startTimeAndEndTimeMap = map.entrySet().stream().filter(k -> k.getKey().contains("DeadDataStartTimeAndEndTime")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
  155. compareData(startTimeAndEndTimeMap, filterData,simpleDateFormat);
  156. } catch (Exception e) {
  157. log.error("数据筛选异常" + e);
  158. e.printStackTrace();
  159. }
  160. return filterData;
  161. }
  162. public void compareData(Map<String, Object> startTimeAndEndTimeMap, List<Map<String, Object>> filterData,SimpleDateFormat simpleDateFormat) {
  163. for (Map<String, Object> filterDatum : filterData) {
  164. for (Map.Entry<String, Object> entry : startTimeAndEndTimeMap.entrySet()) {
  165. //获取异常数据字段名
  166. String dataName = entry.getKey().replace("DeadDataStartTimeAndEndTime", "");
  167. //是否存在多时间段异常数据
  168. if (entry.getValue().toString().contains(",")) {
  169. String[] startTimeAndEndTime = entry.getValue().toString().split(",");
  170. for (String time : startTimeAndEndTime) {
  171. //保存异常值
  172. replaceData(time, filterDatum, dataName, simpleDateFormat);
  173. }
  174. } else {
  175. replaceData(entry.getValue().toString(), filterDatum, dataName, simpleDateFormat);
  176. }
  177. }
  178. }
  179. }
  180. public void replaceData(String value, Map<String, Object> filterDatum, String dataName,SimpleDateFormat simpleDateFormat){
  181. Long time;
  182. try {
  183. time = simpleDateFormat.parse(filterDatum.get("time").toString()).getTime();
  184. } catch (ParseException e) {
  185. time = Long.parseLong(filterDatum.get("time").toString());
  186. }
  187. String[] startTimeAndEndTimeSp = value.split("-");
  188. //在时间段内 并且没有此字段名
  189. if (time >= Long.parseLong(startTimeAndEndTimeSp[0]) && time <= Long.parseLong(startTimeAndEndTimeSp[1])) {
  190. if (filterDatum.get("abnormalType") != null && !filterDatum.get("abnormalType").toString().contains(dataName)) {
  191. filterDatum.put("abnormalType", filterDatum.get("abnormalType") + "," + dataName);
  192. }
  193. }
  194. }
  195. public String check(Object object, Integer max, Integer min, Integer change, String name, Long time) {
  196. String s = "";
  197. if (null != object) {
  198. BigDecimal val = new BigDecimal(object.toString());
  199. initValue(val, max, min, name, time);
  200. FakeDataRecord.IrrationalDataType audit = isRational(val, max, min, change, name, time);
  201. //当数据合理时
  202. if (audit == FakeDataRecord.IrrationalDataType.Rational) {
  203. map.put(name + "Time", DateTime.now());
  204. map.put(name + "OriginalVal", val);
  205. map.put(name + "UsedVal", val);
  206. } else {
  207. s = name;
  208. }
  209. }
  210. return s;
  211. }
  212. public void initValue(BigDecimal val, Integer max, Integer min, String name, Long time) {
  213. if (map.get(name + "UsedVal") == null) {
  214. if (val.doubleValue() > max) {
  215. map.put(name + "UsedVal", BigDecimal.valueOf(max));
  216. } else if (val.doubleValue() < min) {
  217. map.put(name + "UsedVal", BigDecimal.valueOf(min));
  218. } else {
  219. map.put(name + "UsedVal", val);
  220. }
  221. }
  222. map.putIfAbsent(name + "OriginalVal", val);
  223. map.putIfAbsent(name + "Time", new DateTime(time));
  224. map.putIfAbsent(name + "DeadDataStartTime", new DateTime(time));
  225. }
  226. /**
  227. * 判断数据是否合理
  228. *
  229. * @param value
  230. * @return
  231. */
  232. public FakeDataRecord.IrrationalDataType isRational(BigDecimal value, Integer max, Integer min, Integer change, String name, Long time) {
  233. //平均值在正常情况下 风速最大值没超过35 即使最大值已经被冻结 依然不标记成异常数据
  234. //风速
  235. if (name.contains("ws")) {
  236. //最大值和平均值需要筛选
  237. if (name.contains("Max") || name.contains("Ave") || name.contains("max") || name.contains("ave")) {
  238. if (isOverMax(name, value, max)) {
  239. return FakeDataRecord.IrrationalDataType.OverMax;
  240. }
  241. if (isLowerMin(name, value, min)) {
  242. return FakeDataRecord.IrrationalDataType.LowerMin;
  243. }
  244. if (isDeadVal(name, value, time)) {
  245. return FakeDataRecord.IrrationalDataType.DeadVal;
  246. }
  247. if (isSuddenChange(name, value, change)) {
  248. return FakeDataRecord.IrrationalDataType.SuddenChange;
  249. }
  250. } else {
  251. return FakeDataRecord.IrrationalDataType.Rational;
  252. }
  253. } else {
  254. if (isOverMax(name, value, max)) {
  255. return FakeDataRecord.IrrationalDataType.OverMax;
  256. }
  257. if (isLowerMin(name, value, min)) {
  258. return FakeDataRecord.IrrationalDataType.LowerMin;
  259. }
  260. if (isDeadVal(name, value, time)) {
  261. return FakeDataRecord.IrrationalDataType.DeadVal;
  262. }
  263. if (isSuddenChange(name, value, change)) {
  264. return FakeDataRecord.IrrationalDataType.SuddenChange;
  265. }
  266. }
  267. return FakeDataRecord.IrrationalDataType.Rational;
  268. }
  269. /**
  270. * 数据是否超上限
  271. *
  272. * @param value 传入值
  273. * @return 是否超上限
  274. */
  275. private static boolean isOverMax(String name, BigDecimal value, Integer max) {
  276. if (BigDecimal.valueOf(max).compareTo(value) < 0) {
  277. log.warn("{}数据超过上限,数值为{},上限为{}", name, value, max);
  278. return true;
  279. } else {
  280. return false;
  281. }
  282. }
  283. /**
  284. * 数据是否越下限
  285. *
  286. * @param value 传入值
  287. * @return 是否越下限
  288. */
  289. private static boolean isLowerMin(String name, BigDecimal value, Integer min) {
  290. if (BigDecimal.valueOf(min).compareTo(value) > 0) {
  291. log.warn("{}数据超过下限,数值为{},下限为{}", name, value, min);
  292. return true;
  293. } else {
  294. return false;
  295. }
  296. }
  297. /**
  298. * 数据是否是死数据
  299. *
  300. * @param value 传入值
  301. * @return 是否是死值
  302. */
  303. private boolean isDeadVal(String name, BigDecimal value, Long time) {
  304. DateTime dateTime = new DateTime(time);
  305. boolean flag = false;
  306. //上个合理值不等于空并且上个合理值和传入值相等
  307. if (map.get(name + "OriginalVal") != null && map.get(name + "OriginalVal").equals(value)) {
  308. String ddst = map.get(name + "DeadDataStartTime").toString();
  309. //如果死值数据开始时间不为空 并且 死值开始时间和传入的时间差距大于30分钟
  310. if (!"".equals(ddst) && Minutes.minutesBetween(new DateTime(ddst), dateTime).getMinutes() > 30) {
  311. log.warn("{}数据死值,数值为{},开始时间为{}", name, value, new DateTime(ddst).toString("HH:mm:ss"));
  312. flag = true;
  313. }
  314. } else {
  315. map.put(name + "DeadDataStartTime", dateTime);
  316. }
  317. return flag;
  318. }
  319. /**
  320. * 数据是否为突变数据
  321. *
  322. * @param value 传入值
  323. * @return boolean 是否突变
  324. */
  325. private boolean isSuddenChange(String name, BigDecimal value, Integer change) {
  326. if (value.subtract(new BigDecimal(map.get(name + "UsedVal").toString())).abs().compareTo(BigDecimal.valueOf(change)) == 1) {
  327. log.warn("{}数据超过突变极限,数值为{},上一个值为{},突变极限为{}", name, value, map.get(name + "UsedVal"), change);
  328. return true;
  329. } else {
  330. return false;
  331. }
  332. }
  333. }