From b0b68199eebf9f0dfebc93f21b1d2077e5d09060 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Mon, 2 Aug 2021 11:39:41 +0400 Subject: [PATCH] #5 -- forecast db time series --- .../ulstu/configuration/MvcConfiguration.java | 2 +- .../ru/ulstu/controller/IndexController.java | 53 ++++++- .../java/ru/ulstu/datamodel/ChartForm.java | 31 ++++ src/main/java/ru/ulstu/datamodel/Model.java | 2 +- .../ru/ulstu/datamodel/ModelingResult.java | 7 + src/main/java/ru/ulstu/datamodel/Score.java | 2 +- .../ru/ulstu/datamodel/ts/TimeSeries.java | 26 ++-- src/main/java/ru/ulstu/db/DbFileService.java | 4 +- .../ru/ulstu/db/model/TimeSeriesMeta.java | 2 +- src/main/java/ru/ulstu/method/Method.java | 2 +- src/main/java/ru/ulstu/page/IndexView.java | 144 ------------------ .../ulstu/service/MethodParamBruteForce.java | 6 +- src/main/resources/templates/error.html | 49 ------ src/main/resources/templates/index.html | 50 +++++- 14 files changed, 151 insertions(+), 229 deletions(-) create mode 100644 src/main/java/ru/ulstu/datamodel/ChartForm.java delete mode 100644 src/main/java/ru/ulstu/page/IndexView.java delete mode 100644 src/main/resources/templates/error.html diff --git a/src/main/java/ru/ulstu/configuration/MvcConfiguration.java b/src/main/java/ru/ulstu/configuration/MvcConfiguration.java index e673f16..8185991 100644 --- a/src/main/java/ru/ulstu/configuration/MvcConfiguration.java +++ b/src/main/java/ru/ulstu/configuration/MvcConfiguration.java @@ -16,7 +16,7 @@ public class MvcConfiguration implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/{articlename:\\w+}"); - registry.addRedirectViewController("/", "/index.html"); + //registry.addRedirectViewController("/", "/index.html"); } @Override diff --git a/src/main/java/ru/ulstu/controller/IndexController.java b/src/main/java/ru/ulstu/controller/IndexController.java index c4f56ed..09458db 100644 --- a/src/main/java/ru/ulstu/controller/IndexController.java +++ b/src/main/java/ru/ulstu/controller/IndexController.java @@ -11,12 +11,17 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import ru.ulstu.datamodel.ChartForm; +import ru.ulstu.datamodel.ModelingResult; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeriesValue; +import ru.ulstu.db.DbService; import ru.ulstu.service.TimeSeriesService; import ru.ulstu.service.UtilService; import springfox.documentation.annotations.ApiIgnore; +import java.io.IOException; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Set; @@ -27,23 +32,50 @@ import java.util.stream.Collectors; public class IndexController { private final UtilService utilService; private final TimeSeriesService timeSeriesService; + private final DbService dbService; private final static Logger LOG = LoggerFactory.getLogger(IndexController.class); public IndexController(UtilService utilService, - TimeSeriesService timeSeriesService) { + TimeSeriesService timeSeriesService, + DbService dbService) { this.utilService = utilService; this.timeSeriesService = timeSeriesService; + this.dbService = dbService; } - @GetMapping("/index.html") - public String index(Model model) { - TimeSeries timeSeries = utilService.getRandomTimeSeries(100); + @GetMapping("/") + public String index(Model model) throws IOException { + model.addAttribute("sets", dbService.getSets()); + model.addAttribute("chartForm", new ChartForm()); + return "index.html"; + } + + @GetMapping("chart") + public String chart(@ModelAttribute ChartForm chartForm, Model model) throws IOException { + model.addAttribute("sets", dbService.getSets()); + if (chartForm.getSet() != null) { + model.addAttribute("listTimeSeries", dbService.getTimeSeriesMeta(chartForm.getSet())); + } + if (chartForm.getTimeSeriesMeta() != null + && chartForm.getTimeSeriesMeta().getKey() != null + && !chartForm.getTimeSeriesMeta().getKey().isEmpty()) { + addChartToModel(dbService.getTimeSeries(chartForm.getSet(), chartForm.getTimeSeriesMeta().getKey()), model); + } + return "index.html"; + } + + private void addChartToModel(TimeSeries timeSeries, Model model) { + int countForecastPoints = 10; TimeSeries timeSeriesModel = null; + ModelingResult modelingResult = null; TimeSeries forecast = null; + TimeSeries testForecast = null; try { timeSeriesModel = timeSeriesService.smoothTimeSeries(timeSeries); - forecast = timeSeriesService.getForecast(timeSeries, 5).getTimeSeries(); + modelingResult = timeSeriesService.getForecast(timeSeries, countForecastPoints); + forecast = modelingResult.getTimeSeries(); + testForecast = modelingResult.getTestForecast(); } catch (Exception e) { LOG.warn(e.getMessage()); } @@ -58,9 +90,18 @@ public class IndexController { model.addAttribute("timeSeries", timeSeries.getValues().stream().map(TimeSeriesValue::getValue).toArray()); model.addAttribute("model", timeSeriesModel.getValues().stream().map(TimeSeriesValue::getValue).toArray()); timeSeries.getValues().remove(timeSeries.getValues().size() - 1); + List forecastValues = timeSeries.getValues().stream().map(v -> (Double) null).collect(Collectors.toList()); forecastValues.addAll(forecast.getValues().stream().map(TimeSeriesValue::getValue).collect(Collectors.toList())); model.addAttribute("forecast", forecastValues.toArray()); - return "index.html"; + + List testForecastValues = timeSeries.getValues() + .stream() + .skip(countForecastPoints) + .map(v -> (Double) null) + .collect(Collectors.toList()); + testForecastValues.addAll(testForecast.getValues().stream().map(TimeSeriesValue::getValue).collect(Collectors.toList())); + model.addAttribute("testForecast", testForecastValues.toArray()); + model.addAttribute("forecastDescription", modelingResult); } } diff --git a/src/main/java/ru/ulstu/datamodel/ChartForm.java b/src/main/java/ru/ulstu/datamodel/ChartForm.java new file mode 100644 index 0000000..f3e395d --- /dev/null +++ b/src/main/java/ru/ulstu/datamodel/ChartForm.java @@ -0,0 +1,31 @@ +/* + * 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.datamodel; + +import ru.ulstu.db.model.TimeSeriesMeta; +import ru.ulstu.db.model.TimeSeriesSet; + +public class ChartForm { + private TimeSeriesSet set; + private TimeSeriesMeta timeSeriesMeta; + + public TimeSeriesSet getSet() { + return set; + } + + public void setSet(TimeSeriesSet set) { + this.set = set; + } + + public TimeSeriesMeta getTimeSeriesMeta() { + return timeSeriesMeta; + } + + public void setTimeSeriesMeta(TimeSeriesMeta timeSeriesMeta) { + this.timeSeriesMeta = timeSeriesMeta; + } +} diff --git a/src/main/java/ru/ulstu/datamodel/Model.java b/src/main/java/ru/ulstu/datamodel/Model.java index 7f912fb..1ee7734 100644 --- a/src/main/java/ru/ulstu/datamodel/Model.java +++ b/src/main/java/ru/ulstu/datamodel/Model.java @@ -12,7 +12,7 @@ public abstract class Model { protected final TimeSeries timeSeriesModel; protected Model(TimeSeries ts) { - timeSeriesModel = new TimeSeries("Model of", ts.getName()); + timeSeriesModel = new TimeSeries("Model of", ts.getKey()); } public TimeSeries getTimeSeriesModel() { diff --git a/src/main/java/ru/ulstu/datamodel/ModelingResult.java b/src/main/java/ru/ulstu/datamodel/ModelingResult.java index 79a8940..f94c111 100644 --- a/src/main/java/ru/ulstu/datamodel/ModelingResult.java +++ b/src/main/java/ru/ulstu/datamodel/ModelingResult.java @@ -14,15 +14,18 @@ import java.util.List; public class ModelingResult { private final TimeSeries timeSeries; + private final TimeSeries testForecast; private final List paramValues; private final Score score; private final Method method; public ModelingResult(TimeSeries timeSeries, + TimeSeries testForecast, List paramValues, Score score, Method method) { this.timeSeries = timeSeries; + this.testForecast = testForecast; this.paramValues = paramValues; this.score = score; this.method = method; @@ -43,4 +46,8 @@ public class ModelingResult { public Method getTimeSeriesMethod() { return method; } + + public TimeSeries getTestForecast() { + return testForecast; + } } diff --git a/src/main/java/ru/ulstu/datamodel/Score.java b/src/main/java/ru/ulstu/datamodel/Score.java index aedf724..a154ab5 100644 --- a/src/main/java/ru/ulstu/datamodel/Score.java +++ b/src/main/java/ru/ulstu/datamodel/Score.java @@ -23,7 +23,7 @@ public class Score { } public Number getValue() { - return value; + return ((double) Math.round(value.doubleValue() * 100)) / 100; } @JsonIgnore diff --git a/src/main/java/ru/ulstu/datamodel/ts/TimeSeries.java b/src/main/java/ru/ulstu/datamodel/ts/TimeSeries.java index 237be7b..ca70eef 100644 --- a/src/main/java/ru/ulstu/datamodel/ts/TimeSeries.java +++ b/src/main/java/ru/ulstu/datamodel/ts/TimeSeries.java @@ -15,20 +15,20 @@ import java.util.List; public class TimeSeries { private List values = new ArrayList<>(); - private String name; + private String key; - public TimeSeries(String name) { - this.name = name; + public TimeSeries(String key) { + this.key = key; } public TimeSeries(String prefix, String suffix) { - this.name = String.format("%s %s", prefix, suffix); + this.key = String.format("%s %s", prefix, suffix); } @JsonCreator - public TimeSeries(@JsonProperty(value = "values") List values, @JsonProperty(value = "name") String name) { + public TimeSeries(@JsonProperty(value = "values") List values, @JsonProperty(value = "name") String key) { this.values = values; - this.name = name; + this.key = key; } public TimeSeries() { @@ -43,16 +43,12 @@ public class TimeSeries { return values; } - public void setValues(List values) { - this.values = values; + public String getKey() { + return key; } - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; + public void setKey(String key) { + this.key = key; } public boolean isEmpty() { @@ -102,7 +98,7 @@ public class TimeSeries { public String toString() { return "TimeSeries{" + "values=" + values + - ", name='" + name + '\'' + + ", name='" + key + '\'' + '}'; } } diff --git a/src/main/java/ru/ulstu/db/DbFileService.java b/src/main/java/ru/ulstu/db/DbFileService.java index 220be1a..8d9d70d 100644 --- a/src/main/java/ru/ulstu/db/DbFileService.java +++ b/src/main/java/ru/ulstu/db/DbFileService.java @@ -86,7 +86,7 @@ public class DbFileService implements DbService { if (!isTimeSeriesSetExists(timeSeriesSet)) { addSet(timeSeriesSet.getKey()); } - BufferedWriter writer = new BufferedWriter(new FileWriter(Paths.get(getSetPath(timeSeriesSet).getAbsolutePath(), timeSeries.getName() + ".csv").toFile())); + BufferedWriter writer = new BufferedWriter(new FileWriter(Paths.get(getSetPath(timeSeriesSet).getAbsolutePath(), timeSeries.getKey() + ".csv").toFile())); writer.write(new UtilService().getTimeSeriesToDateValueString(timeSeries)); writer.close(); createMetaFile(timeSeriesSet, timeSeries); @@ -95,7 +95,7 @@ public class DbFileService implements DbService { private void createMetaFile(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException { TimeSeriesMeta timeSeriesMeta = new TimeSeriesMeta(timeSeries); new ObjectMapper() - .writeValue(Paths.get(getSetPath(timeSeriesSet).getAbsolutePath(), timeSeries.getName() + ".csv.meta") + .writeValue(Paths.get(getSetPath(timeSeriesSet).getAbsolutePath(), timeSeries.getKey() + ".csv.meta") .toFile(), timeSeriesMeta); } diff --git a/src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java b/src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java index d9082b7..56b6b34 100644 --- a/src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java +++ b/src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java @@ -21,7 +21,7 @@ public class TimeSeriesMeta { } public TimeSeriesMeta(TimeSeries timeSeries) { - this.key = timeSeries.getName(); + this.key = timeSeries.getKey(); this.hasDateTime = timeSeries.getValues().stream().anyMatch(v -> v.getDate() != null); this.size = timeSeries.getLength(); } diff --git a/src/main/java/ru/ulstu/method/Method.java b/src/main/java/ru/ulstu/method/Method.java index 4451eb1..d065945 100644 --- a/src/main/java/ru/ulstu/method/Method.java +++ b/src/main/java/ru/ulstu/method/Method.java @@ -98,7 +98,7 @@ public abstract class Method { protected TimeSeries generateEmptyForecastPoints(TimeSeries model, int countPointForecast) { long diffMilliseconds = TimeSeriesUtils.getTimeDifferenceInMilliseconds(model); - TimeSeries forecast = new TimeSeries("Forecast of " + model.getName()); + TimeSeries forecast = new TimeSeries("Forecast of " + model.getKey()); forecast.addValue(new TimeSeriesValue(model.getLastValue().getDate())); for (int i = 1; i < countPointForecast + 1; i++) { forecast.addValue(new TimeSeriesValue(forecast.getValues().get(i - 1).getDate().plus(diffMilliseconds, ChronoUnit.MILLIS))); diff --git a/src/main/java/ru/ulstu/page/IndexView.java b/src/main/java/ru/ulstu/page/IndexView.java deleted file mode 100644 index bfb4caa..0000000 --- a/src/main/java/ru/ulstu/page/IndexView.java +++ /dev/null @@ -1,144 +0,0 @@ -///* -// * 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.page; -// -//import org.primefaces.model.chart.AxisType; -//import org.primefaces.model.chart.DateAxis; -//import org.primefaces.model.chart.LegendPlacement; -//import org.primefaces.model.chart.LineChartModel; -//import org.primefaces.model.chart.LineChartSeries; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import org.springframework.beans.factory.annotation.Autowired; -//import ru.ulstu.datamodel.exception.ModelingException; -//import ru.ulstu.datamodel.ts.TimeSeries; -//import ru.ulstu.datamodel.ts.TimeSeriesValue; -//import ru.ulstu.db.DbService; -//import ru.ulstu.db.model.TimeSeriesMeta; -//import ru.ulstu.db.model.TimeSeriesSet; -//import ru.ulstu.service.TimeSeriesService; -//import ru.ulstu.service.UtilService; -// -//import javax.annotation.PostConstruct; -//import javax.faces.model.SelectItem; -//import javax.faces.view.ViewScoped; -//import javax.inject.Named; -//import java.io.IOException; -//import java.io.Serializable; -//import java.lang.reflect.InvocationTargetException; -//import java.time.format.DateTimeFormatter; -//import java.util.List; -//import java.util.concurrent.ExecutionException; -//import java.util.stream.Collectors; -// -//@Named -//@ViewScoped -//public class IndexView implements Serializable { -// private final static Logger LOG = LoggerFactory.getLogger(IndexView.class); -// -// @Autowired -// private transient TimeSeriesService timeSeriesService; -// -// @Autowired -// private transient DbService dbService; -// -// @Autowired -// private transient UtilService utilService; -// -// private LineChartModel model; -// private List timeSeriesMetas; -// private TimeSeriesMeta timeSeriesMeta; -// -// @PostConstruct -// public void init() throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException, IOException { -// timeSeriesMetas = dbService.getTimeSeriesMeta(new TimeSeriesSet("NN3")); -// timeSeriesMeta = timeSeriesMetas.get(0); -// createChart(); -// } -// -// private LineChartModel initLinearModel() throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException, IOException { -// LineChartModel model = new LineChartModel(); -// -// LineChartSeries series1 = new LineChartSeries(); -// series1.setLabel("Временной ряд"); -// -// TimeSeries timeSeries = dbService.getTimeSeries(new TimeSeriesSet("NN3"), timeSeriesMeta.getKey()); -// for (TimeSeriesValue value : timeSeries.getValues()) { -// series1.set(DateTimeFormatter.ISO_LOCAL_DATE.format(value.getDate()), value.getValue()); -// } -// -// LineChartSeries series2 = new LineChartSeries(); -// series2.setLabel("Сглаженный ряд"); -// try { -// TimeSeries smoothedTimeSeries = timeSeriesService.smoothTimeSeries(timeSeries); -// for (TimeSeriesValue value : smoothedTimeSeries.getValues()) { -// series2.set(DateTimeFormatter.ISO_LOCAL_DATE.format(value.getDate()), value.getValue()); -// } -// } catch (Exception ex) { -// LOG.warn(ex.getMessage()); -// } -// LineChartSeries series3 = new LineChartSeries(); -// series3.setLabel("Прогноз"); -// TimeSeries forecast = timeSeriesService.getForecast(timeSeries, 20).getTimeSeries(); -// for (TimeSeriesValue value : forecast.getValues()) { -// series3.set(DateTimeFormatter.ISO_LOCAL_DATE.format(value.getDate()), value.getValue()); -// } -// model.addSeries(series1); -// model.addSeries(series2); -// model.addSeries(series3); -// return model; -// } -// -// public void createChart() throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException, IOException { -// model = initLinearModel(); -// model.setTitle("Сглаживание временного ряда"); -// model.setLegendPosition("d"); -// model.setLegendPlacement(LegendPlacement.OUTSIDEGRID); -// DateAxis xAxis = new DateAxis("Time"); -// xAxis.setTickFormat("%#d %b %Y"); -// model.getAxes().put(AxisType.X, xAxis); -// } -// -// public LineChartModel getModel() { -// return model; -// } -// -// public List getTimeSeriesMetas() { -// return timeSeriesMetas; -// } -// -// public TimeSeriesMeta getTimeSeriesMeta() { -// return timeSeriesMeta; -// } -// -// public void setTimeSeriesMeta(String timeSeriesMeta) { -// System.out.println(timeSeriesMeta); -// try { -// createChart(); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// -// public void setTimeSeriesMeta(Object timeSeriesMeta) { -// System.out.println(timeSeriesMeta); -// try { -// createChart(); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// -// public void setTimeSeriesMeta(TimeSeriesMeta timeSeriesMeta) { -// System.out.println(timeSeriesMeta); -// try { -// createChart(); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -//} diff --git a/src/main/java/ru/ulstu/service/MethodParamBruteForce.java b/src/main/java/ru/ulstu/service/MethodParamBruteForce.java index a065c01..b78efce 100644 --- a/src/main/java/ru/ulstu/service/MethodParamBruteForce.java +++ b/src/main/java/ru/ulstu/service/MethodParamBruteForce.java @@ -48,7 +48,7 @@ public class MethodParamBruteForce { List results2 = new CopyOnWriteArrayList<>(); final int countPoints = (countPointsForecast > timeSeries.getLength()) ? timeSeries.getLength() / 3 : countPointsForecast; TimeSeries reducedTimeSeries = new TimeSeries(timeSeries.getValues().stream().limit(timeSeries.getLength() - countPoints).collect(Collectors.toList()), - "test part of " + timeSeries.getName()); + "test part of " + timeSeries.getKey()); Map tsValues = timeSeries.getValues().stream() .collect(Collectors.toMap(TimeSeriesValue::getDate, TimeSeriesValue::getValue)); @@ -60,7 +60,7 @@ public class MethodParamBruteForce { if (methodInstance.canMakeForecast(reducedTimeSeries, parametersValues, countPoints)) { results.add(executors.submit(() -> { TimeSeries forecast = methodInstance.getForecast(reducedTimeSeries, parametersValues, countPoints); - return new ModelingResult(forecast, + return new ModelingResult(forecast, null, parametersValues, scoreMethod.getScore(tsValues, forecast), methodInstance); @@ -81,6 +81,7 @@ public class MethodParamBruteForce { forecast.getValue(0).setValue(timeSeries.getNumericValue(timeSeries.getLength() - 1)); return new ModelingResult(forecast, + bestResult.getTimeSeries(), bestResult.getParamValues(), bestResult.getScore(), bestResult.getTimeSeriesMethod()); @@ -105,6 +106,7 @@ public class MethodParamBruteForce { results.add(executors.submit(() -> { Model model = methodInstance.getModel(timeSeries, parametersValues); return new ModelingResult(model.getTimeSeriesModel(), + null, parametersValues, scoreMethod.getScore(tsValues, model.getTimeSeriesModel()), methodInstance); diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html deleted file mode 100644 index 332137c..0000000 --- a/src/main/resources/templates/error.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - -
-

Ошибка

- -

- Страница: Page URL -

- -

- Время: Timestamp -

- -

- Response Status: status-code error ... -

-

- -

- - - - - - - - - - - - - -
- - \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index f6ee834..b69de47 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -14,7 +14,7 @@
- -
- +
-
+
+ + + + + +

Метод прогнозирования: +

Оценка: +

+
+
+