3-ftransform-forecasting #5
@ -34,10 +34,12 @@ dependencies {
|
||||
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jetty'
|
||||
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf'
|
||||
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-test'
|
||||
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-webflux'
|
||||
implementation group: 'org.slf4j', name: 'slf4j-api', version: versionSLF4J
|
||||
implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '3.0.0'
|
||||
implementation group: 'org.javassist', name: 'javassist', version: '3.25.0-GA'
|
||||
implementation group: 'org.eclipse.jetty', name: 'jetty-servlet', version: versionJetty
|
||||
implementation group: 'org.json', name: 'json', version: '20220320'
|
||||
|
||||
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind'
|
||||
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations'
|
||||
|
@ -0,0 +1,14 @@
|
||||
package ru.ulstu.configuration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
@Configuration
|
||||
public class WebClientConfiguration {
|
||||
@Bean
|
||||
public WebClient webClient(WebClient.Builder webClientBuilder) {
|
||||
return webClientBuilder.build(); //contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
}
|
||||
}
|
40
src/main/java/ru/ulstu/controller/AnomalyController.java
Normal file
40
src/main/java/ru/ulstu/controller/AnomalyController.java
Normal file
@ -0,0 +1,40 @@
|
||||
package ru.ulstu.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
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.TimeSeriesSet;
|
||||
import ru.ulstu.estimate.CompressionMetricService;
|
||||
import ru.ulstu.service.UtilService;
|
||||
import ru.ulstu.target.AnomalyDifferenceSmoothed;
|
||||
import ru.ulstu.target.Target;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(ApiConfiguration.API_1_0)
|
||||
public class AnomalyController {
|
||||
|
||||
private final DbService dbService;
|
||||
private final Target target;
|
||||
|
||||
public AnomalyController(CompressionMetricService compressionMetricService, DbService dbService, AnomalyDifferenceSmoothed anomalyDifferenceSmoothed) {
|
||||
this.dbService = dbService;
|
||||
this.target = anomalyDifferenceSmoothed;
|
||||
}
|
||||
|
||||
@GetMapping ("getAnomalyAtDifferenceSmothed")
|
||||
@Operation(description = "Получить аномальные значения")
|
||||
public TimeSeries getAnomalyAtDifferenceSmothed(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException {
|
||||
var timeSeries = dbService.getTimeSeries(new TimeSeriesSet(setKey), timeSeriesKey);
|
||||
var timeSeriesResult = target.calculate(timeSeries);
|
||||
return timeSeriesResult;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package ru.ulstu.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
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.TimeSeriesSet;
|
||||
import ru.ulstu.estimate.CompressionMetricService;
|
||||
import ru.ulstu.service.PrometheusService;
|
||||
import ru.ulstu.service.UtilService;
|
||||
import ru.ulstu.target.AnomalyDifferenceSmoothed;
|
||||
import ru.ulstu.target.Target;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(ApiConfiguration.API_1_0)
|
||||
public class CompressionMetricController {
|
||||
|
||||
private final UtilService utilService;
|
||||
private final DbService dbService;
|
||||
private final PrometheusService prometheusService;
|
||||
private final CompressionMetricService compressionMetricService;
|
||||
private final Target target;
|
||||
|
||||
public CompressionMetricController(UtilService utilService, DbService dbService, PrometheusService prometheusService, CompressionMetricService compressionMetricService, AnomalyDifferenceSmoothed anomalyDifferenceSmoothed) {
|
||||
this.utilService = utilService;
|
||||
this.dbService = dbService;
|
||||
this.prometheusService = prometheusService;
|
||||
this.compressionMetricService = compressionMetricService;
|
||||
this.target = anomalyDifferenceSmoothed;
|
||||
}
|
||||
|
||||
@GetMapping("getMetricAtAnomaly")
|
||||
@Operation(description = "Получить метрику сжатия")
|
||||
public ResponseEntity<TimeSeries> getMetricAtAnomaly(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException {
|
||||
var timeSeries = dbService.getTimeSeries(new TimeSeriesSet(setKey), timeSeriesKey);
|
||||
var timeSeriesResult = compressionMetricService.getCompressionTimeSeries(timeSeries);
|
||||
return new ResponseEntity<>(timeSeriesResult, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("getMetricAtAnomalyOfRandom")
|
||||
@Operation(description = "Получить метрику сжатия")
|
||||
public ResponseEntity<TimeSeries> getMetricAtAnomalyOfRandom(@RequestParam("lenght") int len) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||
var timeSeries = utilService.getRandomTimeSeries(len);
|
||||
var timeSeriesResult = compressionMetricService.getCompressionTimeSeries(timeSeries);
|
||||
return new ResponseEntity<>(timeSeriesResult, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("getMetricAtAnomalyOfPrometheus")
|
||||
@Operation(description = "Получить метрику сжатия")
|
||||
public ResponseEntity<TimeSeries> getMetricAtAnomalyOfPrometheus(@RequestParam("query") String query) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||
var timeSeries = prometheusService.executionQueryRange(query);
|
||||
var timeSeriesResult = compressionMetricService.getCompressionTimeSeries(timeSeries);
|
||||
return new ResponseEntity<>(timeSeriesResult, HttpStatus.OK);
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class TimeSeries {
|
||||
@ -88,6 +89,20 @@ public class TimeSeries {
|
||||
throw new RuntimeException("Индекс выходит за границы временного ряда");
|
||||
}
|
||||
|
||||
public TimeSeriesValue getMax() {
|
||||
if ((values.size() > 0)) {
|
||||
return values.stream().max(Comparator.comparing(TimeSeriesValue::getValue)).get();
|
||||
}
|
||||
throw new RuntimeException("Временной ряд пустой");
|
||||
}
|
||||
|
||||
public TimeSeriesValue getMin() {
|
||||
if ((values.size() > 0)) {
|
||||
return values.stream().min(Comparator.comparing(TimeSeriesValue::getValue)).get();
|
||||
}
|
||||
throw new RuntimeException("Временной ряд пустой");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeSeries{" +
|
||||
|
@ -0,0 +1,93 @@
|
||||
package ru.ulstu.estimate;
|
||||
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.ulstu.datamodel.Model;
|
||||
import ru.ulstu.datamodel.ModelingResult;
|
||||
import ru.ulstu.datamodel.exception.ModelingException;
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||
import ru.ulstu.method.MethodParamValue;
|
||||
import ru.ulstu.method.ftransform.FTransform;
|
||||
import ru.ulstu.score.ScoreMethod;
|
||||
import ru.ulstu.service.MethodParamBruteForce;
|
||||
import ru.ulstu.service.TimeSeriesService;
|
||||
import ru.ulstu.service.UtilService;
|
||||
import ru.ulstu.target.AnomalyDifferenceSmoothed;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class CompressionMetricService {
|
||||
|
||||
private final int DEFAULT_THREAD_COUNT = 10;
|
||||
private final TimeSeriesService timeSeriesService;
|
||||
private final FTransform fTransform;
|
||||
private final MethodParamBruteForce methodParamBruteForce;
|
||||
private final UtilService utilService;
|
||||
private final ScoreMethod scoreMethod;
|
||||
|
||||
private final AnomalyDifferenceSmoothed anomalyDifferenceSmoothed;
|
||||
private final ExecutorService executors = Executors.newFixedThreadPool(DEFAULT_THREAD_COUNT);
|
||||
|
||||
public CompressionMetricService(TimeSeriesService timeSeriesService, FTransform fTransform, MethodParamBruteForce methodParamBruteForce, UtilService utilService, ScoreMethod scoreMethod, AnomalyDifferenceSmoothed anomalyDifferenceSmoothed) {
|
||||
this.timeSeriesService = timeSeriesService;
|
||||
this.fTransform = fTransform;
|
||||
this.methodParamBruteForce = methodParamBruteForce;
|
||||
this.utilService = utilService;
|
||||
this.scoreMethod = scoreMethod;
|
||||
this.anomalyDifferenceSmoothed = anomalyDifferenceSmoothed;
|
||||
}
|
||||
|
||||
public TimeSeries getCompressionTimeSeries(TimeSeries ts) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||
//ModelingResult modelingResult = timeSeriesService.smoothTimeSeries(ts, "FTransform");
|
||||
ModelingResult modelingResult = getCompressionTimeSeriesWithFTransform(ts);
|
||||
//var ts1 = fTransform.getForecast(ts, )
|
||||
var timeSeriesAnomalyResult = anomalyDifferenceSmoothed.calculate(modelingResult.getTimeSeries());
|
||||
var timeSeriesAnomaly = anomalyDifferenceSmoothed.calculate(ts);
|
||||
System.out.println(ts.getLength()+"\t"
|
||||
+timeSeriesAnomaly.getLength()+"\t"
|
||||
+Math.abs(timeSeriesAnomaly.getLength() - timeSeriesAnomalyResult.getLength())+"\t"
|
||||
+(double)modelingResult.getTimeSeries().getLength()/ts.getLength()+"\t"
|
||||
+modelingResult.getScore().getDoubleValue());
|
||||
System.out.println(timeSeriesAnomaly);
|
||||
System.out.println(timeSeriesAnomalyResult);
|
||||
System.out.println(utilService.getTimeSeriesToString(ts));
|
||||
System.out.println(utilService.getTimeSeriesToString(modelingResult.getTimeSeries()));
|
||||
return modelingResult.getTimeSeries();
|
||||
}
|
||||
|
||||
protected ModelingResult getCompressionTimeSeriesWithFTransform(TimeSeries timeSeries) throws ExecutionException, InterruptedException {
|
||||
List<Future<ModelingResult>> results = new ArrayList<>();
|
||||
List<ModelingResult> results2 = new CopyOnWriteArrayList<>();
|
||||
|
||||
Map<LocalDateTime, Double> tsValues = timeSeries.getValues().stream()
|
||||
.collect(Collectors.toMap(TimeSeriesValue::getDate, TimeSeriesValue::getValue,
|
||||
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
|
||||
|
||||
|
||||
List<List<MethodParamValue>> availableParametersValues = methodParamBruteForce.getAvailableParametersValues(timeSeries, fTransform.getAvailableParameters());
|
||||
for (List<MethodParamValue> parametersValues : availableParametersValues) {
|
||||
results.add(executors.submit(() -> {
|
||||
Model model = fTransform.getModel(timeSeries, parametersValues);
|
||||
return new ModelingResult(model.getTimeSeriesModel(),
|
||||
null,
|
||||
parametersValues,
|
||||
scoreMethod.getScore(tsValues, model.getTimeSeriesModel()), fTransform);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
for (Future<ModelingResult> futureModelingResult : results) {
|
||||
results2.add(futureModelingResult.get());
|
||||
}
|
||||
return results2.stream()
|
||||
.min(Comparator.comparing(modelingResult -> modelingResult.getScore().getDoubleValue()))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
}
|
11
src/main/java/ru/ulstu/http/HttpClientService.java
Normal file
11
src/main/java/ru/ulstu/http/HttpClientService.java
Normal file
@ -0,0 +1,11 @@
|
||||
package ru.ulstu.http;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class HttpClientService {
|
||||
|
||||
public void get(){
|
||||
|
||||
}
|
||||
}
|
66
src/main/java/ru/ulstu/http/WebClientService.java
Normal file
66
src/main/java/ru/ulstu/http/WebClientService.java
Normal file
@ -0,0 +1,66 @@
|
||||
package ru.ulstu.http;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class WebClientService {
|
||||
private final Logger log = LoggerFactory.getLogger(WebClientService.class);
|
||||
private final WebClient client;
|
||||
|
||||
public WebClientService(WebClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public JSONObject post(String url, JSONObject postData) {
|
||||
log.debug("Service call: {}", url);
|
||||
JSONObject response = null;
|
||||
try {
|
||||
response = new JSONObject(Optional.ofNullable(client
|
||||
.post()
|
||||
.uri(url)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(BodyInserters.fromValue(postData.toString()))
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.toFuture().get()).orElse("{response:\"empty\"}"));
|
||||
} catch (Exception e) {
|
||||
return new JSONObject("{response:\"empty\"}");
|
||||
}
|
||||
log.debug("Service response: {}", response);
|
||||
return response;
|
||||
}
|
||||
|
||||
public JSONArray get(String url) {
|
||||
log.debug("Service call: {}", url);
|
||||
try {
|
||||
String response = client
|
||||
.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofMinutes(1))
|
||||
.toFuture().get();
|
||||
if (response.startsWith("[")) {
|
||||
return new JSONArray(response);
|
||||
} else {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
jsonArray.put(0, new JSONObject(response));
|
||||
return jsonArray;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +1,21 @@
|
||||
package ru.ulstu.method.ftransform;
|
||||
|
||||
/**
|
||||
* Треугольная функция принадлежности
|
||||
* Базисная функция
|
||||
*/
|
||||
public class AComponent {
|
||||
private int start; // левая граница треугольника
|
||||
private int end; // правая граница треугольника
|
||||
private int top; // вершина треугольника
|
||||
private double start; // левая граница треугольника
|
||||
private double end; // правая граница треугольника
|
||||
private double top; // вершина треугольника
|
||||
|
||||
public int getStart() {
|
||||
public double getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public AComponent() {
|
||||
}
|
||||
|
||||
public AComponent(int start, int top, int end) {
|
||||
public AComponent(double start, double top, double end) {
|
||||
this.start = start;
|
||||
this.top = top;
|
||||
this.end = end;
|
||||
@ -26,19 +26,23 @@ public class AComponent {
|
||||
}
|
||||
|
||||
|
||||
public int getEnd() {
|
||||
public double getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(int end) {
|
||||
public void setEnd(double end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public int getTop() {
|
||||
public double getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public void setTop(int top) {
|
||||
public int getTopInt() {
|
||||
return (int) Math.round(top);
|
||||
}
|
||||
|
||||
public void setTop(double top) {
|
||||
this.top = top;
|
||||
}
|
||||
|
||||
@ -54,4 +58,9 @@ public class AComponent {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "start=" + start;
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,19 @@ package ru.ulstu.method.ftransform;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.ulstu.datamodel.Model;
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||
import ru.ulstu.method.Method;
|
||||
import ru.ulstu.method.MethodParamValue;
|
||||
import ru.ulstu.method.MethodParameter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class FTransform extends Method {
|
||||
private final static int NUMBER_OF_FUZZY_VALUES = 3;
|
||||
|
||||
@Override
|
||||
protected FTransformModel getModelOfValidTimeSeries(TimeSeries ts,
|
||||
@ -29,8 +34,8 @@ public class FTransform extends Method {
|
||||
sum1 += membership * ts.getNumericValue(j);
|
||||
sum2 += membership;
|
||||
}
|
||||
piecewiseLinearTrend.addValue(ts.getValue(aComponent.getTop()), sum1 / sum2);
|
||||
tsModel.addValue(ts.getValue(aComponent.getTop()), sum1 / sum2);
|
||||
piecewiseLinearTrend.addValue(ts.getValue(aComponent.getTopInt()), sum1 / sum2);
|
||||
tsModel.addValue(ts.getValue(aComponent.getTopInt()), sum1 / sum2);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
@ -41,27 +46,27 @@ public class FTransform extends Method {
|
||||
while (currentPoint < ts.getLength()) {
|
||||
int startPoint = (currentPoint == 0)
|
||||
? 0
|
||||
: piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop();
|
||||
AComponent bf = new AComponent(startPoint, currentPoint, (int) (currentPoint + Math.round(numberOfCoveredPoints / 2.0)));
|
||||
if (bf.getStart() < 0) {
|
||||
bf.setStart(0);
|
||||
: piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTopInt();
|
||||
AComponent aComponent = new AComponent(startPoint, currentPoint, (int) (currentPoint + Math.round(numberOfCoveredPoints / 2.0)));
|
||||
if (aComponent.getStart() < 0) {
|
||||
aComponent.setStart(0);
|
||||
}
|
||||
if (bf.getEnd() > ts.getLength() - 1) {
|
||||
bf.setEnd(ts.getLength() - 1);
|
||||
if (aComponent.getEnd() > ts.getLength() - 1) {
|
||||
aComponent.setEnd(ts.getLength() - 1);
|
||||
}
|
||||
|
||||
if (bf.getTop() > ts.getLength() - 1) {
|
||||
bf.setTop(ts.getLength() - 1);
|
||||
if (aComponent.getTop() > ts.getLength() - 1) {
|
||||
aComponent.setTop(ts.getLength() - 1);
|
||||
}
|
||||
|
||||
piecewiseLinearTrend.add(bf);
|
||||
piecewiseLinearTrend.add(aComponent);
|
||||
currentPoint += deltaForTriangle;
|
||||
}
|
||||
if (piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getEnd() != piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop()) {
|
||||
AComponent bf = new AComponent(piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop(),
|
||||
AComponent aComponent = new AComponent(piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop(),
|
||||
piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getEnd(),
|
||||
piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getEnd());
|
||||
piecewiseLinearTrend.add(bf);
|
||||
piecewiseLinearTrend.add(aComponent);
|
||||
}
|
||||
return piecewiseLinearTrend;
|
||||
}
|
||||
@ -69,6 +74,25 @@ public class FTransform extends Method {
|
||||
@Override
|
||||
protected TimeSeries getForecastWithValidParams(Model model, TimeSeries forecast) {
|
||||
FTransformModel fTransformModel = (FTransformModel) model;
|
||||
double minValue = fTransformModel.getPiecewiseLinearTrend().getValues().stream().map(TimeSeriesValue::getValue).min(Double::compareTo).orElse(0.0);
|
||||
double maxValue = fTransformModel.getPiecewiseLinearTrend().getValues().stream().map(TimeSeriesValue::getValue).max(Double::compareTo).orElse(0.0);
|
||||
List<AComponent> fuzzyValues = new ArrayList<>();
|
||||
double diff = (maxValue - minValue) / NUMBER_OF_FUZZY_VALUES;
|
||||
for (int i = 0; i < NUMBER_OF_FUZZY_VALUES; i++) {
|
||||
fuzzyValues.add(new AComponent(minValue + i * diff, minValue + i * diff + diff / 2, minValue + i * diff + diff));
|
||||
}
|
||||
List<AComponent> fuzzyTimeSeries = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < model.getTimeSeriesModel().getLength(); i++) {
|
||||
for (AComponent fuzzyValue : fuzzyValues) {
|
||||
if (model.getTimeSeriesModel().getValue(i).getValue() >= fuzzyValue.getStart()
|
||||
&& model.getTimeSeriesModel().getValue(i).getValue() <= fuzzyValue.getEnd()) {
|
||||
fuzzyTimeSeries.add(fuzzyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int t = 1; t < forecast.getLength(); t++) {
|
||||
forecast.getValues().get(t).setValue(fTransformModel.getPiecewiseLinearTrend().getLastValue().getValue());
|
||||
}
|
||||
@ -80,6 +104,16 @@ public class FTransform extends Method {
|
||||
return FTransformModel.getAvailableParameters();
|
||||
}
|
||||
|
||||
// private AComponent findFuzzyValueByPrevious(List<AComponent> fuzzyTimeSeries, AComponent currentFuzzyValue) {
|
||||
// Map<AComponent, Integer> mostFrequentValues = new HashMap<>();
|
||||
// for (int i = 0; i < fuzzyTimeSeries.size() - 1; i++) {
|
||||
// if (fuzzyTimeSeries.get(i).equals(currentFuzzyValue)) {
|
||||
// mostFrequentValues.put(fuzzyTimeSeries.get(i + 1), mostFrequentValues.getOrDefault(fuzzyTimeSeries.get(i + 1), 0) + 1);
|
||||
// }
|
||||
// }
|
||||
// mostFrequentValues.entrySet().stream()
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "F - преобразование";
|
||||
|
32
src/main/java/ru/ulstu/score/AnomalyCompressionScore.java
Normal file
32
src/main/java/ru/ulstu/score/AnomalyCompressionScore.java
Normal file
@ -0,0 +1,32 @@
|
||||
package ru.ulstu.score;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.ulstu.datamodel.exception.ModelingException;
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||
import ru.ulstu.target.AnomalyDifferenceSmoothed;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
@Component
|
||||
public class AnomalyCompressionScore extends ScoreMethod {
|
||||
|
||||
private final AnomalyDifferenceSmoothed anomalyDifferenceSmoothed;
|
||||
public AnomalyCompressionScore(AnomalyDifferenceSmoothed anomalyDifferenceSmoothed) {
|
||||
super("Smape, %");
|
||||
this.anomalyDifferenceSmoothed = anomalyDifferenceSmoothed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(Map<LocalDateTime, Double> tsValues, TimeSeries model) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||
var timeSeriesAnomalyResult = anomalyDifferenceSmoothed.calculate(model);
|
||||
var timeSeriesAnomaly = anomalyDifferenceSmoothed.calculate(tsValues);
|
||||
// туду: добавить сравнение аномальных точек
|
||||
return (double)model.getLength()/tsValues.size() + Math.abs(timeSeriesAnomaly.getLength() - timeSeriesAnomalyResult.getLength());
|
||||
}
|
||||
}
|
@ -5,9 +5,11 @@ import ru.ulstu.datamodel.exception.ModelingException;
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public abstract class ScoreMethod {
|
||||
private final String name;
|
||||
@ -16,11 +18,11 @@ public abstract class ScoreMethod {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Score getScore(Map<LocalDateTime, Double> tsValues, TimeSeries model) throws ModelingException {
|
||||
public Score getScore(Map<LocalDateTime, Double> tsValues, TimeSeries model) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||
return new Score(this, evaluate(tsValues, model));
|
||||
}
|
||||
|
||||
public abstract Number evaluate(Map<LocalDateTime, Double> tsValues, TimeSeries model) throws ModelingException;
|
||||
public abstract Number evaluate(Map<LocalDateTime, Double> tsValues, TimeSeries model) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
|
@ -28,7 +28,7 @@ import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
class MethodParamBruteForce {
|
||||
public class MethodParamBruteForce {
|
||||
private final int DEFAULT_THREAD_COUNT = 50;
|
||||
private final List<Method> methods;
|
||||
private final ScoreMethod scoreMethod = new Smape();
|
||||
@ -175,7 +175,7 @@ class MethodParamBruteForce {
|
||||
return getSmoothedTimeSeries(timeSeries, methods);
|
||||
}
|
||||
|
||||
private List<List<MethodParamValue>> getAvailableParametersValues(TimeSeries timeSeries, List<MethodParameter> availableParameters) {
|
||||
public List<List<MethodParamValue>> getAvailableParametersValues(TimeSeries timeSeries, List<MethodParameter> availableParameters) {
|
||||
List<List<MethodParamValue>> result = new ArrayList<>();
|
||||
Map<MethodParameter, Integer> parameterOffset = new TreeMap<>();
|
||||
Map<MethodParameter, List<Number>> parameterValues = new TreeMap<>();
|
||||
|
87
src/main/java/ru/ulstu/service/PrometheusService.java
Normal file
87
src/main/java/ru/ulstu/service/PrometheusService.java
Normal file
@ -0,0 +1,87 @@
|
||||
package ru.ulstu.service;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||
import ru.ulstu.http.WebClientService;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Service
|
||||
public class PrometheusService {
|
||||
|
||||
private static final String PROMETHEUS_API_URL = "http://prometheus.athene.tech/api/v1/";
|
||||
private final WebClientService httpService;
|
||||
|
||||
public PrometheusService(WebClientService httpService) {
|
||||
this.httpService = httpService;
|
||||
}
|
||||
|
||||
public TimeSeries executionQuery(String query){ // example: pve_cpu_usage_ratio{id="lxc/111"}[5h]
|
||||
var timeSeries = new TimeSeries();
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(PROMETHEUS_API_URL + "query")
|
||||
.queryParam("query",
|
||||
"pve_cpu_usage_ratio{id='lxc/111'}[1h]");
|
||||
|
||||
var response = httpService.get(PROMETHEUS_API_URL + "query?query=" + query);
|
||||
if (response.getJSONObject(0).getString("status").equals("success")){
|
||||
|
||||
}
|
||||
return timeSeries;
|
||||
}
|
||||
|
||||
public TimeSeries executionQueryPost(String query){ // example: pve_cpu_usage_ratio{id="lxc/111"}[5h]
|
||||
var timeSeries = new TimeSeries();
|
||||
var postData = new JSONObject();
|
||||
postData.put("query", query);
|
||||
var response = httpService.post(PROMETHEUS_API_URL + "query", postData);
|
||||
// if (response.getJSONObject(0).getString("status").equals("success")){
|
||||
//
|
||||
// }
|
||||
return timeSeries;
|
||||
}
|
||||
|
||||
public TimeSeries executionQueryRange(String query){
|
||||
int numberTimeSeries = 14;
|
||||
var nowDateTime = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS);
|
||||
var timeSeries = new TimeSeries();
|
||||
var response = httpService.get(PROMETHEUS_API_URL + "query_range?query=" + query +
|
||||
"&start=" + nowDateTime.minusHours(10).minusMinutes(100).toString()+".004Z" +
|
||||
"&end=" + nowDateTime.minusHours(10).toString()+".004Z" +
|
||||
"&step=15s");
|
||||
var array = response.getJSONObject(0).getJSONObject("data").getJSONArray("result").getJSONObject(numberTimeSeries).getJSONArray("values").toList();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
BigDecimal seconds = (BigDecimal)(((ArrayList) array.get(i)).get(0));
|
||||
Double value = Double.parseDouble((String)(((ArrayList) array.get(i)).get(1)));
|
||||
LocalDateTime dateTime =
|
||||
LocalDateTime.ofInstant(Instant.ofEpochSecond(seconds.longValue()), ZoneId.systemDefault());
|
||||
timeSeries.addValue(new TimeSeriesValue(dateTime, value));
|
||||
}
|
||||
return timeSeries;
|
||||
}
|
||||
|
||||
public TimeSeries executionQueryRangePost(String query){
|
||||
var timeSeries = new TimeSeries();
|
||||
var postData = new JSONObject();
|
||||
postData.put("query", query);
|
||||
postData.put("start", "2023-04-06T00:00:00.004Z");
|
||||
postData.put("end", "2023-04-07T00:00:00.004Z");
|
||||
postData.put("step", "15s");
|
||||
|
||||
var response = httpService.post(PROMETHEUS_API_URL + "query_range", postData);
|
||||
// response.getJSONObject();
|
||||
// if (response.getJSONObject(0).getString("status").equals("success")){
|
||||
// var array = response.getJSONObject(0).getJSONObject("data").getJSONArray("result");
|
||||
// int a = 5;
|
||||
// }
|
||||
return timeSeries;
|
||||
}
|
||||
|
||||
}
|
17
src/main/java/ru/ulstu/target/AnomalyDecompose.java
Normal file
17
src/main/java/ru/ulstu/target/AnomalyDecompose.java
Normal file
@ -0,0 +1,17 @@
|
||||
package ru.ulstu.target;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
|
||||
@Service
|
||||
public class AnomalyDecompose extends Target {
|
||||
public AnomalyDecompose() {
|
||||
super("Разложение");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSeries calculate(TimeSeries model) {
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
46
src/main/java/ru/ulstu/target/AnomalyDifferenceSmoothed.java
Normal file
46
src/main/java/ru/ulstu/target/AnomalyDifferenceSmoothed.java
Normal file
@ -0,0 +1,46 @@
|
||||
package ru.ulstu.target;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.ulstu.datamodel.ModelingResult;
|
||||
import ru.ulstu.datamodel.exception.ModelingException;
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||
import ru.ulstu.service.TimeSeriesService;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@Service
|
||||
public class AnomalyDifferenceSmoothed extends Target {
|
||||
|
||||
private final TimeSeriesService timeSeriesService;
|
||||
|
||||
public AnomalyDifferenceSmoothed(TimeSeriesService timeSeriesService) {
|
||||
super("Модель сравнения со сглаженным ВР");
|
||||
this.timeSeriesService = timeSeriesService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSeries calculate(TimeSeries timeSeries) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||
TimeSeries residual = new TimeSeries();
|
||||
TimeSeries anomalyPoints = new TimeSeries();
|
||||
|
||||
TimeSeries timeSeriesSmooth = timeSeriesService.smoothTimeSeries(timeSeries, "AddTrendAddSeason").getTimeSeries();
|
||||
|
||||
for (int i = 0; i < timeSeries.getLength(); i++) {
|
||||
residual.addValue(new TimeSeriesValue(timeSeries.getValue(i).getDate(),
|
||||
Math.abs(timeSeries.getNumericValue(i) - timeSeriesSmooth.getNumericValue(i))));
|
||||
}
|
||||
|
||||
double diff = timeSeries.getMax().getValue()-timeSeries.getMin().getValue();
|
||||
|
||||
for (int i = 0; i < residual.getLength(); i++) {
|
||||
if (residual.getNumericValue(i)/diff > 0.05) {
|
||||
anomalyPoints.addValue(new TimeSeriesValue(residual.getValue(i).getDate(),
|
||||
timeSeries.getNumericValue(i)));
|
||||
}
|
||||
}
|
||||
|
||||
return anomalyPoints;
|
||||
}
|
||||
}
|
14
src/main/java/ru/ulstu/target/AnomalyPredictive.java
Normal file
14
src/main/java/ru/ulstu/target/AnomalyPredictive.java
Normal file
@ -0,0 +1,14 @@
|
||||
package ru.ulstu.target;
|
||||
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
|
||||
public class AnomalyPredictive extends Target {
|
||||
public AnomalyPredictive() {
|
||||
super("Прогнозная модель, %");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSeries calculate(TimeSeries model) {
|
||||
return null;
|
||||
}
|
||||
}
|
32
src/main/java/ru/ulstu/target/Target.java
Normal file
32
src/main/java/ru/ulstu/target/Target.java
Normal file
@ -0,0 +1,32 @@
|
||||
package ru.ulstu.target;
|
||||
|
||||
import ru.ulstu.datamodel.exception.ModelingException;
|
||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public abstract class Target {
|
||||
private final String name;
|
||||
|
||||
public Target(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public abstract TimeSeries calculate(TimeSeries model) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException;
|
||||
|
||||
public TimeSeries calculate(Map<LocalDateTime, Double> values) throws ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||
TimeSeries model = new TimeSeries();
|
||||
for (var entry : values.entrySet()) {
|
||||
model.addValue(new TimeSeriesValue(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return calculate(model);
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ spring.main.banner-mode=off
|
||||
logging.level.tech.athene=DEBUG
|
||||
server.port=8080
|
||||
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
|
||||
spring.codec.max-in-memory-size=50MB
|
||||
joinfaces.primefaces.theme=afterwork
|
||||
joinfaces.primefaces.font-awesome=true
|
||||
time-series.db-path=time-series-db
|
||||
|
Loading…
Reference in New Issue
Block a user