3-ftransform-forecasting #5

Open
romanov73 wants to merge 27 commits from 3-f-transform into master
19 changed files with 605 additions and 27 deletions

View File

@ -34,10 +34,12 @@ dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jetty' 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-thymeleaf'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-test' 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: 'org.slf4j', name: 'slf4j-api', version: versionSLF4J
implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '3.0.0' 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.javassist', name: 'javassist', version: '3.25.0-GA'
implementation group: 'org.eclipse.jetty', name: 'jetty-servlet', version: versionJetty 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-databind'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations'

View File

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

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

View File

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

View File

@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
public class TimeSeries { public class TimeSeries {
@ -88,6 +89,20 @@ public class TimeSeries {
throw new RuntimeException("Индекс выходит за границы временного ряда"); 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 @Override
public String toString() { public String toString() {
return "TimeSeries{" + return "TimeSeries{" +

View File

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

View File

@ -0,0 +1,11 @@
package ru.ulstu.http;
import org.springframework.stereotype.Service;
@Service
public class HttpClientService {
public void get(){
}
}

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

View File

@ -1,21 +1,21 @@
package ru.ulstu.method.ftransform; package ru.ulstu.method.ftransform;
/** /**
* Треугольная функция принадлежности * Базисная функция
*/ */
public class AComponent { public class AComponent {
private int start; // левая граница треугольника private double start; // левая граница треугольника
private int end; // правая граница треугольника private double end; // правая граница треугольника
private int top; // вершина треугольника private double top; // вершина треугольника
public int getStart() { public double getStart() {
return start; return start;
} }
public AComponent() { public AComponent() {
} }
public AComponent(int start, int top, int end) { public AComponent(double start, double top, double end) {
this.start = start; this.start = start;
this.top = top; this.top = top;
this.end = end; this.end = end;
@ -26,19 +26,23 @@ public class AComponent {
} }
public int getEnd() { public double getEnd() {
return end; return end;
} }
public void setEnd(int end) { public void setEnd(double end) {
this.end = end; this.end = end;
} }
public int getTop() { public double getTop() {
return top; return top;
} }
public void setTop(int top) { public int getTopInt() {
return (int) Math.round(top);
}
public void setTop(double top) {
this.top = top; this.top = top;
} }
@ -54,4 +58,9 @@ public class AComponent {
} }
return 0; return 0;
} }
@Override
public String toString() {
return "start=" + start;
}
} }

View File

@ -3,14 +3,19 @@ package ru.ulstu.method.ftransform;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.ulstu.datamodel.Model; import ru.ulstu.datamodel.Model;
import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.datamodel.ts.TimeSeriesValue;
import ru.ulstu.method.Method; import ru.ulstu.method.Method;
import ru.ulstu.method.MethodParamValue; import ru.ulstu.method.MethodParamValue;
import ru.ulstu.method.MethodParameter; import ru.ulstu.method.MethodParameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@Component @Component
public class FTransform extends Method { public class FTransform extends Method {
private final static int NUMBER_OF_FUZZY_VALUES = 3;
@Override @Override
protected FTransformModel getModelOfValidTimeSeries(TimeSeries ts, protected FTransformModel getModelOfValidTimeSeries(TimeSeries ts,
@ -29,8 +34,8 @@ public class FTransform extends Method {
sum1 += membership * ts.getNumericValue(j); sum1 += membership * ts.getNumericValue(j);
sum2 += membership; sum2 += membership;
} }
piecewiseLinearTrend.addValue(ts.getValue(aComponent.getTop()), sum1 / sum2); piecewiseLinearTrend.addValue(ts.getValue(aComponent.getTopInt()), sum1 / sum2);
tsModel.addValue(ts.getValue(aComponent.getTop()), sum1 / sum2); tsModel.addValue(ts.getValue(aComponent.getTopInt()), sum1 / sum2);
} }
return model; return model;
} }
@ -41,27 +46,27 @@ public class FTransform extends Method {
while (currentPoint < ts.getLength()) { while (currentPoint < ts.getLength()) {
int startPoint = (currentPoint == 0) int startPoint = (currentPoint == 0)
? 0 ? 0
: piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop(); : piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTopInt();
AComponent bf = new AComponent(startPoint, currentPoint, (int) (currentPoint + Math.round(numberOfCoveredPoints / 2.0))); AComponent aComponent = new AComponent(startPoint, currentPoint, (int) (currentPoint + Math.round(numberOfCoveredPoints / 2.0)));
if (bf.getStart() < 0) { if (aComponent.getStart() < 0) {
bf.setStart(0); aComponent.setStart(0);
} }
if (bf.getEnd() > ts.getLength() - 1) { if (aComponent.getEnd() > ts.getLength() - 1) {
bf.setEnd(ts.getLength() - 1); aComponent.setEnd(ts.getLength() - 1);
} }
if (bf.getTop() > ts.getLength() - 1) { if (aComponent.getTop() > ts.getLength() - 1) {
bf.setTop(ts.getLength() - 1); aComponent.setTop(ts.getLength() - 1);
} }
piecewiseLinearTrend.add(bf); piecewiseLinearTrend.add(aComponent);
currentPoint += deltaForTriangle; currentPoint += deltaForTriangle;
} }
if (piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getEnd() != piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop()) { 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.get(piecewiseLinearTrend.size() - 1).getEnd()); piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getEnd());
piecewiseLinearTrend.add(bf); piecewiseLinearTrend.add(aComponent);
} }
return piecewiseLinearTrend; return piecewiseLinearTrend;
} }
@ -69,6 +74,25 @@ public class FTransform extends Method {
@Override @Override
protected TimeSeries getForecastWithValidParams(Model model, TimeSeries forecast) { protected TimeSeries getForecastWithValidParams(Model model, TimeSeries forecast) {
FTransformModel fTransformModel = (FTransformModel) model; 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++) { for (int t = 1; t < forecast.getLength(); t++) {
forecast.getValues().get(t).setValue(fTransformModel.getPiecewiseLinearTrend().getLastValue().getValue()); forecast.getValues().get(t).setValue(fTransformModel.getPiecewiseLinearTrend().getLastValue().getValue());
} }
@ -80,6 +104,16 @@ public class FTransform extends Method {
return FTransformModel.getAvailableParameters(); 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 @Override
public String getName() { public String getName() {
return "F - преобразование"; return "F - преобразование";

View 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());
}
}

View File

@ -5,9 +5,11 @@ import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.datamodel.ts.TimeSeriesValue; import ru.ulstu.datamodel.ts.TimeSeriesValue;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException;
public abstract class ScoreMethod { public abstract class ScoreMethod {
private final String name; private final String name;
@ -16,11 +18,11 @@ public abstract class ScoreMethod {
this.name = name; 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)); 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() { public String getName() {
return name; return name;

View File

@ -28,7 +28,7 @@ import java.util.concurrent.Future;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
class MethodParamBruteForce { public class MethodParamBruteForce {
private final int DEFAULT_THREAD_COUNT = 50; private final int DEFAULT_THREAD_COUNT = 50;
private final List<Method> methods; private final List<Method> methods;
private final ScoreMethod scoreMethod = new Smape(); private final ScoreMethod scoreMethod = new Smape();
@ -175,7 +175,7 @@ class MethodParamBruteForce {
return getSmoothedTimeSeries(timeSeries, methods); 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<>(); List<List<MethodParamValue>> result = new ArrayList<>();
Map<MethodParameter, Integer> parameterOffset = new TreeMap<>(); Map<MethodParameter, Integer> parameterOffset = new TreeMap<>();
Map<MethodParameter, List<Number>> parameterValues = new TreeMap<>(); Map<MethodParameter, List<Number>> parameterValues = new TreeMap<>();

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

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

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

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

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

View File

@ -2,6 +2,7 @@ spring.main.banner-mode=off
logging.level.tech.athene=DEBUG logging.level.tech.athene=DEBUG
server.port=8080 server.port=8080
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
spring.codec.max-in-memory-size=50MB
joinfaces.primefaces.theme=afterwork joinfaces.primefaces.theme=afterwork
joinfaces.primefaces.font-awesome=true joinfaces.primefaces.font-awesome=true
time-series.db-path=time-series-db time-series.db-path=time-series-db