Ломбок, Новая логика приоритетов, Исправление багов

This commit is contained in:
Mark Struchkov 2019-07-12 17:12:49 +03:00
parent c7eda5c61d
commit f2ad7bee0f
7 changed files with 107 additions and 129 deletions

View File

@ -15,8 +15,6 @@ import org.sadtech.autoresponder.util.Parser;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Реализуют основную логику автоответчика.
@ -24,7 +22,7 @@ import java.util.regex.Pattern;
* @author upagge [07/07/2019]
*/
@Slf4j
public class Autoresponder {
public class AutoResponder {
@Description("Компоратор для сортировки Unit-ов")
private static final UnitPriorityComparator UNIT_PRIORITY_COMPARATOR = new UnitPriorityComparator();
@ -40,7 +38,7 @@ public class Autoresponder {
@Getter
private final UnitPointerService unitPointerService;
public Autoresponder(UnitPointerService unitPointerService, Set<Unit> startUnits) {
public AutoResponder(UnitPointerService unitPointerService, Set<Unit> startUnits) {
this.startUnits = startUnits;
this.unitPointerService = unitPointerService;
}
@ -56,7 +54,7 @@ public class Autoresponder {
UnitPointer unitPointer = checkAndAddPerson(personId);
Unit unit;
try {
if (unitPointer.getUnit() == null || unitPointer.getUnit().getNextUnits() == null) {
if (unitPointer.getUnit() == null || unitPointer.getUnit().getNextUnits() == null || unitPointer.getUnit().getNextUnits().isEmpty()) {
unit = nextUnit(startUnits, message);
} else {
unit = nextUnit(unitPointer.getUnit().getNextUnits(), message);
@ -75,23 +73,22 @@ public class Autoresponder {
* @param message Запрос пользователя - текстовое сообщение
* @return Юнит, который нуждается в обработке в соответствии с запросом пользователя
*/
private Unit nextUnit(Set<Unit> nextUnits, String message) {
Optional<Unit> unit = nextUnits.stream()
private Unit nextUnit(@NonNull Set<Unit> nextUnits, String message) {
Set<Unit> searchUnit = new HashSet<>();
nextUnits.stream()
.filter(nextUnit -> nextUnit.getPattern() != null && patternReg(nextUnit, message))
.max(UNIT_PRIORITY_COMPARATOR);
.forEach(searchUnit::add);
if (!unit.isPresent()) {
unit = nextUnits.stream()
.filter(nextUnit -> percentageMatch(nextUnit, Parser.parse(message)) >= nextUnit.getMatchThreshold())
.max(UNIT_PRIORITY_COMPARATOR);
}
nextUnits.stream()
.filter(nextUnit -> percentageMatch(nextUnit, Parser.parse(message)) >= nextUnit.getMatchThreshold())
.forEach(searchUnit::add);
if (!unit.isPresent()) {
unit = nextUnits.stream()
.filter(nextUnit -> (nextUnit.getPattern() == null && nextUnit.getKeyWords() == null))
.max(UNIT_PRIORITY_COMPARATOR);
}
return unit.orElseThrow(NotFoundUnitException::new);
nextUnits.stream()
.filter(nextUnit -> (nextUnit.getPattern() == null && (nextUnit.getKeyWords() == null || nextUnit.getKeyWords().isEmpty())))
.forEach(searchUnit::add);
return searchUnit.stream().max(UNIT_PRIORITY_COMPARATOR).orElseThrow(NotFoundUnitException::new);
}
/**
@ -100,7 +97,7 @@ public class Autoresponder {
* @param personId Идентификатор пользователя
* @return {@link UnitPointer}, который сохраняет {@link Unit}, который был обработан последним
*/
private UnitPointer checkAndAddPerson(Integer personId) {
private UnitPointer checkAndAddPerson(@NonNull Integer personId) {
UnitPointer unitPointer;
if (unitPointerService.check(personId)) {
unitPointer = unitPointerService.getByEntityId(personId);
@ -112,14 +109,12 @@ public class Autoresponder {
}
private boolean patternReg(Unit unit, String message) {
Pattern pattern = unit.getPattern();
Matcher m = pattern.matcher(message);
return m.find();
private boolean patternReg(@NonNull Unit unit, String message) {
return message.matches(unit.getPattern().pattern());
}
private Double percentageMatch(Unit unit, Set<String> words) {
if (unit.getKeyWords() != null) {
if (unit.getKeyWords() != null && !unit.getKeyWords().isEmpty()) {
Set<String> temp = new HashSet<>(unit.getKeyWords());
temp.retainAll(words);
log.info("Ключевые слова юнита: {} ({})", unit.getKeyWords(), unit.getKeyWords().size());

View File

@ -3,10 +3,10 @@ package org.sadtech.autoresponder.entity;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.sadtech.autoresponder.util.Description;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
@ -17,52 +17,30 @@ import java.util.regex.Pattern;
*/
@Getter
@EqualsAndHashCode
@ToString
@Setter
public abstract class Unit {
@Description("Ключевые слова")
private Set<String> keyWords;
protected Set<String> keyWords;
@Setter
@Description("Регулярное выражение")
private Pattern pattern;
protected Pattern pattern;
@Setter
// todo [upagge] [07/07/2019]: Придумать нормальное описание
private Integer matchThreshold = 10;
@Description("Значение минимального отношения количества найденых ключевых слов, к количеству ключевых слов Unit-а")
protected Integer matchThreshold;
@Setter
@Description("Значение приоритета")
private Integer priority = 10;
protected Integer priority;
@Description("Множество следующих Unit в сценарии")
private Set<Unit> nextUnits;
protected Set<Unit> nextUnits;
public void setKeyWord(String... keyWord) {
if (this.keyWords == null) {
this.keyWords = new HashSet<>();
}
this.keyWords.addAll(Arrays.asList(keyWord));
protected Unit(Set<String> keyWords, Pattern pattern, Integer matchThreshold, Integer priority, Set<Unit> nextUnits) {
this.keyWords = keyWords;
this.pattern = pattern;
this.matchThreshold = Optional.ofNullable(matchThreshold).orElse(10);
this.priority = Optional.ofNullable(priority).orElse(10);
this.nextUnits = nextUnits;
}
public void setKeyWords(Set<String> keyWords) {
if (this.keyWords == null) {
this.keyWords = new HashSet<>();
}
this.keyWords.addAll(keyWords);
}
public void setNextUnit(Unit... unit) {
if (nextUnits == null) {
nextUnits = new HashSet<>();
}
nextUnits.addAll(Arrays.asList(unit));
}
public void setNextUnits(Set<Unit> nextUnits) {
if (nextUnits == null) {
nextUnits = new HashSet<>();
}
this.nextUnits.addAll(nextUnits);
}
}

View File

@ -6,4 +6,5 @@ package org.sadtech.autoresponder.exception;
* @author upagge [07/07/2019]
*/
public class NotFoundUnitException extends RuntimeException {
}

View File

@ -1,5 +1,6 @@
package org.sadtech.autoresponder.repository;
import lombok.NonNull;
import org.sadtech.autoresponder.entity.UnitPointer;
import java.util.Collection;
@ -16,27 +17,27 @@ public class UnitPointerRepositoryMap implements UnitPointerRepository {
private Map<Integer, UnitPointer> unitPointerMap = new HashMap<>();
@Override
public void add(UnitPointer unitPointer) {
public void add(@NonNull UnitPointer unitPointer) {
unitPointerMap.put(unitPointer.getEntityId(), unitPointer);
}
@Override
public void edit(UnitPointer unitPointer) {
public void edit(@NonNull UnitPointer unitPointer) {
unitPointerMap.get(unitPointer.getEntityId()).setUnit(unitPointer.getUnit());
}
@Override
public void remove(Integer entityId) {
public void remove(@NonNull Integer entityId) {
unitPointerMap.remove(entityId);
}
@Override
public void addAll(Collection<UnitPointer> unitPointers) {
public void addAll(@NonNull Collection<UnitPointer> unitPointers) {
unitPointers.parallelStream().forEach(unitPointer -> unitPointerMap.put(unitPointer.getEntityId(), unitPointer));
}
@Override
public UnitPointer findByEntityId(Integer entityId) {
public UnitPointer findByEntityId(@NonNull Integer entityId) {
return unitPointerMap.get(entityId);
}
}

View File

@ -1,44 +1,40 @@
package org.sadtech.autoresponder.service;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.sadtech.autoresponder.entity.Unit;
import org.sadtech.autoresponder.entity.UnitPointer;
import org.sadtech.autoresponder.repository.UnitPointerRepository;
import org.sadtech.autoresponder.repository.UnitPointerRepositoryMap;
@Slf4j
public class UnitPointerServiceImpl implements UnitPointerService {
private UnitPointerRepository unitPointerRepository;
public UnitPointerServiceImpl() {
this.unitPointerRepository = new UnitPointerRepositoryMap();
}
private final UnitPointerRepository unitPointerRepository;
public UnitPointerServiceImpl(UnitPointerRepository unitPointerRepository) {
this.unitPointerRepository = unitPointerRepository;
}
@Override
public UnitPointer getByEntityId(Integer entityId) {
public UnitPointer getByEntityId(@NonNull Integer entityId) {
return unitPointerRepository.findByEntityId(entityId);
}
@Override
public void edit(Integer personId, Unit unit) {
public void edit(@NonNull Integer personId, Unit unit) {
if (check(personId)) {
unitPointerRepository.edit(new UnitPointer(personId, unit));
}
}
@Override
public void add(UnitPointer unitPointer) {
public void add(@NonNull UnitPointer unitPointer) {
unitPointerRepository.add(unitPointer);
log.info("Пользователь отправлен в репозиторий");
}
@Override
public boolean check(Integer entityId) {
public boolean check(@NonNull Integer entityId) {
return unitPointerRepository.findByEntityId(entityId) != null;
}
}

View File

@ -12,42 +12,53 @@ import org.sadtech.autoresponder.test.TestUnit;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class AutoresponderTest {
public class AutoResponderTest {
private Autoresponder autoresponder;
private AutoResponder autoresponder;
@Before
public void setUp() {
TestUnit dela = new TestUnit();
dela.setKeyWord("дела", "делишки");
dela.setMessage("хорошо");
TestUnit dela = TestUnit.builder()
.keyWord("дела")
.keyWord("делишки")
.message("хорошо")
.build();
TestUnit delaTop = new TestUnit();
delaTop.setPriority(100);
delaTop.setKeyWord("делишки");
delaTop.setMessage("отлично");
TestUnit delaTop = TestUnit.builder()
.priority(100)
.keyWord("делишки")
.message("отлично")
.build();
TestUnit hello = new TestUnit();
hello.setMessage("тест");
hello.setKeyWord("привет");
hello.setNextUnit(dela);
hello.setNextUnit(delaTop);
TestUnit hello = TestUnit.builder()
.keyWord("привет")
.message("тест")
.nextUnit(dela)
.nextUnit(delaTop)
.build();
TestUnit number = new TestUnit();
number.setKeyWord("89101234567");
number.setMessage("ответ");
TestUnit regExp = new TestUnit();
regExp.setPattern(Pattern.compile("^((8|\\+7)[\\- ]?)?(\\(?\\d{3}\\)?[\\- ]?)?[\\d\\- ]{7,10}$"));
regExp.setMessage("регулярка");
dela.setNextUnit(regExp);
dela.setNextUnit(number);
TestUnit number = TestUnit.builder()
.keyWord("89101234567")
.message("ответ")
.build();
TestUnit unreal = new TestUnit();
unreal.setKeyWord("витамин", "мультифрукт", "арбуз", "параметр");
unreal.setMessage("победа");
unreal.setMatchThreshold(100);
TestUnit regExp = TestUnit.builder()
.pattern(Pattern.compile("^((8|\\+7)[\\- ]?)?(\\(?\\d{3}\\)?[\\- ]?)?[\\d\\- ]{7,10}$"))
.message("регулярка")
.build();
dela.setNextUnits(Stream.of(regExp, number).collect(Collectors.toSet()));
Set<String> strings = Stream.of("витамин", "мультифрукт", "арбуз", "параметр").collect(Collectors.toSet());
TestUnit unreal = TestUnit.builder()
.keyWords(strings)
.message("победа")
.matchThreshold(100)
.build();
Set<Unit> testUnits = new HashSet<>();
testUnits.add(hello);
@ -55,7 +66,7 @@ public class AutoresponderTest {
testUnits.add(unreal);
UnitPointerServiceImpl unitPointerService = new UnitPointerServiceImpl(new UnitPointerRepositoryMap());
autoresponder = new Autoresponder(unitPointerService, testUnits);
autoresponder = new AutoResponder(unitPointerService, testUnits);
}
@Test
@ -68,8 +79,7 @@ public class AutoresponderTest {
@Test
public void defaultAnswer() {
TestUnit defaultUnit = new TestUnit();
defaultUnit.setMessage("не знаю");
TestUnit defaultUnit = TestUnit.builder().message("не знаю").build();
autoresponder.setDefaultUnit(defaultUnit);
Assert.assertEquals(((TestUnit) autoresponder.answer(2, "пока")).getMessage(), "не знаю");
@ -113,8 +123,7 @@ public class AutoresponderTest {
@Test
public void generalAnswer() {
TestUnit defaultUnit = new TestUnit();
defaultUnit.setMessage("не знаю");
TestUnit defaultUnit = TestUnit.builder().message("не знаю").build();
autoresponder.setDefaultUnit(defaultUnit);
String answer = ((TestUnit) autoresponder.answer(1, "привет это тестирование функциональности")).getMessage();
Assert.assertEquals("тест", answer);

View File

@ -1,32 +1,30 @@
package org.sadtech.autoresponder.test;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Singular;
import lombok.ToString;
import org.sadtech.autoresponder.entity.Unit;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
@Getter
@EqualsAndHashCode(callSuper = true)
@ToString
public class TestUnit extends Unit {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
@Builder
public TestUnit(@Singular(value = "keyWord") Set<String> keyWords,
Pattern pattern,
Integer matchThreshold,
Integer priority,
@Singular(value = "nextUnit") Set<Unit> nextUnits,
String message) {
super(keyWords, pattern, matchThreshold, priority, nextUnits);
this.message = message;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TestUnit)) return false;
if (!super.equals(o)) return false;
TestUnit testUnit = (TestUnit) o;
return Objects.equals(message, testUnit.message);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), message);
}
}