Теперь для каждого ключевого слова можно указывать его важность.
This commit is contained in:
parent
deb53d600e
commit
252d987857
2
pom.xml
2
pom.xml
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
package dev.struchkov.autoresponder.exception;
|
||||
|
||||
public class AutoresponderException extends RuntimeException {
|
||||
|
||||
public AutoresponderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
@ -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 = "Процент: {} Необходимо: {}";
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
Loading…
Reference in New Issue
Block a user