В наши дни чат-боты используются в самых разных сценариях взаимодействия с пользователями. Например, в службах поддержки клиентов различных компаний, о чём я уже писала. В этом материале я хочу рассказать о механизмах, которые используются в чат-ботах при поиске того, что нужно пользователю.



Например, посетитель сайта что-то ищет и пользуется для этого чат-ботом, работающим на сайте или в мобильном приложении. Бот разбирает сообщение и, основываясь на имеющихся в нём ключевых словах, отвечает пользователю, выдавая ссылку на страницу с результатами поиска, среди которых пользователь может найти то, что ему нужно.

Бот, о котором пойдёт речь в этом материале, создан с использованием Java и Apache OpenNLP. Здесь мы поговорим о том, как боты разбирают сообщения пользователей, удаляя из них всё ненужное.

Удаление из сообщений ненужных символов


Когда пользователь общается с ботом, в сообщениях пользователя могут присутствовать ненужные символы. Поэтому, прежде чем бот сможет адекватно ответить, всё ненужное из сообщений пользователя нужно удалить.

Вот пример сообщения, которое пользователь отправил боту. В верхней части находится исходный текст, а в нижней — он же, но очищенный от ненужных символов.


Исходное и обработанное сообщение

В Java для удаления ненужных символов можно воспользоваться следующим регулярным выражением:

"[^\\w.,;:'\"\\s]+"

Токенизация текста в OpenNLP


После очистки текста от ненужных символов его нужно токенизировать с использованием соответствующих инструментов OpenNLP. В результате исходное предложение будет разбито на мелкие фрагменты (токены). Этот процесс и называют токенизацией. В целом можно сказать, что исходный необработанный текст токенизируется с опорой на набор символов-разделителей (это, в основном, пробелы). Токенизация используется при решении, например, следующих задач:

  • Проверка правописания.
  • Выполнение поиска.
  • Идентификация частей речи.
  • Обнаружение предложений.
  • Классификация документов.

В следующем примере сначала выполняется обучение токенизатора с использованием классов TokenizerMe и TokenizerModel:

try (InputStream modelIn = new ByteArrayInputStream(Files.readAllBytes(tokeniserTrainingFile.get()))) {
  this.tokenizer = new TokenizerME(new TokenizerModel(modelIn));
}

Класс TokenizerMe преобразует исходный текст в набор токенов. Он, принимая решение о разделении текста на токены, пользуется показателем энтропии.

В машинном обучении энтропия — это мера неопределённости некоей системы (1 — полная определённость, 0 — полная неопределённость).

Затем выполняется токенизация текста:

private tokenizerMe;
final String[] tokenizedMessage = this.tokenizerMe.tokenize(RobotUtil.getOnlyValidCharacters(inputMessage));

На следующем изображении показан результат токенизации сообщения.


Результат токенизации сообщения

После токенизации сообщения нужно определить тип токенов, понять, к каким частям речи они относятся, и убрать те из них, которые нам не нужны.

Выявление частей речи с использованием OpenNLP


Теперь нам нужно выяснить то, к какой части речи относится каждый из токенов. Узнать о том, что это: имя существительное, глагол, наречие, имя прилагательное. В OpenNLP для обозначения частей речи используются сокращения, приведённые в следующей таблице.

Сокращение Часть речи
NN Имя существительное в единственном числе или неисчисляемое существительное
DT Определяющее слово
VB Глагол в базовой форме
VBD Глагол в прошедшем времени
VBZ Глагол в третьем лице единственного числа настоящего времени
IN Предлог или подчинительный союз
NNP Имя собственное в единственном числе
TO to
JJ Имя прилагательное

Вот код, в котором для выявления частей речи в тексте используется класс POSTaggerME:

private POSTaggerME ptagger;
try (InputStream modelIn = new ByteArrayInputStream(Files.readAllBytes(trainingFile.get()))) {
  this.ptagger = new POSTaggerME(new POSModel(modelIn));
}

Класс POSTaggerME используется для определения частей речи в исходном тексте. Он, при обработке текста, использует показатель энтропии.

final String[] tags = this.ptagger.tag(tokenizedMessage);

После того, как выяснено то, к какой части речи относится каждый из токенов, мы убираем из текста всё ненужное.


Удаление ненужных токенов

Нас в данном случае интересует имя прилагательное (JJ) и имя существительное (NN).

Теперь в нашем распоряжении оказываются ключевые слова. Бот, воспользовавшись ими, может выдать ссылку, позволяющую пользователю найти то, что ему нужно.


Бот отвечает пользователю

Применяются ли в ваших проектах чат-боты?