#1 -- add choosing method in api

This commit is contained in:
Anton Romanov 2022-04-18 12:19:25 +04:00
parent e13ba082d8
commit d5c99caeb3
6 changed files with 69 additions and 19 deletions

View File

@ -20,6 +20,7 @@ import ru.ulstu.method.Method;
import ru.ulstu.service.TimeSeriesService; import ru.ulstu.service.TimeSeriesService;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -37,7 +38,7 @@ public class TimeSeriesController {
@PostMapping("getForecast") @PostMapping("getForecast")
@Operation(description = "Получить прогноз временного ряда любым методом") @Operation(description = "Получить прогноз временного ряда любым методом")
public ResponseEntity<ModelingResult> getForecastTimeSeries(@RequestBody ForecastParams forecastParams, HttpServletRequest request) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException { public ResponseEntity<ModelingResult> getForecastTimeSeries(@RequestBody @Valid ForecastParams forecastParams, HttpServletRequest request) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException {
LOGGER.info("User ip: " + HttpUtils.getUserIp(request)); LOGGER.info("User ip: " + HttpUtils.getUserIp(request));
LOGGER.info("Forecast: " + forecastParams); LOGGER.info("Forecast: " + forecastParams);
ResponseEntity<ModelingResult> result = new ResponseEntity<>(timeSeriesService.getForecast(forecastParams.getOriginalTimeSeries(), ResponseEntity<ModelingResult> result = new ResponseEntity<>(timeSeriesService.getForecast(forecastParams.getOriginalTimeSeries(),
@ -58,10 +59,11 @@ public class TimeSeriesController {
@PostMapping("getSpecificMethodForecast") @PostMapping("getSpecificMethodForecast")
@Operation(description = "Получить прогноз временного ряда указанным методом") @Operation(description = "Получить прогноз временного ряда указанным методом")
public ResponseEntity<ModelingResult> getForecastTimeSeriesSpecificMethod(@RequestBody ForecastParams forecastParams, HttpServletRequest request) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException { public ResponseEntity<ModelingResult> getForecastTimeSeriesSpecificMethod(@RequestBody @Valid ForecastParams forecastParams, HttpServletRequest request) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException {
LOGGER.info("User ip: " + HttpUtils.getUserIp(request)); LOGGER.info("User ip: " + HttpUtils.getUserIp(request));
LOGGER.info("Forecast: " + forecastParams); LOGGER.info("Forecast: " + forecastParams);
ResponseEntity<ModelingResult> result = new ResponseEntity<>(timeSeriesService.getForecast(forecastParams.getOriginalTimeSeries(), ResponseEntity<ModelingResult> result = new ResponseEntity<>(timeSeriesService.getForecast(forecastParams.getOriginalTimeSeries(),
forecastParams.getMethodClassName(),
forecastParams.getCountForecast()), HttpStatus.OK); forecastParams.getCountForecast()), HttpStatus.OK);
LOGGER.info("Forecast result complete"); LOGGER.info("Forecast result complete");
return result; return result;

View File

@ -2,9 +2,14 @@ package ru.ulstu.datamodel;
import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeries;
import javax.validation.constraints.NotNull;
public class ForecastParams { public class ForecastParams {
@NotNull
private TimeSeries originalTimeSeries; private TimeSeries originalTimeSeries;
@NotNull
private int countForecast; private int countForecast;
private String methodClassName;
public TimeSeries getOriginalTimeSeries() { public TimeSeries getOriginalTimeSeries() {
return originalTimeSeries; return originalTimeSeries;
@ -22,6 +27,14 @@ public class ForecastParams {
this.countForecast = countForecast; this.countForecast = countForecast;
} }
public String getMethodClassName() {
return methodClassName;
}
public void setMethodClassName(String methodClassName) {
this.methodClassName = methodClassName;
}
@Override @Override
public String toString() { public String toString() {
return "ForecastParams{" + return "ForecastParams{" +

View File

@ -3,7 +3,7 @@ package ru.ulstu.db.model;
import java.io.File; import java.io.File;
public class TimeSeriesSet { public class TimeSeriesSet {
private String key; private final String key;
public TimeSeriesSet(File dir) { public TimeSeriesSet(File dir) {
this.key = dir.getName(); this.key = dir.getName();

View File

@ -86,7 +86,9 @@ public abstract class Method {
Model model = getModel(timeSeries, parameters); Model model = getModel(timeSeries, parameters);
TimeSeries forecast = generateEmptyForecastPoints(model.getTimeSeriesModel(), countPoints); TimeSeries forecast = generateEmptyForecastPoints(model.getTimeSeriesModel(), countPoints);
forecast.getFirstValue().setValue(model.getTimeSeriesModel().getLastValue().getValue()); forecast.getFirstValue().setValue(model.getTimeSeriesModel().getLastValue().getValue());
return getForecastWithValidParams(model, forecast); forecast = getForecastWithValidParams(model, forecast);
forecast.getFirstValue().setValue(timeSeries.getLastValue().getValue());
return forecast;
} }
protected TimeSeries generateEmptyForecastPoints(TimeSeries model, int countPointForecast) { protected TimeSeries generateEmptyForecastPoints(TimeSeries model, int countPointForecast) {

View File

@ -37,9 +37,9 @@ class MethodParamBruteForce {
this.methods = methods; this.methods = methods;
} }
public ModelingResult getForecast(TimeSeries timeSeries, int countPointsForecast) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ModelingException { private ModelingResult getForecastByMethods(TimeSeries timeSeries, List<Method> methods, int countPointsForecast) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ModelingException {
List<Future<ModelingResult>> results = new ArrayList<>(); List<Future<ModelingResult>> futureModelingResults = new ArrayList<>();
List<ModelingResult> results2 = new CopyOnWriteArrayList<>(); List<ModelingResult> modelingResults = new CopyOnWriteArrayList<>();
final int countPoints = (countPointsForecast > timeSeries.getLength()) ? timeSeries.getLength() / 3 : countPointsForecast; final int countPoints = (countPointsForecast > timeSeries.getLength()) ? timeSeries.getLength() / 3 : countPointsForecast;
TimeSeries reducedTimeSeries = new TimeSeries(timeSeries.getValues().stream().limit(timeSeries.getLength() - countPoints).collect(Collectors.toList()), TimeSeries reducedTimeSeries = new TimeSeries(timeSeries.getValues().stream().limit(timeSeries.getLength() - countPoints).collect(Collectors.toList()),
"test part of " + timeSeries.getKey()); "test part of " + timeSeries.getKey());
@ -52,7 +52,7 @@ class MethodParamBruteForce {
for (List<MethodParamValue> parametersValues : availableParametersValues) { for (List<MethodParamValue> parametersValues : availableParametersValues) {
Method methodInstance = method.getClass().getDeclaredConstructor().newInstance(); Method methodInstance = method.getClass().getDeclaredConstructor().newInstance();
if (methodInstance.canMakeForecast(reducedTimeSeries, parametersValues, countPoints)) { if (methodInstance.canMakeForecast(reducedTimeSeries, parametersValues, countPoints)) {
results.add(executors.submit(() -> { futureModelingResults.add(executors.submit(() -> {
TimeSeries forecast = syncDates(methodInstance.getForecast(reducedTimeSeries, parametersValues, countPoints), timeSeries); TimeSeries forecast = syncDates(methodInstance.getForecast(reducedTimeSeries, parametersValues, countPoints), timeSeries);
return new ModelingResult(forecast, null, return new ModelingResult(forecast, null,
parametersValues, parametersValues,
@ -62,17 +62,39 @@ class MethodParamBruteForce {
} }
} }
} }
for (Future<ModelingResult> futureModelingResult : results) { for (Future<ModelingResult> futureModelingResult : futureModelingResults) {
results2.add(futureModelingResult.get()); modelingResults.add(futureModelingResult.get());
} }
ModelingResult bestResult = results2.stream()
return getBestResultForecast(modelingResults, timeSeries, countPoints);
}
public ModelingResult getForecast(TimeSeries timeSeries, String methodClassName, int countPointsForecast) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ModelingException {
Method method = methods.stream()
.filter(m -> m.getClass().getSimpleName().equals(methodClassName))
.findAny()
.orElseThrow(() -> new ModelingException("Неизвестный метод прогнозирования"));
return getForecastByMethods(timeSeries, List.of(method), countPointsForecast);
}
public ModelingResult getForecast(TimeSeries timeSeries, Method method, int countPointsForecast) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ModelingException {
return getForecastByMethods(timeSeries, List.of(method), countPointsForecast);
}
public ModelingResult getForecast(TimeSeries timeSeries, int countPointsForecast) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ModelingException {
return getForecastByMethods(timeSeries, methods, countPointsForecast);
}
private ModelingResult getBestResultForecast(List<ModelingResult> modelingResults,
TimeSeries timeSeries,
int countPoints) throws ModelingException {
ModelingResult bestResult = modelingResults.stream()
.min(Comparator.comparing(modelingResult -> modelingResult.getScore().getDoubleValue())) .min(Comparator.comparing(modelingResult -> modelingResult.getScore().getDoubleValue()))
.orElseThrow(() -> new ModelingException("Лучший метод не найден")); .orElseThrow(() -> new ModelingException("Лучший метод не найден"));
TimeSeries forecast = bestResult.getTimeSeriesMethod().getForecast(timeSeries, TimeSeries forecast = bestResult.getTimeSeriesMethod().getForecast(timeSeries,
bestResult.getParamValues(), bestResult.getParamValues(),
countPoints); countPoints);
forecast.getValue(0).setValue(timeSeries.getNumericValue(timeSeries.getLength() - 1));
return new ModelingResult(forecast, return new ModelingResult(forecast,
bestResult.getTimeSeries(), bestResult.getTimeSeries(),
@ -90,9 +112,12 @@ class MethodParamBruteForce {
return forecast; return forecast;
} }
/*
TODO:
public TimeSeries getForecastWithOptimalLength(TimeSeries timeSeries) { public TimeSeries getForecastWithOptimalLength(TimeSeries timeSeries) {
throw new RuntimeException("Not implemented"); throw new RuntimeException("Not implemented");
} }
*/
public ModelingResult getSmoothedTimeSeries(TimeSeries timeSeries) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { public ModelingResult getSmoothedTimeSeries(TimeSeries timeSeries) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
List<Future<ModelingResult>> results = new ArrayList<>(); List<Future<ModelingResult>> results = new ArrayList<>();
@ -133,7 +158,7 @@ class MethodParamBruteForce {
parameterOffset.put(methodParameter, 0); parameterOffset.put(methodParameter, 0);
parameterValues.put(methodParameter, methodParameter.getAvailableValues()); parameterValues.put(methodParameter, methodParameter.getAvailableValues());
} }
while (!isAllValuesUsed(parameterOffset, parameterValues)) { while (isNotAllParameterValuesUsed(parameterOffset, parameterValues)) {
List<MethodParamValue> resultRow = new ArrayList<>(); List<MethodParamValue> resultRow = new ArrayList<>();
for (MethodParameter methodParameter : parameterOffset.keySet()) { for (MethodParameter methodParameter : parameterOffset.keySet()) {
resultRow.add(new MethodParamValue(methodParameter, resultRow.add(new MethodParamValue(methodParameter,
@ -149,7 +174,7 @@ class MethodParamBruteForce {
Map<MethodParameter, List<Number>> parameterValues) { Map<MethodParameter, List<Number>> parameterValues) {
List<MethodParameter> parameters = new ArrayList<>(parameterOffset.keySet()); List<MethodParameter> parameters = new ArrayList<>(parameterOffset.keySet());
int i = 0; int i = 0;
while (i < parameters.size() && !isAllValuesUsed(parameterOffset, parameterValues)) { while (i < parameters.size() && isNotAllParameterValuesUsed(parameterOffset, parameterValues)) {
if (parameterOffset.get(parameters.get(i)) == parameterValues.get(parameters.get(i)).size() - 1) { if (parameterOffset.get(parameters.get(i)) == parameterValues.get(parameters.get(i)).size() - 1) {
parameterOffset.put(parameters.get(i), 0); parameterOffset.put(parameters.get(i), 0);
i++; i++;
@ -163,15 +188,15 @@ class MethodParamBruteForce {
} }
} }
private boolean isAllValuesUsed(Map<MethodParameter, Integer> parameterOffset, private boolean isNotAllParameterValuesUsed(Map<MethodParameter, Integer> parameterOffset,
Map<MethodParameter, List<Number>> parameterValues) { Map<MethodParameter, List<Number>> parameterValues) {
for (MethodParameter methodParameter : parameterOffset.keySet()) { for (MethodParameter methodParameter : parameterOffset.keySet()) {
if (parameterOffset.get(methodParameter) != parameterValues.get(methodParameter).size() - 1) { if (parameterOffset.get(methodParameter) != parameterValues.get(methodParameter).size() - 1) {
return false;
}
}
return true; return true;
} }
}
return false;
}
public List<Method> getAvailableMethods() { public List<Method> getAvailableMethods() {
return methods; return methods;

View File

@ -1,5 +1,6 @@
package ru.ulstu.service; package ru.ulstu.service;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.datamodel.ModelingResult; import ru.ulstu.datamodel.ModelingResult;
import ru.ulstu.datamodel.exception.ModelingException; import ru.ulstu.datamodel.exception.ModelingException;
@ -14,15 +15,22 @@ import java.util.concurrent.ExecutionException;
@Service @Service
public class TimeSeriesService { public class TimeSeriesService {
private final MethodParamBruteForce methodParamBruteForce; private final MethodParamBruteForce methodParamBruteForce;
private final ApplicationContext applicationContext;
public TimeSeriesService(MethodParamBruteForce methodParamBruteForce) { public TimeSeriesService(MethodParamBruteForce methodParamBruteForce,
ApplicationContext applicationContext) {
this.methodParamBruteForce = methodParamBruteForce; this.methodParamBruteForce = methodParamBruteForce;
this.applicationContext = applicationContext;
} }
public ModelingResult getForecast(TimeSeries timeSeries, int countPoints) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException { public ModelingResult getForecast(TimeSeries timeSeries, int countPoints) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException {
return methodParamBruteForce.getForecast(timeSeries, countPoints); return methodParamBruteForce.getForecast(timeSeries, countPoints);
} }
public ModelingResult getForecast(TimeSeries timeSeries, String methodClassName, int countPoints) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException {
return methodParamBruteForce.getForecast(timeSeries, methodClassName, countPoints);
}
public ModelingResult smoothTimeSeries(TimeSeries timeSeries) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { public ModelingResult smoothTimeSeries(TimeSeries timeSeries) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
return methodParamBruteForce.getSmoothedTimeSeries(timeSeries); return methodParamBruteForce.getSmoothedTimeSeries(timeSeries);
} }