Введение
Рекомендательные системы используются в приложениях для улучшения взаимодействия с пользователями. Например, приложения электронной коммерции рекомендуют продукты покупателям, которые другие покупатели — с похожим поведением — просмотрели, лайкнули или приобрели. Новостные приложения могут также использовать рекомендательные системы в реальном времени. Эти дополнения к стандартным функциям улучшат интерфейс пользователя, увеличат продажи и помогут улучшить лояльность клиентов. Эта статья содержит примеры кода для построения рекомендательной системы реального времени, основанной на косинусном сходстве.
Этот пример использует фреймворк Spring Boot, с помощью которого можно быстро развернуть бэкенд системы на Java. В качестве базы данных используется Aerospike.
Aerospike — высоконадежная NoSQL база данных и низкими задержками, которая масштабируется линейно — таким образом легко ее использовать в качестве хранилища для онлайн приложений. Она хорошо подходит к этому примеру, потому что она масштабируется как горизонтально (увеличивая количество нод на кластере), так и вертикально (поддерживает многопоточность). Aerospike — это in-memory база данных, оптимизированная для использования и DRAM и нативной Flash памяти. Aerospike может похвастаться задержками менее чем в 1 миллисекунду на более чем 100 000 запросов в секунду на один сервер с большим уровнем доступности и немедленной согласованностью данных. Это все автоматизировано и доступно «из коробки».
Что будем разрабатывать?
В этой статье я создам простой рекомендательный сервис. Предлагаемый движок будет использовать векторы сходимости для рекомендации продукта — в нашем случае, фильмов — клиенту. Алгоритм элементарный, и предоставляет стартовую площадку для реальных исследований рекомендаций.
Для обеспечения эффективной работы рекомендательного сервиса Вам необходима БД, которая может выгружать данные очень быстро, настолько что, понадобится лишь несколько запросов для выявления полноценной рекомендации. Если Ваша база данных работает очень медленно, то и процесс выявления рекомендаций затянется надолго.
Вы можете использовать любую БД, в этом примере я буду использовать Aerospike NoSQL БД.
Вы построите сервис, который принимает HTTP GET запрос вида:
http://localhost:8080/aerospike/recommmendation/{user}
Сервис ответит следующим JSON массивом рекомендаций:
[ {"expiration":130019315, "bins": {"title":"Classic Albums: Meat Loaf: Bat Out of Hell", "yearOfRelease":"1999"}, "generation":4}, {"expiration":130019337, "bins": {"title":"Rudolph the Red-Nosed Reindeer", "yearOfRelease":"1964"}, "generation":4}, {"expiration":130019338, "bins":{"title":"The Bad and the Beautiful", "yearOfRelease":"1952"}, "generation":4}, {"expiration":130019384, "bins": {"title":"Jingle All the Way","yearOfRelease":"1996"}, "generation":4}, {"expiration":130019386, "bins": {"title":"The Killing","yearOfRelease":"1956"}, "generation":4}, {"expiration":130019400, "bins": {"title":"Silkwood","yearOfRelease":"1983"},"generation":4}, {"expiration":130019404,"bins":{"title":"Chain of Command","yearOfRelease":"2000"}, "generation":4}]
Каждый элемент JSON массива содержит 3 поля: generation, expiration и bins. Generation — это число используемое Aerospike для многопоточности, которое изменяется каждый раз когда происходит изменение записи. Expiration — это дата (time to live) в секундах, при наступлении которой запись автоматически удалится из кластера. Bins — это список пар имя/значение, в котором содержится данные записи. Bins похожи на столбцы в реляционных БД. Каждый объект или запись могут иметь множество бинов.
Алгоритм выявления рекомендаций
Будем разрабатывать поведенческий рекомендательный движок. Есть три категории объектов: Клиенты, Рейтинги и Фильмы. Клиенты идентифицируются случайными идентификаторами. Есть несколько доступных операций — просмотр фильма или выставление рейтинга фильму. Идентификатор фильма также абстрактное число.
В нашей системе, клиенты смотрят и оценивают фильмы. На основании их оценок, сервис определяет для других клиентов интересны ли им для просмотра некоторые фильмы.
Профиль клиента содержит историю его просмотров и рейтинги, и Фильм содержит список людей оценивших его.
Простая задача нахождения рекомендаций — это найти другого клиента, который похож на заданного клиента и рекомендовать продукты, которые понравились другому клиенту. Хорошей идеей является исключить дубликаты, так что список рекомендованных фильмов будет состоять из фильмов, которые заданный клиент еще не смотрел..
Данные, которые мы будем использовать в этом упражнении это моделируемый набор данных, который состоит из Фильмов просмотренных Клиентами, похожий на данные любого медиа сайта как NetFlix, Hulu, или Tivo. В этой симуляции есть только около 25 фильмов в датасете.
Схема данных
Aerospike имеет гибкую NoSQL модель данных. Set может быть использован для группировки записей, как таблица в реляционной БД , но без ограничений, применяемых к записям в Set.
Данные в этом примере хранятся в двух Aerospike сетах (Sets):
- MOVIE_TITLES
- MOVIE_CUSTOMERS
Рейтинги
Рейтинг это подзапись (sub-record), которая хранит мап (map) значений. Он хранится в Large List. Large List хранится в Bin в обоих записях: Сustomer record и Movie record. Значения в мапе это:
customer-id | movie-id | rating | date |
---|---|---|---|
String | String | Integer | String |
Фильмы
Запись Movie содержит некоторые детали о фильме, как Title (Название) и Year of release (Год выпуска),но более важен список тех кто просмотрел его, пользовательский рейтинг и когда он был выставлен. Этот список важен при определении того кто наиболее похожий клиент.
Move ID (primary key) | YearOfRelease | Title | WATCHED_BY | Rating |
---|---|---|---|---|
String | String | String | Large Stack of Ratings (Aerospike), List (MongoDB) | Integer |
Клиенты
Запись Customer содержит ID клиента и список просмотренных и оцененных фильмов. Можно было бы разместить больше дополнительных атрибутов клиента, но для примера запись просто содержит список рейтингов.
Customer ID (primary key) | MOVIES_WATCHED |
---|---|
String | Large Stack of Ratings (Aerospike), List (MongoDB) |
Как будем искать схожесть?
Схожесть может быть найдена используя несколько алгоритмов,есть множество научных книг, в которых описываются функции высшей математики с помощью которых можно найти схожесть. В этом примере, мы будем использовать очень простой алгоритм, используя косинусную схожесть для получения простой оценки. Подробнее о ней можете прочесть в другой моей статье.
Сценарий
- Jane Doe входит в приложение
- Получаем профиль Jane
- Получаем запись Movie для каждого фильма, который Jane просмотрела. Если число фильмов мало, Вы можете использовать батчевую операцию в Aerospike, которая вытащит список записей за один проход. Если оно большое, лучше получать их частями.
- Для каждого фильма:
- Получаем профиль каждого просмотревшего данный фильм пользователя
- Смотрим насколько данный профиль схож с профилем Jane, задав ему оценку схожести
- Используя профиль пользователя с самой большой оценкой схожести, рекомендуем фильмы из профиля этого пользователя, которые Jane еще не смотрела.
Это очень элементарная техника и она полезна только как иллюстрация, и в ней есть несколько недостатков:
- Представьте, что Jane просмотрела Гарри Поттера. Было бы глупо вычислять схожесть, используя профили пользователей, которые просмотрели этот фильмы, потому что очень большое количество людей посмотрели Гарри Поттера. Если обобщить эту идею, то фильмы, с количеством просмотров превышающего некоторые порог должны быть исключены.
- Косинусная схожесть предполагает, что каждый элемент в векторе имеет одинаковый вес. Элементы в наших векторах это movie ID и рейтинг фильма также.
Продолжение во второй части…