Как программно найти варианты конкретного слова в предложении?
Иногда данные, которые вы получаете, не являются чистыми и имеют вариации используемых слов, с ошибками или манипуляциями. Можем ли мы найти такие примеры наиболее близкого сходства слов в предложении?
Например, если я ищу слово "Awesome", которое использовалось в качестве варианта в предложении, как
"We had an awwweesssommmeeee dinner at sea resort"
"We had an awesomeeee dinner at sea resort"
"We had an awwesooomee dinner at sea resort"
etc..
2 ответа
В качестве быстрого решения вы можете использовать строчные буквы в своих документах, разбивать их на пробелы и сворачивать последовательные символы каждого термина:
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
public class CollapseConsecutiveCharsDemo {
public static String collapse(final String term) {
final StringBuilder buffer = new StringBuilder();
if (!term.isEmpty()) {
char prev = term.charAt(0);
buffer.append(prev);
for (int i = 1; i < term.length(); i += 1) {
final char curr = term.charAt(i);
if (curr != prev) {
buffer.append(curr);
prev = curr;
}
}
}
return buffer.toString();
}
public static void main(final String... documents) {
final Map<String, Set<String>> termVariations = new TreeMap<>();
for (final String document : documents) {
final Scanner scanner = new Scanner(document.toLowerCase());
while (scanner.hasNext()) {
final String expandedTerm = scanner.next();
final String collapsedTerm = collapse(expandedTerm);
Set<String> variations = termVariations.get(collapsedTerm);
if (null == variations) {
variations = new TreeSet<String>();
termVariations.put(collapsedTerm, variations);
}
variations.add(expandedTerm);
}
}
for (final Map.Entry<String, Set<String>> entry : termVariations.entrySet()) {
final String term = entry.getKey();
final Set<String> variations = entry.getValue();
System.out.printf("variations(\"%s\") = {%s}%n",
term,
variations.stream()
.map((variation) -> String.format("\"%s\"", variation))
.collect(Collectors.joining(", ")));
}
}
}
Пример выполнения:
% java CollapseConsecutiveCharsDemo "We had an awwweesssommmeeee dinner at sea resort" "We had an awesomeeee dinner at sea resort" "We had an awwesooomee dinner at sea resort"
variations("an") = {"an"}
variations("at") = {"at"}
variations("awesome") = {"awesomeeee", "awwesooomee", "awwweesssommmeeee"}
variations("diner") = {"dinner"}
variations("had") = {"had"}
variations("resort") = {"resort"}
variations("sea") = {"sea"}
variations("we") = {"we"}
Для более сложного решения вы можете маркировать свои документы с помощью токенайзера Stanford CoreNLP, который правильно обрабатывает знаки препинания, и комбинировать его с исправлением орфографии, например с liblevenshtein.
Вы хотите сделать это исключительно в SQL?
В противном случае вам понадобится некоторая функция сравнения строк с нечетким соответствием для вызова в SQL. Функция будет использовать некоторую комбинацию алгоритмов, таких как Яро-Винклер, Левенштейн, Нграмс и др. Или фонетическое соответствие метафона двойной метафон, метафон 3, soundex
В зависимости от того, какой sql-сервер вы используете, вы можете установить и использовать Компоненты Качества Данных, которые имеют собственную реализацию CLR некоторых из этих алгоритмов. Или нечеткие соответствующие компоненты служб SSIS. Или же.....
Я лично написал для этого функции C# .net clr, но я имею дело только с именами, предложения становятся все более сложными, и вы, вероятно, захотите разбить их на слова / токены для сравнения как частей, а затем как целого....