diff --git a/src/main/java/ru/ulstu/extractor/recommendation/controller/RecommendationController.java b/src/main/java/ru/ulstu/extractor/assessment/controller/AssessmentController.java similarity index 60% rename from src/main/java/ru/ulstu/extractor/recommendation/controller/RecommendationController.java rename to src/main/java/ru/ulstu/extractor/assessment/controller/AssessmentController.java index 4c0f803..3e3d3cc 100644 --- a/src/main/java/ru/ulstu/extractor/recommendation/controller/RecommendationController.java +++ b/src/main/java/ru/ulstu/extractor/assessment/controller/AssessmentController.java @@ -1,39 +1,39 @@ -package ru.ulstu.extractor.recommendation.controller; +package ru.ulstu.extractor.assessment.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; +import ru.ulstu.extractor.assessment.model.FilterBranchForm; import ru.ulstu.extractor.branch.service.BranchService; -import ru.ulstu.extractor.recommendation.model.FilterBranchForm; import ru.ulstu.extractor.rule.service.FuzzyInferenceService; import springfox.documentation.annotations.ApiIgnore; import java.util.Optional; -import static ru.ulstu.extractor.core.Route.RECOMMENDATIONS; +import static ru.ulstu.extractor.core.Route.ASSESSMENTS; @Controller @ApiIgnore -public class RecommendationController { +public class AssessmentController { private final FuzzyInferenceService fuzzyInferenceService; private final BranchService branchService; - public RecommendationController(FuzzyInferenceService fuzzyInferenceService, - BranchService branchService) { + public AssessmentController(FuzzyInferenceService fuzzyInferenceService, + BranchService branchService) { this.fuzzyInferenceService = fuzzyInferenceService; this.branchService = branchService; } - @GetMapping(RECOMMENDATIONS) - public String getRecommendations(Model model, @RequestParam Optional branchId) { + @GetMapping(ASSESSMENTS) + public String getAssessments(Model model, @RequestParam Optional branchId) { model.addAttribute("branches", branchService.findAll()); if (branchId.isPresent()) { - model.addAttribute("recommendations", fuzzyInferenceService.getRecommendations(branchId.get())); + model.addAttribute("assessments", fuzzyInferenceService.getAssessmentsByForecastTendencies(branchId.get())); model.addAttribute("filterBranchForm", new FilterBranchForm(branchId.get())); } else { model.addAttribute("filterBranchForm", new FilterBranchForm()); } - return RECOMMENDATIONS; + return ASSESSMENTS; } } diff --git a/src/main/java/ru/ulstu/extractor/assessment/model/Assessment.java b/src/main/java/ru/ulstu/extractor/assessment/model/Assessment.java new file mode 100644 index 0000000..f6609b4 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/assessment/model/Assessment.java @@ -0,0 +1,40 @@ +package ru.ulstu.extractor.assessment.model; + +import ru.ulstu.extractor.rule.model.DbRule; +import ru.ulstu.extractor.ts.model.TimeSeriesType; + +public class Assessment { + private final String consequent; + private final TimeSeriesType firstAntecedent; + private final String firstAntecedentTendency; + private final TimeSeriesType secondAntecedent; + private final String secondAntecedentTendency; + + public Assessment(DbRule dbRule) { + this.consequent = dbRule.getConsequent(); + this.firstAntecedent = dbRule.getFirstAntecedent(); + this.firstAntecedentTendency = dbRule.getFirstAntecedentValue().getAntecedentValue(); + this.secondAntecedent = dbRule.getSecondAntecedent(); + this.secondAntecedentTendency = dbRule.getSecondAntecedentValue().getAntecedentValue(); + } + + public String getConsequent() { + return consequent; + } + + public TimeSeriesType getFirstAntecedent() { + return firstAntecedent; + } + + public String getFirstAntecedentTendency() { + return firstAntecedentTendency; + } + + public TimeSeriesType getSecondAntecedent() { + return secondAntecedent; + } + + public String getSecondAntecedentTendency() { + return secondAntecedentTendency; + } +} diff --git a/src/main/java/ru/ulstu/extractor/recommendation/model/FilterBranchForm.java b/src/main/java/ru/ulstu/extractor/assessment/model/FilterBranchForm.java similarity index 87% rename from src/main/java/ru/ulstu/extractor/recommendation/model/FilterBranchForm.java rename to src/main/java/ru/ulstu/extractor/assessment/model/FilterBranchForm.java index 0d331c3..280727b 100644 --- a/src/main/java/ru/ulstu/extractor/recommendation/model/FilterBranchForm.java +++ b/src/main/java/ru/ulstu/extractor/assessment/model/FilterBranchForm.java @@ -1,4 +1,4 @@ -package ru.ulstu.extractor.recommendation.model; +package ru.ulstu.extractor.assessment.model; public class FilterBranchForm { private Integer branchId; diff --git a/src/main/java/ru/ulstu/extractor/core/Route.java b/src/main/java/ru/ulstu/extractor/core/Route.java index 614bd69..be9cb53 100644 --- a/src/main/java/ru/ulstu/extractor/core/Route.java +++ b/src/main/java/ru/ulstu/extractor/core/Route.java @@ -19,7 +19,7 @@ public class Route { public static final String STATISTIC = "statistic"; public static final String LIST_RULE = "listRules"; public static final String ADD_RULE = "addRule"; - public static final String RECOMMENDATIONS = "recommendations"; + public static final String ASSESSMENTS = "assessments"; public static final String DELETE_RULE = "deleteRule"; public static String getLIST_INDEXED_REPOSITORIES() { @@ -42,7 +42,7 @@ public class Route { return STATISTIC; } - public static String getRECOMMENDATIONS() { - return RECOMMENDATIONS; + public static String getASSESSMENTS() { + return ASSESSMENTS; } } diff --git a/src/main/java/ru/ulstu/extractor/rule/model/AssessmentException.java b/src/main/java/ru/ulstu/extractor/rule/model/AssessmentException.java new file mode 100644 index 0000000..d021db6 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/rule/model/AssessmentException.java @@ -0,0 +1,7 @@ +package ru.ulstu.extractor.rule.model; + +public class AssessmentException extends RuntimeException { + public AssessmentException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/ulstu/extractor/rule/service/FuzzyInferenceService.java b/src/main/java/ru/ulstu/extractor/rule/service/FuzzyInferenceService.java index 706f55c..9d8bc86 100644 --- a/src/main/java/ru/ulstu/extractor/rule/service/FuzzyInferenceService.java +++ b/src/main/java/ru/ulstu/extractor/rule/service/FuzzyInferenceService.java @@ -12,16 +12,20 @@ import com.fuzzylite.term.Triangle; import com.fuzzylite.variable.InputVariable; import com.fuzzylite.variable.OutputVariable; import org.springframework.stereotype.Service; +import ru.ulstu.extractor.assessment.model.Assessment; import ru.ulstu.extractor.gitrepository.service.GitRepositoryService; import ru.ulstu.extractor.rule.model.AntecedentValue; +import ru.ulstu.extractor.rule.model.AssessmentException; import ru.ulstu.extractor.rule.model.DbRule; import ru.ulstu.extractor.ts.model.TimeSeries; import ru.ulstu.extractor.ts.service.TimeSeriesService; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; @Service public class FuzzyInferenceService { @@ -29,6 +33,7 @@ public class FuzzyInferenceService { private final static String RULE_TEMPLATE = "if %s is %s and %s is %s then " + OUTPUT_VARIABLE_NAME + " is %s"; + private final static String NO_RESULT = "Нет результата"; private final DbRuleService ruleService; private final AntecedentValueService antecedentValueService; private final GitRepositoryService gitRepositoryService; @@ -44,10 +49,9 @@ public class FuzzyInferenceService { this.timeSeriesService = timeSeriesService; } - public List getRulesFromDb(Map variableValues) { - List dbDbRules = ruleService.getList(); - validateVariables(variableValues, dbDbRules); - return dbDbRules.stream().map(this::getFuzzyRule).collect(Collectors.toList()); + public List getRulesFromDb(List dbRules, Map variableValues) { + validateVariables(variableValues, dbRules); + return dbRules.stream().map(this::getFuzzyRule).collect(Collectors.toList()); } private String getFuzzyRule(DbRule dbRule) { @@ -56,13 +60,14 @@ public class FuzzyInferenceService { dbRule.getFirstAntecedentValue().getAntecedentValue(), dbRule.getSecondAntecedent().name(), dbRule.getSecondAntecedentValue().getAntecedentValue(), - dbRule.getConsequent().replaceAll(" ", "_")); + dbRule.getId()); } private RuleBlock getRuleBlock(Engine engine, + List dbRules, Map variableValues, List antecedentValues, - List consequentValues) { + List consequentValues) { variableValues.forEach((key, value) -> { InputVariable input = new InputVariable(); input.setName(key); @@ -86,7 +91,7 @@ public class FuzzyInferenceService { output.setDefaultValue(Double.NaN); output.setLockValueInRange(false); for (int i = 0; i < consequentValues.size(); i++) { - output.addTerm(new Triangle(consequentValues.get(i).replaceAll(" ", "_"), i - 0.1, i + 2.1)); + output.addTerm(new Triangle(consequentValues.get(i).toString(), i - 0.1, i + 2.1)); } engine.addOutputVariable(output); @@ -98,7 +103,7 @@ public class FuzzyInferenceService { mamdani.setDisjunction(new BoundedSum()); mamdani.setImplication(new AlgebraicProduct()); mamdani.setActivation(new Highest()); - getRulesFromDb(variableValues).forEach(r -> mamdani.addRule(Rule.parse(r, engine))); + getRulesFromDb(dbRules, variableValues).forEach(r -> mamdani.addRule(Rule.parse(r, engine))); return mamdani; } @@ -109,15 +114,67 @@ public class FuzzyInferenceService { return engine; } - public String getRecommendations(Integer branchId) { + public List getAssessmentsByForecastTendencies(Integer branchId) { List timeSeries = timeSeriesService.getByBranch(branchId); + List dbRules = ruleService.getList(); + try { + return getAssessmentsByTimeSeriesTendencies(dbRules, timeSeries); + } catch (AssessmentException ex) { + return new ArrayList<>(); + } + } + + public List getAssessmentsByLastValues(Integer branchId) { + List timeSeries = timeSeriesService.getByBranch(branchId); + List dbRules = ruleService.getList(); + return getAssessmentsByLastValues(dbRules, timeSeries); + } + + private List getFuzzyInference(List dbRules, Map variableValues) { Engine engine = getFuzzyEngine(); - List antecedentValues = antecedentValueService.getList(); - List consequentValues = ruleService.getConsequentList(); + List antecedentValues = Stream.concat(dbRules.stream().map(DbRule::getFirstAntecedentValue), + dbRules.stream().map(DbRule::getSecondAntecedentValue)).distinct().collect(Collectors.toList()); + List consequentValues = dbRules.stream().map(DbRule::getId).collect(Collectors.toList()); + engine.addRuleBlock(getRuleBlock(engine, dbRules, variableValues, antecedentValues, consequentValues)); + String consequent = getConsequent(engine, variableValues); + if (consequent.equals(NO_RESULT)) { + return new ArrayList<>(); + } + return dbRules + .stream() + .filter(r -> r.getId().equals(Integer.valueOf(consequent))) + .map(Assessment::new) + .collect(Collectors.toList()); + } + + private List getSingleAssessmentByTimeSeriesTendencies(List dbRules, List timeSeries) throws AssessmentException { + Map variableValues = new HashMap<>(); + timeSeries.forEach(ts -> variableValues.put(ts.getTimeSeriesType().name(), + timeSeriesService.getLastTimeSeriesTendency(ts) + .orElseThrow(() -> new AssessmentException("")))); + return getFuzzyInference(dbRules, variableValues); + } + + private List getAssessmentsByTimeSeriesTendencies(List dbRules, List timeSeries) { + return dbRules + .stream() + .flatMap(dbRule -> { + Map variableValues = new HashMap<>(); + timeSeries + .stream() + .filter(ts -> ts.getTimeSeriesType() == dbRule.getFirstAntecedent() + || ts.getTimeSeriesType() == dbRule.getSecondAntecedent()) + .forEach(ts -> variableValues.put(ts.getTimeSeriesType().name(), timeSeriesService + .getLastTimeSeriesTendency(ts) + .orElseThrow(() -> new AssessmentException("")))); + return getFuzzyInference(List.of(dbRule), variableValues).stream(); + }).collect(Collectors.toList()); + } + + private List getAssessmentsByLastValues(List dbRules, List timeSeries) { Map variableValues = new HashMap<>(); - timeSeries.forEach(ts -> variableValues.put(ts.getTimeSeriesType().name(), timeSeriesService.getLastTimeSeriesTendency(ts))); - engine.addRuleBlock(getRuleBlock(engine, variableValues, antecedentValues, consequentValues)); - return getConsequent(engine, variableValues); + timeSeries.forEach(ts -> variableValues.put(ts.getTimeSeriesType().name(), ts.getValues().get(ts.getValues().size() - 1).getValue())); + return getFuzzyInference(dbRules, variableValues); } private void validateVariables(Map variableValues, List dbDbRules) { @@ -144,7 +201,7 @@ public class FuzzyInferenceService { outputVariable.defuzzify(); } return (outputVariable == null || Double.isNaN(outputVariable.getValue())) - ? "Нет рекомендаций" + ? NO_RESULT : outputVariable.highestMembership(outputVariable.getValue()).getSecond().getName(); } } diff --git a/src/main/java/ru/ulstu/extractor/ts/service/TimeSeriesService.java b/src/main/java/ru/ulstu/extractor/ts/service/TimeSeriesService.java index 3f8f6cd..4cc2de9 100644 --- a/src/main/java/ru/ulstu/extractor/ts/service/TimeSeriesService.java +++ b/src/main/java/ru/ulstu/extractor/ts/service/TimeSeriesService.java @@ -115,16 +115,16 @@ public class TimeSeriesService { return timeSeriesRepository.getTimeSeriesByBranchId(branchId); } - public Double getLastTimeSeriesTendency(TimeSeries ts) { + public Optional getLastTimeSeriesTendency(TimeSeries ts) { if (ts != null && ts.getValues().size() > 5) { JSONObject response = httpService.post(TIME_SERIES_TENDENCY_URL, new JSONObject(new SmoothingTimeSeries(ts))); LOG.debug("Успешно отправлен на сервис сглаживания"); if (response.has("response") && response.getString("response").equals("empty")) { - return 0.0; + return Optional.empty(); } JSONArray jsonArray = response.getJSONObject("timeSeries").getJSONArray("values"); - return jsonArray.getJSONObject(jsonArray.length() - 1).getDouble("value"); + return Optional.of(jsonArray.getJSONObject(jsonArray.length() - 1).getDouble("value")); } - return 0.0; + return Optional.empty(); } } diff --git a/src/main/resources/templates/recommendations.html b/src/main/resources/templates/assessments.html similarity index 61% rename from src/main/resources/templates/recommendations.html rename to src/main/resources/templates/assessments.html index 7d43881..516628a 100644 --- a/src/main/resources/templates/recommendations.html +++ b/src/main/resources/templates/assessments.html @@ -7,7 +7,7 @@
-
+
Репозиторий-ветка @@ -26,17 +26,26 @@ ]) ; $('#select-branch').selectpicker('refresh'); -
-
Выбрерите ветку для получения рекомендаций
+
Выбрерите ветку для получения оценки репозитория
-
-
+
+
Состояние репозитория описывается следующими выражениями:
+
+ + вследствие тенденции '' показателя '' + и тенденции '' показателя ''; +
+
+
+
Нет результатов
diff --git a/src/main/resources/templates/default.html b/src/main/resources/templates/default.html index d118ca8..45c036d 100644 --- a/src/main/resources/templates/default.html +++ b/src/main/resources/templates/default.html @@ -41,7 +41,7 @@ Link