Временные ряды #59
@ -48,6 +48,9 @@ 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-data-jpa'
|
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
|
||||||
|
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-webflux'
|
||||||
|
implementation group: 'org.json', name: 'json', version: '20220320'
|
||||||
|
|
||||||
implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect'
|
implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect'
|
||||||
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner'
|
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner'
|
||||||
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
|
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package ru.ulstu.extractor.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebClientConfiguration {
|
||||||
|
@Bean
|
||||||
|
public WebClient webClient(WebClient.Builder webClientBuilder) {
|
||||||
|
return webClientBuilder.build();
|
||||||
|
}
|
||||||
|
}
|
36
src/main/java/ru/ulstu/extractor/http/HttpService.java
Normal file
36
src/main/java/ru/ulstu/extractor/http/HttpService.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package ru.ulstu.extractor.http;
|
||||||
|
|
||||||
|
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.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class HttpService {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(HttpService.class);
|
||||||
|
private final WebClient client;
|
||||||
|
|
||||||
|
public HttpService(WebClient client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject post(String url, JSONObject postData) {
|
||||||
|
log.debug("Service call: {}", url);
|
||||||
|
JSONObject 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)
|
||||||
|
.block()).orElse("{response:\"empty\"}"));
|
||||||
|
log.debug("Service response: {}", response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
35
src/main/java/ru/ulstu/extractor/http/JsonTimeSeries.java
Normal file
35
src/main/java/ru/ulstu/extractor/http/JsonTimeSeries.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package ru.ulstu.extractor.http;
|
||||||
|
|
||||||
|
import ru.ulstu.extractor.model.TimeSeries;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class JsonTimeSeries {
|
||||||
|
private String name;
|
||||||
|
private List<JsonTimeSeriesValue> values;
|
||||||
|
|
||||||
|
public JsonTimeSeries(TimeSeries timeSeries) {
|
||||||
|
this.name = timeSeries.getName();
|
||||||
|
this.values = timeSeries.getValues()
|
||||||
|
.stream()
|
||||||
|
.map(JsonTimeSeriesValue::new)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<JsonTimeSeriesValue> getValues() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValues(List<JsonTimeSeriesValue> values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package ru.ulstu.extractor.http;
|
||||||
|
|
||||||
|
import ru.ulstu.extractor.model.TimeSeriesValue;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
|
public class JsonTimeSeriesValue {
|
||||||
|
private LocalDateTime date;
|
||||||
|
private Double value;
|
||||||
|
|
||||||
|
public JsonTimeSeriesValue(TimeSeriesValue timeSeriesValue) {
|
||||||
|
this.value = timeSeriesValue.getValue();
|
||||||
|
this.date = timeSeriesValue.getDate()
|
||||||
|
.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDate(LocalDateTime date) {
|
||||||
|
this.date = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Double value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
@ -6,17 +6,17 @@ import java.util.Date;
|
|||||||
@Entity
|
@Entity
|
||||||
public class TimeSeriesValue extends BaseEntity {
|
public class TimeSeriesValue extends BaseEntity {
|
||||||
private Date date;
|
private Date date;
|
||||||
private Integer value;
|
private Double value;
|
||||||
|
|
||||||
public TimeSeriesValue() {
|
public TimeSeriesValue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSeriesValue(Date date, Integer value) {
|
public TimeSeriesValue(Date date, Double value) {
|
||||||
this.date = date;
|
this.date = date;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSeriesValue(TimeSeries timeSeries, Date date, Integer value) {
|
public TimeSeriesValue(TimeSeries timeSeries, Date date, Double value) {
|
||||||
this.date = date;
|
this.date = date;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ public class TimeSeriesValue extends BaseEntity {
|
|||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getValue() {
|
public Double getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ public class TimeSeriesValue extends BaseEntity {
|
|||||||
this.date = date;
|
this.date = date;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(Integer value) {
|
public void setValue(Double value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,12 @@
|
|||||||
|
|
||||||
package ru.ulstu.extractor.service;
|
package ru.ulstu.extractor.service;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.ulstu.extractor.http.HttpService;
|
||||||
|
import ru.ulstu.extractor.http.JsonTimeSeries;
|
||||||
import ru.ulstu.extractor.model.TimeSeries;
|
import ru.ulstu.extractor.model.TimeSeries;
|
||||||
import ru.ulstu.extractor.model.TimeSeriesValue;
|
import ru.ulstu.extractor.model.TimeSeriesValue;
|
||||||
import ru.ulstu.extractor.repository.TimeSeriesRepository;
|
import ru.ulstu.extractor.repository.TimeSeriesRepository;
|
||||||
@ -28,10 +31,15 @@ public class TimeSeriesService {
|
|||||||
private final TimeSeriesRepository timeSeriesRepository;
|
private final TimeSeriesRepository timeSeriesRepository;
|
||||||
private final TimeSeriesValueRepository timeSeriesValueRepository;
|
private final TimeSeriesValueRepository timeSeriesValueRepository;
|
||||||
private final TimeSeriesDateMapper.TimeSeriesInterval timeSeriesInterval = TimeSeriesDateMapper.TimeSeriesInterval.HOUR;
|
private final TimeSeriesDateMapper.TimeSeriesInterval timeSeriesInterval = TimeSeriesDateMapper.TimeSeriesInterval.HOUR;
|
||||||
|
private final HttpService httpService;
|
||||||
|
private final static String TIME_SERIES_SERVICE_URL = "http://time-series.athene.tech/api/1.0/add-time-series?setKey=git-extractor";
|
||||||
|
|
||||||
public TimeSeriesService(TimeSeriesRepository timeSeriesRepository, TimeSeriesValueRepository timeSeriesValueRepository) {
|
public TimeSeriesService(TimeSeriesRepository timeSeriesRepository,
|
||||||
|
TimeSeriesValueRepository timeSeriesValueRepository,
|
||||||
|
HttpService httpService) {
|
||||||
this.timeSeriesRepository = timeSeriesRepository;
|
this.timeSeriesRepository = timeSeriesRepository;
|
||||||
this.timeSeriesValueRepository = timeSeriesValueRepository;
|
this.timeSeriesValueRepository = timeSeriesValueRepository;
|
||||||
|
this.httpService = httpService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,6 +67,7 @@ public class TimeSeriesService {
|
|||||||
TimeSeries savedTimeSeries = timeSeriesRepository.save(timeSeries);
|
TimeSeries savedTimeSeries = timeSeriesRepository.save(timeSeries);
|
||||||
LOG.debug("Clear {} time series values ", timeSeriesValuesToRemove.size());
|
LOG.debug("Clear {} time series values ", timeSeriesValuesToRemove.size());
|
||||||
timeSeriesValueRepository.deleteAll(timeSeriesValuesToRemove);
|
timeSeriesValueRepository.deleteAll(timeSeriesValuesToRemove);
|
||||||
|
sendToTimeSeriesService(savedTimeSeries);
|
||||||
return savedTimeSeries;
|
return savedTimeSeries;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +89,7 @@ public class TimeSeriesService {
|
|||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTimeSeriesValue(String timeSeriesName, Date date, Integer value) {
|
public void addTimeSeriesValue(String timeSeriesName, Date date, Double value) {
|
||||||
LOG.debug("Start add time series values to {} time series values ", timeSeriesName);
|
LOG.debug("Start add time series values to {} time series values ", timeSeriesName);
|
||||||
TimeSeries timeSeries = findOrCreate(timeSeriesName);
|
TimeSeries timeSeries = findOrCreate(timeSeriesName);
|
||||||
timeSeriesValueRepository.save(new TimeSeriesValue(timeSeries, date, value));
|
timeSeriesValueRepository.save(new TimeSeriesValue(timeSeries, date, value));
|
||||||
@ -93,4 +102,15 @@ public class TimeSeriesService {
|
|||||||
public TimeSeriesDateMapper.TimeSeriesInterval getTimeSeriesInterval() {
|
public TimeSeriesDateMapper.TimeSeriesInterval getTimeSeriesInterval() {
|
||||||
return timeSeriesInterval;
|
return timeSeriesInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendToTimeSeriesService(TimeSeries timeSeries) {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
httpService.post(TIME_SERIES_SERVICE_URL, new JSONObject(new JsonTimeSeries(timeSeries)));
|
||||||
|
LOG.debug("Успешно отправлен на сервис");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LOG.debug(ex.getMessage());
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public class CommitsTS extends AbstractTimeSeriesCreator {
|
|||||||
result.put(String.format("%s %s %s", getTimeSeriesName(), repositoryId, branchName),
|
result.put(String.format("%s %s %s", getTimeSeriesName(), repositoryId, branchName),
|
||||||
commitService.findByRepositoryIdAndName(repositoryId, branchName)
|
commitService.findByRepositoryIdAndName(repositoryId, branchName)
|
||||||
.stream()
|
.stream()
|
||||||
.map(c -> new TimeSeriesValue(c.getDate(), 1))
|
.map(c -> new TimeSeriesValue(c.getDate(), 1.0))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,10 @@ public class TimeSeriesDateMapper {
|
|||||||
.map(timeSeriesValue -> new TimeSeriesValue(trimTo(timeSeriesInterval, timeSeriesValue.getDate()),
|
.map(timeSeriesValue -> new TimeSeriesValue(trimTo(timeSeriesInterval, timeSeriesValue.getDate()),
|
||||||
timeSeriesValue.getValue()))
|
timeSeriesValue.getValue()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
Map<Date, Integer> groupedTimeSeriesValues = trimmedTimeSeriesValues
|
Map<Date, Double> groupedTimeSeriesValues = trimmedTimeSeriesValues
|
||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.groupingBy(TimeSeriesValue::getDate,
|
.collect(Collectors.groupingBy(TimeSeriesValue::getDate,
|
||||||
Collectors.summingInt(TimeSeriesValue::getValue)));
|
Collectors.summingDouble(TimeSeriesValue::getValue)));
|
||||||
|
|
||||||
return groupedTimeSeriesValues.entrySet()
|
return groupedTimeSeriesValues.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -11,4 +11,13 @@
|
|||||||
<changeSet author="orion" id="20221006-120000-1">
|
<changeSet author="orion" id="20221006-120000-1">
|
||||||
<dropNotNullConstraint tableName="time_series_value" columnName="time_series_id"/>
|
<dropNotNullConstraint tableName="time_series_value" columnName="time_series_id"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
<changeSet author="orion" id="20221006-120000-2">
|
||||||
|
<delete tableName="time_series_value"/>
|
||||||
|
<dropColumn tableName="time_series_value" columnName="value"/>
|
||||||
|
<addColumn tableName="time_series_value">
|
||||||
|
<column name="value" type="double">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
</changeSet>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
Loading…
Reference in New Issue
Block a user