Теперь для каждого ключевого слова можно указывать его важность.

This commit is contained in:
Struchkov Mark 2022-07-09 07:24:54 +03:00
parent deb53d600e
commit 252d987857
8 changed files with 217 additions and 140 deletions

View File

@ -6,7 +6,7 @@
<groupId>dev.struchkov</groupId>
<artifactId>autoresponder</artifactId>
<version>3.0.0</version>
<version>3.1.0</version>
<packaging>jar</packaging>
<name>Abstract Autoresponder</name>

View File

@ -1,6 +1,7 @@
package dev.struchkov.autoresponder;
import dev.struchkov.autoresponder.compare.UnitPriorityComparator;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.autoresponder.entity.Unit;
import dev.struchkov.autoresponder.util.Message;
import org.slf4j.Logger;
@ -42,10 +43,10 @@ public final class Responder {
* @return Юнит, который нуждается в обработке в соответствии с запросом пользователя
*/
public static <U extends Unit<U>> Optional<U> nextUnit(String message, Collection<U> nextUnits) {
isNotNull(nextUnits, message);
isNotNull(nextUnits);
final Set<U> searchUnit = new HashSet<>();
if (nextUnits != null) {
if (message != null && nextUnits != null) {
for (U unit : nextUnits) {
final String unitPhrase = unit.getPhrase();
if (
@ -60,41 +61,68 @@ public final class Responder {
searchUnit.add(unit);
}
if (percentageMatch(unit, splitWords(message)) >= unit.getMatchThreshold()) {
if (percentageMatch(unit, message) >= unit.getMatchThreshold()) {
searchUnit.add(unit);
}
}
}
if (searchUnit.isEmpty()) {
for (U nextUnit : nextUnits) {
if ((nextUnit.getPattern() == null && (nextUnit.getKeyWords() == null || nextUnit.getKeyWords().isEmpty()))) {
if (isNotPattern(nextUnit) && isNotKeyWords(nextUnit) && isNotPhrase(nextUnit)) {
searchUnit.add(nextUnit);
}
}
}
}
return searchUnit.stream().max(UNIT_PRIORITY_COMPARATOR);
}
private static <U extends Unit<U>> boolean isNotPhrase(U nextUnit) {
return nextUnit.getPhrase() == null;
}
private static <U extends Unit<U>> boolean isNotPattern(U nextUnit) {
return nextUnit.getPattern() == null;
}
private static <U extends Unit<U>> boolean isNotKeyWords(U nextUnit) {
return nextUnit.getKeyWords() == null || nextUnit.getKeyWords().isEmpty();
}
private static boolean patternReg(Pattern pattern, String message) {
isNotNull(pattern);
return message.matches(pattern.pattern());
}
private static <U extends Unit<U>> Double percentageMatch(U unit, Set<String> words) {
final Set<String> keyWords = unit.getKeyWords();
if (keyWords != null && !keyWords.isEmpty()) {
final Set<String> temp = new HashSet<>(keyWords);
temp.retainAll(words);
log.trace(Message.UNIT_KEYWORDS, keyWords, keyWords.size());
log.trace(Message.USER_MESSAGE_KEYWORDS, words);
log.trace(Message.INTERSECTION, temp, temp.size());
log.trace(Message.CROSSING_PERCENTAGE, (double) temp.size() / (double) keyWords.size() * 100.0, unit.getMatchThreshold());
return (double) temp.size() / (double) keyWords.size() * 100.0;
private static <U extends Unit<U>> double percentageMatch(U unit, String message) {
final Set<KeyWord> unitKeyWords = unit.getKeyWords();
if (unitKeyWords != null && !unitKeyWords.isEmpty()) {
final Set<String> messageWords = splitWords(message);
final Set<KeyWord> intersection = getIntersection(unitKeyWords, messageWords);
final double intersectionWeight = getIntersectionWeight(intersection);
log.debug(Message.UNIT_KEYWORDS, unitKeyWords, unitKeyWords.size());
log.debug(Message.USER_MESSAGE_KEYWORDS, messageWords);
log.debug(Message.INTERSECTION, intersection, intersectionWeight);
log.debug(Message.CROSSING_PERCENTAGE, intersectionWeight / (double) unitKeyWords.size() * 100.0, unit.getMatchThreshold());
return (double) intersection.size() / (double) unitKeyWords.size() * 100.0;
} else {
return 0.0;
}
}
private static double getIntersectionWeight(Set<KeyWord> intersection) {
return intersection.stream().mapToInt(KeyWord::getImportant).sum();
}
private static Set<KeyWord> getIntersection(Set<KeyWord> unitKeyWords, Set<String> messageWords) {
final Set<KeyWord> intersection = new HashSet<>();
for (KeyWord unitKeyWord : unitKeyWords) {
if (messageWords.contains(unitKeyWord.getWord())) {
intersection.add(unitKeyWord);
}
}
return intersection;
}
}

View File

@ -0,0 +1,37 @@
package dev.struchkov.autoresponder.entity;
import dev.struchkov.autoresponder.exception.AutoresponderException;
/**
* Ключевое слово для юнитов.
*/
public class KeyWord {
private final Integer important;
private final String word;
private KeyWord(Integer important, String word) {
if (important < 0 || important > 10) {
throw new AutoresponderException("Вес слова должен быть значением от 0 до 100");
}
this.important = important;
this.word = word;
}
public static KeyWord of(Integer weight, String word) {
return new KeyWord(weight, word);
}
public static KeyWord of(String word) {
return new KeyWord(1, word);
}
public Integer getImportant() {
return important;
}
public String getWord() {
return word;
}
}

View File

@ -15,7 +15,7 @@ public abstract class Unit<U extends Unit<U>> {
/**
* Ключевые слова.
*/
protected Set<String> keyWords = new HashSet<>();
protected Set<KeyWord> keyWords = new HashSet<>();
/**
* Точная фраза.
@ -42,12 +42,14 @@ public abstract class Unit<U extends Unit<U>> {
*/
protected Set<U> nextUnits = new HashSet<>();
protected Unit(Set<String> keyWords,
protected Unit(
Set<KeyWord> keyWords,
String phrase,
Pattern pattern,
Integer matchThreshold,
Integer priority,
Set<U> nextUnits) {
Set<U> nextUnits
) {
this.keyWords = keyWords;
this.phrase = phrase;
this.pattern = pattern;
@ -56,11 +58,11 @@ public abstract class Unit<U extends Unit<U>> {
this.nextUnits = nextUnits;
}
public Set<String> getKeyWords() {
public Set<KeyWord> getKeyWords() {
return keyWords;
}
public void setKeyWords(Set<String> keyWords) {
public void setKeyWords(Set<KeyWord> keyWords) {
this.keyWords = keyWords;
}

View File

@ -0,0 +1,9 @@
package dev.struchkov.autoresponder.exception;
public class AutoresponderException extends RuntimeException {
public AutoresponderException(String message) {
super(message);
}
}

View File

@ -9,7 +9,7 @@ public final class Message {
static final String UTILITY_CLASS = "Клас утилита";
public static final String UNIT_KEYWORDS = "Ключевые слова юнита: {} ({})";
public static final String USER_MESSAGE_KEYWORDS = "Ключевые слова от пользователя: {}";
public static final String USER_MESSAGE_KEYWORDS = "Слова, которые прислал пользователь: {}";
public static final String INTERSECTION = "Пересечение: {} ({})";
public static final String CROSSING_PERCENTAGE = "Процент: {} Необходимо: {}";

View File

@ -4,7 +4,7 @@ import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.autoresponder.util.Message.UTILITY_CLASS;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
/**
* Разбивает строку на множество слов, удаляя предлоги.
@ -18,10 +18,11 @@ public class Parser {
*/
private static final Set<String> pretexts = Set.of(
"в", "без", "до", "из", "к", "на", "по", "о", "от", "перед", "при", "с", "у", "за", "над", "об",
"под", "про", "для");
"под", "про", "для"
);
private Parser() {
throw new IllegalStateException(UTILITY_CLASS);
utilityClass();
}
/**

View File

@ -1,108 +1,108 @@
package dev.struchkov.autoresponder.test;
import dev.struchkov.autoresponder.entity.Unit;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
public class TestUnit extends Unit<TestUnit> {
private String message;
public TestUnit(Set<String> keyWords,
String phrase,
Pattern pattern,
Integer matchThreshold,
Integer priority,
Set<TestUnit> nextUnits,
String message) {
super(keyWords, phrase, pattern, matchThreshold, priority, nextUnits);
this.message = message;
}
private TestUnit(Builder builder) {
super(builder.keyWords, builder.phrase, builder.pattern, builder.matchThreshold, builder.priority, builder.nextUnits);
message = builder.message;
}
public static Builder builder() {
return new Builder();
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return "TestUnit{" +
"keyWords=" + keyWords +
", phrase='" + phrase + '\'' +
", pattern=" + pattern +
", matchThreshold=" + matchThreshold +
", priority=" + priority +
", message='" + message + '\'' +
'}';
}
public static final class Builder {
private Set<String> keyWords = new HashSet<>();
private String phrase;
private Pattern pattern;
private Integer matchThreshold;
private Integer priority;
private Set<TestUnit> nextUnits = new HashSet<>();
private String message;
public Builder keyWords(Set<String> val) {
keyWords = val;
return this;
}
public Builder keyWord(String val) {
keyWords.add(val);
return this;
}
public Builder phrase(String val) {
phrase = val;
return this;
}
public Builder pattern(Pattern val) {
pattern = val;
return this;
}
public Builder matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder priority(Integer val) {
priority = val;
return this;
}
public Builder nextUnits(Set<TestUnit> val) {
nextUnits = val;
return this;
}
public Builder nextUnit(TestUnit val) {
nextUnits.add(val);
return this;
}
public Builder message(String val) {
message = val;
return this;
}
public TestUnit build() {
return new TestUnit(this);
}
}
}
//package dev.struchkov.autoresponder.test;
//
//import dev.struchkov.autoresponder.entity.Unit;
//
//import java.util.HashSet;
//import java.util.Set;
//import java.util.regex.Pattern;
//
//public class TestUnit extends Unit<TestUnit> {
//
// private String message;
//
// public TestUnit(Set<String> keyWords,
// String phrase,
// Pattern pattern,
// Integer matchThreshold,
// Integer priority,
// Set<TestUnit> nextUnits,
// String message) {
// super(keyWords, phrase, pattern, matchThreshold, priority, nextUnits);
// this.message = message;
// }
//
// private TestUnit(Builder builder) {
// super(builder.keyWords, builder.phrase, builder.pattern, builder.matchThreshold, builder.priority, builder.nextUnits);
// message = builder.message;
// }
//
// public static Builder builder() {
// return new Builder();
// }
//
// public String getMessage() {
// return message;
// }
//
// @Override
// public String toString() {
// return "TestUnit{" +
// "keyWords=" + keyWords +
// ", phrase='" + phrase + '\'' +
// ", pattern=" + pattern +
// ", matchThreshold=" + matchThreshold +
// ", priority=" + priority +
// ", message='" + message + '\'' +
// '}';
// }
//
//
// public static final class Builder {
// private Set<String> keyWords = new HashSet<>();
// private String phrase;
// private Pattern pattern;
// private Integer matchThreshold;
// private Integer priority;
// private Set<TestUnit> nextUnits = new HashSet<>();
// private String message;
//
// public Builder keyWords(Set<String> val) {
// keyWords = val;
// return this;
// }
//
// public Builder keyWord(String val) {
// keyWords.add(val);
// return this;
// }
//
// public Builder phrase(String val) {
// phrase = val;
// return this;
// }
//
// public Builder pattern(Pattern val) {
// pattern = val;
// return this;
// }
//
// public Builder matchThreshold(Integer val) {
// matchThreshold = val;
// return this;
// }
//
// public Builder priority(Integer val) {
// priority = val;
// return this;
// }
//
// public Builder nextUnits(Set<TestUnit> val) {
// nextUnits = val;
// return this;
// }
//
// public Builder nextUnit(TestUnit val) {
// nextUnits.add(val);
// return this;
// }
//
// public Builder message(String val) {
// message = val;
// return this;
// }
//
// public TestUnit build() {
// return new TestUnit(this);
// }
// }
//}