Теперь для каждого ключевого слова можно указывать его важность.
This commit is contained in:
parent
deb53d600e
commit
252d987857
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>dev.struchkov</groupId>
|
<groupId>dev.struchkov</groupId>
|
||||||
<artifactId>autoresponder</artifactId>
|
<artifactId>autoresponder</artifactId>
|
||||||
<version>3.0.0</version>
|
<version>3.1.0</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Abstract Autoresponder</name>
|
<name>Abstract Autoresponder</name>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package dev.struchkov.autoresponder;
|
package dev.struchkov.autoresponder;
|
||||||
|
|
||||||
import dev.struchkov.autoresponder.compare.UnitPriorityComparator;
|
import dev.struchkov.autoresponder.compare.UnitPriorityComparator;
|
||||||
|
import dev.struchkov.autoresponder.entity.KeyWord;
|
||||||
import dev.struchkov.autoresponder.entity.Unit;
|
import dev.struchkov.autoresponder.entity.Unit;
|
||||||
import dev.struchkov.autoresponder.util.Message;
|
import dev.struchkov.autoresponder.util.Message;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -42,10 +43,10 @@ public final class Responder {
|
|||||||
* @return Юнит, который нуждается в обработке в соответствии с запросом пользователя
|
* @return Юнит, который нуждается в обработке в соответствии с запросом пользователя
|
||||||
*/
|
*/
|
||||||
public static <U extends Unit<U>> Optional<U> nextUnit(String message, Collection<U> nextUnits) {
|
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<>();
|
final Set<U> searchUnit = new HashSet<>();
|
||||||
|
|
||||||
if (nextUnits != null) {
|
if (message != null && nextUnits != null) {
|
||||||
for (U unit : nextUnits) {
|
for (U unit : nextUnits) {
|
||||||
final String unitPhrase = unit.getPhrase();
|
final String unitPhrase = unit.getPhrase();
|
||||||
if (
|
if (
|
||||||
@ -60,41 +61,68 @@ public final class Responder {
|
|||||||
searchUnit.add(unit);
|
searchUnit.add(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (percentageMatch(unit, splitWords(message)) >= unit.getMatchThreshold()) {
|
if (percentageMatch(unit, message) >= unit.getMatchThreshold()) {
|
||||||
searchUnit.add(unit);
|
searchUnit.add(unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (searchUnit.isEmpty()) {
|
if (searchUnit.isEmpty()) {
|
||||||
for (U nextUnit : nextUnits) {
|
for (U nextUnit : nextUnits) {
|
||||||
if ((nextUnit.getPattern() == null && (nextUnit.getKeyWords() == null || nextUnit.getKeyWords().isEmpty()))) {
|
if (isNotPattern(nextUnit) && isNotKeyWords(nextUnit) && isNotPhrase(nextUnit)) {
|
||||||
searchUnit.add(nextUnit);
|
searchUnit.add(nextUnit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return searchUnit.stream().max(UNIT_PRIORITY_COMPARATOR);
|
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) {
|
private static boolean patternReg(Pattern pattern, String message) {
|
||||||
isNotNull(pattern);
|
isNotNull(pattern);
|
||||||
return message.matches(pattern.pattern());
|
return message.matches(pattern.pattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <U extends Unit<U>> Double percentageMatch(U unit, Set<String> words) {
|
private static <U extends Unit<U>> double percentageMatch(U unit, String message) {
|
||||||
final Set<String> keyWords = unit.getKeyWords();
|
final Set<KeyWord> unitKeyWords = unit.getKeyWords();
|
||||||
if (keyWords != null && !keyWords.isEmpty()) {
|
if (unitKeyWords != null && !unitKeyWords.isEmpty()) {
|
||||||
final Set<String> temp = new HashSet<>(keyWords);
|
final Set<String> messageWords = splitWords(message);
|
||||||
temp.retainAll(words);
|
final Set<KeyWord> intersection = getIntersection(unitKeyWords, messageWords);
|
||||||
log.trace(Message.UNIT_KEYWORDS, keyWords, keyWords.size());
|
final double intersectionWeight = getIntersectionWeight(intersection);
|
||||||
log.trace(Message.USER_MESSAGE_KEYWORDS, words);
|
log.debug(Message.UNIT_KEYWORDS, unitKeyWords, unitKeyWords.size());
|
||||||
log.trace(Message.INTERSECTION, temp, temp.size());
|
log.debug(Message.USER_MESSAGE_KEYWORDS, messageWords);
|
||||||
log.trace(Message.CROSSING_PERCENTAGE, (double) temp.size() / (double) keyWords.size() * 100.0, unit.getMatchThreshold());
|
log.debug(Message.INTERSECTION, intersection, intersectionWeight);
|
||||||
return (double) temp.size() / (double) keyWords.size() * 100.0;
|
log.debug(Message.CROSSING_PERCENTAGE, intersectionWeight / (double) unitKeyWords.size() * 100.0, unit.getMatchThreshold());
|
||||||
|
return (double) intersection.size() / (double) unitKeyWords.size() * 100.0;
|
||||||
} else {
|
} else {
|
||||||
return 0.0;
|
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 Set<U> nextUnits = new HashSet<>();
|
||||||
|
|
||||||
protected Unit(Set<String> keyWords,
|
protected Unit(
|
||||||
|
Set<KeyWord> keyWords,
|
||||||
String phrase,
|
String phrase,
|
||||||
Pattern pattern,
|
Pattern pattern,
|
||||||
Integer matchThreshold,
|
Integer matchThreshold,
|
||||||
Integer priority,
|
Integer priority,
|
||||||
Set<U> nextUnits) {
|
Set<U> nextUnits
|
||||||
|
) {
|
||||||
this.keyWords = keyWords;
|
this.keyWords = keyWords;
|
||||||
this.phrase = phrase;
|
this.phrase = phrase;
|
||||||
this.pattern = pattern;
|
this.pattern = pattern;
|
||||||
@ -56,11 +58,11 @@ public abstract class Unit<U extends Unit<U>> {
|
|||||||
this.nextUnits = nextUnits;
|
this.nextUnits = nextUnits;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getKeyWords() {
|
public Set<KeyWord> getKeyWords() {
|
||||||
return keyWords;
|
return keyWords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKeyWords(Set<String> keyWords) {
|
public void setKeyWords(Set<KeyWord> keyWords) {
|
||||||
this.keyWords = 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 = "Клас утилита";
|
static final String UTILITY_CLASS = "Клас утилита";
|
||||||
public static final String UNIT_KEYWORDS = "Ключевые слова юнита: {} ({})";
|
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 INTERSECTION = "Пересечение: {} ({})";
|
||||||
public static final String CROSSING_PERCENTAGE = "Процент: {} Необходимо: {}";
|
public static final String CROSSING_PERCENTAGE = "Процент: {} Необходимо: {}";
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
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 static final Set<String> pretexts = Set.of(
|
||||||
"в", "без", "до", "из", "к", "на", "по", "о", "от", "перед", "при", "с", "у", "за", "над", "об",
|
"в", "без", "до", "из", "к", "на", "по", "о", "от", "перед", "при", "с", "у", "за", "над", "об",
|
||||||
"под", "про", "для");
|
"под", "про", "для"
|
||||||
|
);
|
||||||
|
|
||||||
private Parser() {
|
private Parser() {
|
||||||
throw new IllegalStateException(UTILITY_CLASS);
|
utilityClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,108 +1,108 @@
|
|||||||
package dev.struchkov.autoresponder.test;
|
//package dev.struchkov.autoresponder.test;
|
||||||
|
//
|
||||||
import dev.struchkov.autoresponder.entity.Unit;
|
//import dev.struchkov.autoresponder.entity.Unit;
|
||||||
|
//
|
||||||
import java.util.HashSet;
|
//import java.util.HashSet;
|
||||||
import java.util.Set;
|
//import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
//import java.util.regex.Pattern;
|
||||||
|
//
|
||||||
public class TestUnit extends Unit<TestUnit> {
|
//public class TestUnit extends Unit<TestUnit> {
|
||||||
|
//
|
||||||
private String message;
|
// private String message;
|
||||||
|
//
|
||||||
public TestUnit(Set<String> keyWords,
|
// public TestUnit(Set<String> keyWords,
|
||||||
String phrase,
|
// String phrase,
|
||||||
Pattern pattern,
|
// Pattern pattern,
|
||||||
Integer matchThreshold,
|
// Integer matchThreshold,
|
||||||
Integer priority,
|
// Integer priority,
|
||||||
Set<TestUnit> nextUnits,
|
// Set<TestUnit> nextUnits,
|
||||||
String message) {
|
// String message) {
|
||||||
super(keyWords, phrase, pattern, matchThreshold, priority, nextUnits);
|
// super(keyWords, phrase, pattern, matchThreshold, priority, nextUnits);
|
||||||
this.message = message;
|
// this.message = message;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private TestUnit(Builder builder) {
|
// private TestUnit(Builder builder) {
|
||||||
super(builder.keyWords, builder.phrase, builder.pattern, builder.matchThreshold, builder.priority, builder.nextUnits);
|
// super(builder.keyWords, builder.phrase, builder.pattern, builder.matchThreshold, builder.priority, builder.nextUnits);
|
||||||
message = builder.message;
|
// message = builder.message;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Builder builder() {
|
// public static Builder builder() {
|
||||||
return new Builder();
|
// return new Builder();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public String getMessage() {
|
// public String getMessage() {
|
||||||
return message;
|
// return message;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public String toString() {
|
// public String toString() {
|
||||||
return "TestUnit{" +
|
// return "TestUnit{" +
|
||||||
"keyWords=" + keyWords +
|
// "keyWords=" + keyWords +
|
||||||
", phrase='" + phrase + '\'' +
|
// ", phrase='" + phrase + '\'' +
|
||||||
", pattern=" + pattern +
|
// ", pattern=" + pattern +
|
||||||
", matchThreshold=" + matchThreshold +
|
// ", matchThreshold=" + matchThreshold +
|
||||||
", priority=" + priority +
|
// ", priority=" + priority +
|
||||||
", message='" + message + '\'' +
|
// ", message='" + message + '\'' +
|
||||||
'}';
|
// '}';
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
public static final class Builder {
|
// public static final class Builder {
|
||||||
private Set<String> keyWords = new HashSet<>();
|
// private Set<String> keyWords = new HashSet<>();
|
||||||
private String phrase;
|
// private String phrase;
|
||||||
private Pattern pattern;
|
// private Pattern pattern;
|
||||||
private Integer matchThreshold;
|
// private Integer matchThreshold;
|
||||||
private Integer priority;
|
// private Integer priority;
|
||||||
private Set<TestUnit> nextUnits = new HashSet<>();
|
// private Set<TestUnit> nextUnits = new HashSet<>();
|
||||||
private String message;
|
// private String message;
|
||||||
|
//
|
||||||
public Builder keyWords(Set<String> val) {
|
// public Builder keyWords(Set<String> val) {
|
||||||
keyWords = val;
|
// keyWords = val;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Builder keyWord(String val) {
|
// public Builder keyWord(String val) {
|
||||||
keyWords.add(val);
|
// keyWords.add(val);
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Builder phrase(String val) {
|
// public Builder phrase(String val) {
|
||||||
phrase = val;
|
// phrase = val;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Builder pattern(Pattern val) {
|
// public Builder pattern(Pattern val) {
|
||||||
pattern = val;
|
// pattern = val;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Builder matchThreshold(Integer val) {
|
// public Builder matchThreshold(Integer val) {
|
||||||
matchThreshold = val;
|
// matchThreshold = val;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Builder priority(Integer val) {
|
// public Builder priority(Integer val) {
|
||||||
priority = val;
|
// priority = val;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Builder nextUnits(Set<TestUnit> val) {
|
// public Builder nextUnits(Set<TestUnit> val) {
|
||||||
nextUnits = val;
|
// nextUnits = val;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Builder nextUnit(TestUnit val) {
|
// public Builder nextUnit(TestUnit val) {
|
||||||
nextUnits.add(val);
|
// nextUnits.add(val);
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public Builder message(String val) {
|
// public Builder message(String val) {
|
||||||
message = val;
|
// message = val;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public TestUnit build() {
|
// public TestUnit build() {
|
||||||
return new TestUnit(this);
|
// return new TestUnit(this);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
Loading…
Reference in New Issue
Block a user