#9 -- add validation

This commit is contained in:
Anton Romanov 2021-08-12 12:02:28 +04:00
parent 430d9496fb
commit 03a9abb428
8 changed files with 71 additions and 51 deletions

View File

@ -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));
}
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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<MethodParamValue> 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<MethodParamValue> 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<MethodParamValue> 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<MethodParamValue> parameters) throws ModelingException {
}

View File

@ -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<LocalDateTime, Double> tsValues, TimeSeriesValue modelValue) throws ModelingException {
return Optional.ofNullable(tsValues.get(modelValue.getDate()))
.orElseThrow(() -> new ModelingException("Значение модельного ряда не найдено в оригинальном ряде: "
+ timeSeriesValueToFind.getDate()
+ " " + timeSeries));
+ modelValue.getDate()
+ " " + tsValues));
}
}

View File

@ -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<LocalDateTime, Double> 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);
}

View File

@ -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),

View File

@ -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("Временной ряд должен иметь разные отметки времени");
}
}
}