diff --git a/src/main/java/ru/ulstu/controller/DbController.java b/src/main/java/ru/ulstu/controller/DbController.java index 6a721e4..334f23f 100644 --- a/src/main/java/ru/ulstu/controller/DbController.java +++ b/src/main/java/ru/ulstu/controller/DbController.java @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import ru.ulstu.configuration.ApiConfiguration; +import ru.ulstu.datamodel.exception.ModelingException; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.db.DbService; import ru.ulstu.db.model.TimeSeriesMeta; @@ -52,29 +53,29 @@ public class DbController { } @GetMapping("add-time-series-set") - public void addTimeSeriesSet(@RequestParam("setKey") String setKey) { - dbService.addSet(setKey); + public boolean addTimeSeriesSet(@RequestParam("setKey") String setKey) { + return dbService.addSet(setKey); } @PostMapping("add-time-series") - public void addTimeSeries(@RequestParam("setKey") String setKey, @RequestBody TimeSeries timeSeries) throws IOException { + public void addTimeSeries(@RequestParam("setKey") String setKey, @RequestBody TimeSeries timeSeries) throws IOException, ModelingException { dbService.addTimeSeries(new TimeSeriesSet(setKey), timeSeries); } @PostMapping("add-time-series-string") - public void addTimeSeries(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey, @RequestBody String timeSeries) throws IOException { + public void addTimeSeries(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey, @RequestBody String timeSeries) throws IOException, ModelingException { TimeSeries timeSeriesWithKey = utilService.getTimeSeriesFromString(timeSeries); timeSeriesWithKey.setKey(timeSeriesKey); dbService.addTimeSeries(new TimeSeriesSet(setKey), timeSeriesWithKey); } @DeleteMapping("delete-time-series") - public void deleteTimeSeries(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey) throws IOException { - dbService.deleteTimeSeries(new TimeSeriesSet(setKey), timeSeriesKey); + public boolean deleteTimeSeries(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey) throws IOException { + return dbService.deleteTimeSeries(new TimeSeriesSet(setKey), timeSeriesKey); } @DeleteMapping("delete-time-series-set") - public void deleteTimeSeriesSet(@RequestParam("setKey") String setKey) throws IOException { - dbService.deleteTimeSeriesSet(new TimeSeriesSet(setKey)); + public boolean deleteTimeSeriesSet(@RequestParam("setKey") String setKey) throws IOException { + return dbService.deleteTimeSeriesSet(new TimeSeriesSet(setKey)); } } diff --git a/src/main/java/ru/ulstu/db/DbFileService.java b/src/main/java/ru/ulstu/db/DbFileService.java index d6281b6..8e6cdf0 100644 --- a/src/main/java/ru/ulstu/db/DbFileService.java +++ b/src/main/java/ru/ulstu/db/DbFileService.java @@ -9,10 +9,12 @@ package ru.ulstu.db; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import ru.ulstu.datamodel.exception.ModelingException; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.db.model.TimeSeriesMeta; import ru.ulstu.db.model.TimeSeriesSet; import ru.ulstu.service.UtilService; +import ru.ulstu.service.ValidationUtils; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -72,17 +74,18 @@ public class DbFileService implements DbService { } @Override - public void addSet(String key) { + public boolean addSet(String key) { TimeSeriesSet timeSeriesSet = new TimeSeriesSet(key); if (isTimeSeriesSetExists(timeSeriesSet)) { throw new RuntimeException(String.format("Time series set %s already exists", timeSeriesSet.getKey())); } else { - Paths.get(timeSeriesDbPath, timeSeriesSet.getKey()).toFile().mkdirs(); + return Paths.get(timeSeriesDbPath, timeSeriesSet.getKey()).toFile().mkdirs(); } } @Override - public void addTimeSeries(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException { + public void addTimeSeries(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException, ModelingException { + ValidationUtils.validateTimeSeries(timeSeries); if (!isTimeSeriesSetExists(timeSeriesSet)) { addSet(timeSeriesSet.getKey()); } @@ -100,16 +103,17 @@ public class DbFileService implements DbService { } @Override - public void deleteTimeSeries(TimeSeriesSet set, String timeSeriesKey) throws IOException { + public boolean deleteTimeSeries(TimeSeriesSet set, String timeSeriesKey) throws IOException { validateDb(set, timeSeriesKey); Files.delete(getTimeSeriesFile(set, timeSeriesKey).toPath()); Files.delete(getTimeSeriesMetaFile(set, timeSeriesKey).toPath()); + return true; } @Override - public void deleteTimeSeriesSet(TimeSeriesSet timeSeriesSet) { + public boolean deleteTimeSeriesSet(TimeSeriesSet timeSeriesSet) { validateDb(timeSeriesSet); - deleteDirectory(getSetPath(timeSeriesSet)); + return deleteDirectory(getSetPath(timeSeriesSet)); } private void validateDb(TimeSeriesSet timeSeriesSet, String timeSeriesKey) { diff --git a/src/main/java/ru/ulstu/db/DbService.java b/src/main/java/ru/ulstu/db/DbService.java index a3457e9..db0af76 100644 --- a/src/main/java/ru/ulstu/db/DbService.java +++ b/src/main/java/ru/ulstu/db/DbService.java @@ -6,6 +6,7 @@ package ru.ulstu.db; +import ru.ulstu.datamodel.exception.ModelingException; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.db.model.TimeSeriesMeta; import ru.ulstu.db.model.TimeSeriesSet; @@ -20,11 +21,11 @@ public interface DbService { TimeSeries getTimeSeries(TimeSeriesSet timeSeriesSet, String timeSeriesKey) throws IOException; - void addSet(String key); + boolean addSet(String key); - void addTimeSeries(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException; + void addTimeSeries(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException, ModelingException; - void deleteTimeSeries(TimeSeriesSet set, String timeSeriesKey) throws IOException; + boolean deleteTimeSeries(TimeSeriesSet set, String timeSeriesKey) throws IOException; - void deleteTimeSeriesSet(TimeSeriesSet timeSeriesSet) throws IOException; + boolean deleteTimeSeriesSet(TimeSeriesSet timeSeriesSet) throws IOException; } diff --git a/src/main/java/ru/ulstu/method/Method.java b/src/main/java/ru/ulstu/method/Method.java index d065945..9a4e459 100644 --- a/src/main/java/ru/ulstu/method/Method.java +++ b/src/main/java/ru/ulstu/method/Method.java @@ -12,9 +12,9 @@ import ru.ulstu.TimeSeriesUtils; import ru.ulstu.datamodel.Model; import ru.ulstu.datamodel.exception.ForecastValidateException; import ru.ulstu.datamodel.exception.ModelingException; -import ru.ulstu.datamodel.exception.TimeSeriesValidateException; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeriesValue; +import ru.ulstu.service.ValidationUtils; import java.time.temporal.ChronoUnit; import java.util.List; @@ -44,7 +44,7 @@ public abstract class Method { * @throws ModelingException генерируется, если есть проблемы моделирования при задании параметров */ public Model getModel(TimeSeries timeSeries, List parameters) throws ModelingException { - validateTimeSeries(timeSeries); + ValidationUtils.validateTimeSeries(timeSeries); validateAdditionalParams(timeSeries, parameters); return getModelOfValidTimeSeries(timeSeries, parameters); } @@ -60,7 +60,7 @@ public abstract class Method { public boolean canMakeForecast(TimeSeries timeSeries, List parameters, int countPoints) { try { - validateTimeSeries(timeSeries); + ValidationUtils.validateTimeSeries(timeSeries); validateAdditionalParams(timeSeries, parameters); validateForecastParams(countPoints); } catch (ModelingException ex) { @@ -71,7 +71,7 @@ public abstract class Method { public boolean canMakeModel(TimeSeries timeSeries, List parameters) { try { - validateTimeSeries(timeSeries); + ValidationUtils.validateTimeSeries(timeSeries); validateAdditionalParams(timeSeries, parameters); } catch (ModelingException ex) { return false; @@ -112,21 +112,6 @@ public abstract class Method { } } - protected void validateTimeSeries(TimeSeries timeSeries) throws ModelingException { - if (timeSeries == null || timeSeries.isEmpty()) { - throw new TimeSeriesValidateException("Временной ряд должен быть не пустым"); - } - if (timeSeries.getLength() < 2) { - throw new TimeSeriesValidateException("Временной ряд должен содержать хотя бы 2 точки"); - } - if (timeSeries.getValues().stream().anyMatch(val -> val == null || val.getValue() == null)) { - throw new TimeSeriesValidateException("Временной ряд содержит пустые значения"); - } - if (timeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) { - throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени"); - } - } - protected void validateAdditionalParams(TimeSeries timeSeries, List parameters) throws ModelingException { } diff --git a/src/main/java/ru/ulstu/score/ScoreMethod.java b/src/main/java/ru/ulstu/score/ScoreMethod.java index b85874f..caffd58 100644 --- a/src/main/java/ru/ulstu/score/ScoreMethod.java +++ b/src/main/java/ru/ulstu/score/ScoreMethod.java @@ -13,6 +13,7 @@ import ru.ulstu.datamodel.ts.TimeSeriesValue; import java.time.LocalDateTime; import java.util.Map; +import java.util.Optional; public abstract class ScoreMethod { private final String name; @@ -31,13 +32,10 @@ public abstract class ScoreMethod { return name; } - protected TimeSeriesValue getValueOnSameDate(TimeSeriesValue timeSeriesValueToFind, TimeSeries timeSeries) throws ModelingException { - return timeSeries.getValues() - .stream() - .filter(v -> v.getDate().equals(timeSeriesValueToFind.getDate())) - .findAny() + protected Double getValueOnSameDate(Map tsValues, TimeSeriesValue modelValue) throws ModelingException { + return Optional.ofNullable(tsValues.get(modelValue.getDate())) .orElseThrow(() -> new ModelingException("Значение модельного ряда не найдено в оригинальном ряде: " - + timeSeriesValueToFind.getDate() - + " " + timeSeries)); + + modelValue.getDate() + + " " + tsValues)); } } diff --git a/src/main/java/ru/ulstu/score/Smape.java b/src/main/java/ru/ulstu/score/Smape.java index 4b5af9e..d5a1a44 100644 --- a/src/main/java/ru/ulstu/score/Smape.java +++ b/src/main/java/ru/ulstu/score/Smape.java @@ -12,7 +12,6 @@ import ru.ulstu.datamodel.ts.TimeSeriesValue; import java.time.LocalDateTime; import java.util.Map; -import java.util.Optional; import static java.lang.Math.abs; @@ -25,10 +24,7 @@ public class Smape extends ScoreMethod { public Number evaluate(Map tsValues, TimeSeries model) throws ModelingException { double sum = 0; for (TimeSeriesValue modelValue : model.getValues()) { - //double actualValue = getValueOnSameDate(modelValue, original).getValue(); - double actualValue = Optional.ofNullable(tsValues.get(modelValue.getDate())) - .orElseThrow(() -> new ModelingException("Значение модельного ряда не найдено в оригинальном ряде: " - + modelValue.getDate())); + double actualValue = getValueOnSameDate(tsValues, modelValue); sum += abs(modelValue.getValue() - actualValue) / ((abs(actualValue) + abs(modelValue.getValue())) / 2); } diff --git a/src/main/java/ru/ulstu/service/MethodParamBruteForce.java b/src/main/java/ru/ulstu/service/MethodParamBruteForce.java index 897a788..f528aff 100644 --- a/src/main/java/ru/ulstu/service/MethodParamBruteForce.java +++ b/src/main/java/ru/ulstu/service/MethodParamBruteForce.java @@ -59,8 +59,7 @@ public class MethodParamBruteForce { Method methodInstance = method.getClass().getDeclaredConstructor().newInstance(); if (methodInstance.canMakeForecast(reducedTimeSeries, parametersValues, countPoints)) { results.add(executors.submit(() -> { - TimeSeries forecast = methodInstance.getForecast(reducedTimeSeries, parametersValues, countPoints); - forecast = syncDates(forecast, timeSeries); + TimeSeries forecast = syncDates(methodInstance.getForecast(reducedTimeSeries, parametersValues, countPoints), timeSeries); return new ModelingResult(forecast, null, parametersValues, scoreMethod.getScore(tsValues, forecast), diff --git a/src/main/java/ru/ulstu/service/ValidationUtils.java b/src/main/java/ru/ulstu/service/ValidationUtils.java new file mode 100644 index 0000000..ffeced5 --- /dev/null +++ b/src/main/java/ru/ulstu/service/ValidationUtils.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + */ + +package ru.ulstu.service; + +import ru.ulstu.datamodel.exception.ModelingException; +import ru.ulstu.datamodel.exception.TimeSeriesValidateException; +import ru.ulstu.datamodel.ts.TimeSeries; +import ru.ulstu.datamodel.ts.TimeSeriesValue; + +import java.util.stream.Collectors; + + +public class ValidationUtils { + public static void validateTimeSeries(TimeSeries timeSeries) throws ModelingException { + if (timeSeries == null || timeSeries.isEmpty()) { + throw new TimeSeriesValidateException("Временной ряд должен быть не пустым"); + } + if (timeSeries.getLength() < 2) { + throw new TimeSeriesValidateException("Временной ряд должен содержать хотя бы 2 точки"); + } + if (timeSeries.getValues().stream().anyMatch(val -> val == null || val.getValue() == null)) { + throw new TimeSeriesValidateException("Временной ряд содержит пустые значения"); + } + if (timeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) { + throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени"); + } + + if (timeSeries.getValues().stream().map(TimeSeriesValue::getDate).collect(Collectors.toSet()).size() < timeSeries.getLength()) { + throw new TimeSeriesValidateException("Временной ряд должен иметь разные отметки времени"); + } + } +}