Merge pull request 'Add generation' (#97) from 96-generation into master

Reviewed-on: #97
This commit is contained in:
romanov73 2024-05-13 00:54:17 +04:00
commit c29650935c
16 changed files with 315 additions and 22 deletions

View File

@ -6,14 +6,7 @@ import ru.ulstu.extractor.commit.model.Commit;
import ru.ulstu.extractor.core.BaseEntity;
import ru.ulstu.extractor.gitrepository.model.GitRepository;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@ -21,6 +14,7 @@ import static ru.ulstu.extractor.branch.model.IndexingStatus.EMPTY;
@Entity
public class Branch extends BaseEntity {
public static Integer GENERATED_BRANCH_ID = 1;
private String name;
@ManyToOne

View File

@ -18,6 +18,8 @@ public class Route {
public static final String DELETE_RULE = "deleteRule";
public static final String ADD_MARKUP = "addMarkup";
public static final String GENERATION = "generation";
public static String getLIST_INDEXED_REPOSITORIES() {
return LIST_INDEXED_REPOSITORIES;
}
@ -45,4 +47,8 @@ public class Route {
public static String getADD_MARKUP() {
return ADD_MARKUP;
}
public static String getGENERATION() {
return GENERATION;
}
}

View File

@ -0,0 +1,35 @@
package ru.ulstu.extractor.generation.controller;
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 org.springframework.web.bind.annotation.PostMapping;
import ru.ulstu.extractor.generation.model.GenerationForm;
import ru.ulstu.extractor.generation.service.GenerationService;
import springfox.documentation.annotations.ApiIgnore;
import static ru.ulstu.extractor.core.Route.GENERATION;
@Controller
@ApiIgnore
public class GenerationController {
private final GenerationService generationService;
public GenerationController(GenerationService generationService) {
this.generationService = generationService;
}
@GetMapping(GENERATION)
public String getGenerationsPage(Model model) {
model.addAttribute("generationForm", new GenerationForm());
return GENERATION;
}
@PostMapping(GENERATION)
public String setGenerationParams(Model model, @ModelAttribute GenerationForm generationForm) {
model.addAttribute("generationForm", generationForm);
generationService.generate(generationForm);
return GENERATION;
}
}

View File

@ -0,0 +1,67 @@
package ru.ulstu.extractor.generation.model;
public class GenerationForm {
private int tsLength;
private double min;
private double max;
private double base;
private double baseTendency;
private double tendencyDynamic;
private double randomWeight;
public int getTsLength() {
return tsLength;
}
public void setTsLength(int tsLength) {
this.tsLength = tsLength;
}
public double getMin() {
return min;
}
public void setMin(double min) {
this.min = min;
}
public double getMax() {
return max;
}
public void setMax(double max) {
this.max = max;
}
public double getBase() {
return base;
}
public void setBase(double base) {
this.base = base;
}
public double getBaseTendency() {
return baseTendency;
}
public void setBaseTendency(double baseTendency) {
this.baseTendency = baseTendency;
}
public double getTendencyDynamic() {
return tendencyDynamic;
}
public void setTendencyDynamic(double tendencyDynamic) {
this.tendencyDynamic = tendencyDynamic;
}
public double getRandomWeight() {
return randomWeight;
}
public void setRandomWeight(double randomWeight) {
this.randomWeight = randomWeight;
}
}

View File

@ -0,0 +1,67 @@
package ru.ulstu.extractor.generation.service;
import org.springframework.stereotype.Service;
import ru.ulstu.extractor.branch.model.Branch;
import ru.ulstu.extractor.branch.service.BranchService;
import ru.ulstu.extractor.generation.model.GenerationForm;
import ru.ulstu.extractor.ts.model.TimeSeriesType;
import ru.ulstu.extractor.ts.model.TimeSeriesValue;
import ru.ulstu.extractor.ts.service.TimeSeriesService;
import ru.ulstu.extractor.ts.util.DateUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@Service
public class GenerationService {
private final TimeSeriesService timeSeriesService;
private final BranchService branchService;
public GenerationService(TimeSeriesService timeSeriesService,
BranchService branchService) {
this.timeSeriesService = timeSeriesService;
this.branchService = branchService;
}
public void generate(GenerationForm generationForm) {
Branch branch = branchService.findByBranchId(Branch.GENERATED_BRANCH_ID).orElseThrow();
Date startDate = DateUtils.addDays(-generationForm.getTsLength());
Arrays.stream(TimeSeriesType.values()).forEach(tsType -> {
List<TimeSeriesValue> tsValues = new ArrayList<>();
for (int i = 0; i < generationForm.getTsLength(); i++) {
tsValues.add(new TimeSeriesValue(DateUtils.addDays(startDate, i),
getNextAdditiveValue(tsValues, generationForm)));
}
final String tsName = "Генерированный " + tsType.getDescription();
timeSeriesService.save(tsName, branch, tsType, tsValues);
});
}
private double getNextAdditiveValue(List<TimeSeriesValue> timeSeriesValues, GenerationForm generationForm) {
double newValue;
int maxTryCount = 10;
do {
double oneStepDiff = generationForm.getRandomWeight() * (Math.random() - 0.5) * (generationForm.getMax() - generationForm.getMin()) / (generationForm.getTsLength() + 10);
if (timeSeriesValues.isEmpty()) {
if (generationForm.getBaseTendency() > 0) {
newValue = 0.1 * (generationForm.getRandomWeight() > 0.0 ? oneStepDiff : 1.0) * (generationForm.getMax() - generationForm.getMin());
} else if (generationForm.getBaseTendency() < 0) {
newValue = generationForm.getMax() - 0.1 * (generationForm.getRandomWeight() > 0.0 ? oneStepDiff : 1.0) * (generationForm.getMax() - generationForm.getMin());
} else {
newValue = generationForm.getBase();
}
} else {
newValue = timeSeriesValues.get(timeSeriesValues.size() - 1).getValue()
+ (generationForm.getRandomWeight() > 0.0 ? oneStepDiff : 1.0) * generationForm.getBaseTendency()
* ((generationForm.getMax() - generationForm.getMin()) / (generationForm.getTsLength() + 10))
* generationForm.getTendencyDynamic();
}
maxTryCount--;
} while (((newValue <= generationForm.getMin())
|| (newValue >= generationForm.getMax()))
&& (maxTryCount > 0));
return newValue;
}
}

View File

@ -7,8 +7,11 @@ import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.extractor.gitrepository.repository.GitRepositoryRepository;
import springfox.documentation.annotations.ApiIgnore;
import java.util.stream.Collectors;
import static ru.ulstu.extractor.core.Route.DELETE_INDEXED_REPOSITORY;
import static ru.ulstu.extractor.core.Route.LIST_INDEXED_REPOSITORIES;
import static ru.ulstu.extractor.gitrepository.model.GitRepository.GENERATED_REPOSITORY_ID;
@Controller
@ApiIgnore
@ -21,7 +24,10 @@ public class RepositoryController {
@GetMapping(LIST_INDEXED_REPOSITORIES)
public String indexNewRepo(Model model) {
model.addAttribute("repositories", gitRepositoryRepository.findAll());
model.addAttribute("repositories", gitRepositoryRepository.findAll()
.stream()
.filter(r -> !r.getId().equals(GENERATED_REPOSITORY_ID))
.collect(Collectors.toList()));
return LIST_INDEXED_REPOSITORIES;
}
@ -29,7 +35,10 @@ public class RepositoryController {
public String deleteRepo(Model model,
@RequestParam Integer id) {
gitRepositoryRepository.deleteById(id);
model.addAttribute("repositories", gitRepositoryRepository.findAll());
model.addAttribute("repositories", gitRepositoryRepository.findAll()
.stream()
.filter(r -> !r.getId().equals(GENERATED_REPOSITORY_ID))
.collect(Collectors.toList()));
return "redirect:/" + LIST_INDEXED_REPOSITORIES;
}
}

View File

@ -14,6 +14,7 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static ru.ulstu.extractor.branch.model.Branch.GENERATED_BRANCH_ID;
import static ru.ulstu.extractor.core.Route.STATISTIC;
@Controller
@ -60,7 +61,9 @@ public class StatisticController {
filterForm.setEntity(entity.orElse(null));
model.addAttribute("filterForm", filterForm);
model.addAttribute("entityPresent", filteringService.getEntityPresent());
model.addAttribute("branches", branchService.findAll());
model.addAttribute("branches", branchService.findAll().stream()
.filter(r -> !r.getId().equals(GENERATED_BRANCH_ID))
.collect(Collectors.toList()));
model.addAttribute("authors", filteringService.getRepositoryAuthors(branchId.orElse(null)));
return STATISTIC;
}

View File

@ -7,6 +7,8 @@ import javax.persistence.Entity;
@Entity
public class GitRepository extends BaseEntity {
public static Integer GENERATED_REPOSITORY_ID = 1;
private String url;
private String repositoryId;

View File

@ -14,6 +14,9 @@ import ru.ulstu.extractor.ts.service.TimeSeriesService;
import springfox.documentation.annotations.ApiIgnore;
import java.util.List;
import java.util.stream.Collectors;
import static ru.ulstu.extractor.branch.model.Branch.GENERATED_BRANCH_ID;
@Controller
@ApiIgnore
@ -32,14 +35,18 @@ public class TimeSeriesMarkupController {
@GetMapping("time-series-markup")
public String markupTs(Model model) {
model.addAttribute("branches", branchService.findAllValid());
model.addAttribute("branches", branchService.findAllValid().stream()
.filter(r -> !r.getId().equals(GENERATED_BRANCH_ID))
.collect(Collectors.toList()));
model.addAttribute("markupForm", new MarkupForm());
return "markup";
}
@PostMapping("time-series-markup")
public String filter(Model model, @ModelAttribute MarkupForm markupForm) {
model.addAttribute("branches", branchService.findAllValid());
model.addAttribute("branches", branchService.findAllValid().stream()
.filter(r -> !r.getId().equals(GENERATED_BRANCH_ID))
.collect(Collectors.toList()));
if (markupForm != null && markupForm.getBranchId() != null) {
List<TimeSeriesForMarkup> tss = markupService.getTimeSeriesForMarkup(
timeSeriesService.getGroupedTendencies(
@ -56,7 +63,9 @@ public class TimeSeriesMarkupController {
@PostMapping(Route.ADD_MARKUP)
public String addMarkups(Model model, @ModelAttribute MarkupForm markupForm) {
model.addAttribute("branches", branchService.findAllValid());
model.addAttribute("branches", branchService.findAllValid().stream()
.filter(r -> !r.getId().equals(GENERATED_BRANCH_ID))
.collect(Collectors.toList()));
if (markupForm != null && markupForm.getBranchId() != null) {
List<TimeSeriesForMarkup> tss = markupService.getTimeSeriesForMarkup(
timeSeriesService.getGroupedTendencies(

View File

@ -9,6 +9,9 @@ import ru.ulstu.extractor.branch.service.BranchService;
import ru.ulstu.extractor.ts.creator.scheduled.ScheduledTimeSeriesCreator;
import java.util.List;
import java.util.stream.Collectors;
import static ru.ulstu.extractor.branch.model.Branch.GENERATED_BRANCH_ID;
@Service
public class ScheduledTimeSeriesService {
@ -25,7 +28,10 @@ public class ScheduledTimeSeriesService {
@Scheduled(cron = "0 0 8 * * *")
public void addTimeSeriesPoints() {
log.info("Старт добавления новых точек временного ряда");
List<Branch> branches = branchService.findAll();
List<Branch> branches = branchService.findAll()
.stream()
.filter(b -> !b.getId().equals(GENERATED_BRANCH_ID))
.collect(Collectors.toList());
branches.forEach(branch -> {
scheduledTimeSeriesCreators.forEach(creator -> creator.addTimeSeriesValue(branch));
});

View File

@ -5,9 +5,16 @@ import java.util.Date;
import java.util.GregorianCalendar;
public class DateUtils {
public static Date addMonths(int amount) {
public static Date addDays(int amount) {
Calendar c = GregorianCalendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, amount);
return c.getTime();
}
public static Date addDays(Date startDate, int amount) {
Calendar c = GregorianCalendar.getInstance();
c.setTime(startDate);
c.add(Calendar.DAY_OF_MONTH, amount);
return c.getTime();
}
}

View File

@ -6,10 +6,10 @@ import java.util.List;
public class Dummy {
public static List<TimeSeriesValue> getDefaultTimeSeries (){
return List.of(new TimeSeriesValue(DateUtils.addMonths(-5), 1.0),
new TimeSeriesValue(DateUtils.addMonths(-4), 2.0),
new TimeSeriesValue(DateUtils.addMonths(-3), 3.0),
new TimeSeriesValue(DateUtils.addMonths(-2), 4.0),
new TimeSeriesValue(DateUtils.addMonths(-1), 5.0));
return List.of(new TimeSeriesValue(DateUtils.addDays(-5), 1.0),
new TimeSeriesValue(DateUtils.addDays(-4), 2.0),
new TimeSeriesValue(DateUtils.addDays(-3), 3.0),
new TimeSeriesValue(DateUtils.addDays(-2), 4.0),
new TimeSeriesValue(DateUtils.addDays(-1), 5.0));
}
}

View File

@ -46,4 +46,15 @@
</sql>
</changeSet>
<changeSet author="orion" id="20240510-210000-1">
<insert tableName="git_repository">
<column name="id">1</column>
<column name="url">Генерированный репозиторий</column>
</insert>
<insert tableName="branch">
<column name="id">1</column>
<column name="name">Сгенерированные показатели</column>
<column name="git_repository_id">1</column>
</insert>
</changeSet>
</databaseChangeLog>

View File

@ -3,7 +3,7 @@
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
<head>
<title>Простая обработка формы на Spring MVC</title>
<title>Оценка репозиториев</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">

View File

@ -38,6 +38,9 @@
<li class="nav-item">
<a class="nav-link" href="/listRules">Правила</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/generation">Синтетические данные</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/assessments">Рекомендации</a>
</li>

View File

@ -0,0 +1,74 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
<head>
<title>Генерация</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<form action="#" th:action="${@route.GENERATION}" th:object="${generationForm}" method="post">
<div class="row">
<div class="col-md-4 col-sm-12">
Длина временных рядов
</div>
<div class="col-md-6 col-sm-12">
<input type="text" class="form-control m-1" th:field="*{tsLength}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
Минимум
</div>
<div class="col-md-6 col-sm-12">
<input type="text" class="form-control m-1" th:field="*{min}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
Максимум
</div>
<div class="col-md-6 col-sm-12">
<input type="text" class="form-control m-1" th:field="*{max}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
Основное значение
</div>
<div class="col-md-6 col-sm-12">
<input type="text" class="form-control m-1" th:field="*{base}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
Основная тенденция
</div>
<div class="col-md-6 col-sm-12">
<input type="text" class="form-control m-1" th:field="*{baseTendency}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
Динамика тенденции
</div>
<div class="col-md-6 col-sm-12">
<input type="text" class="form-control m-1" th:field="*{tendencyDynamic}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
Величина шума
</div>
<div class="col-md-6 col-sm-12">
<input type="text" class="form-control m-1" th:field="*{randomWeight}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
<input type="submit" class="btn btn-outline-success form-control" value="Сгенерировать временные ряды"/>
</div>
</div>
</form>
</div>
</html>