Рубрики
Без рубрики

Создание механизма рекомендаций, подобного Amazon, с использованием Slash GraphQL

[[[[TL;DR; Начните использовать продукт Dgraph Slash GraphQL и подключитесь к приложению Spring Boot whi… Помечено как graphql, учебное пособие, java, веб-разработчик.

[TL;ДР; Начните использовать продукт Graphs Slash GraphQL и подключитесь к приложению Spring Boot, которое будет действовать как простой рекомендательный сервис RESTful, подобный Amazon.]

Еще в начале 2000-х я работал над проектом по внедрению решения для электронной коммерции от Art Technology Group (ATG), которое сейчас принадлежит Oracle. Продукт ATG Dynamo был впечатляющим решением, поскольку он включал уровень сохраняемости и модуль сценариев . В то время такие компании, как Target и Best Buy, использовали решение Dynamo, используя модуль сценариев для предоставления рекомендаций заказчику.

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

С тех пор я всегда хотел создать простой механизм рекомендаций, что и является моей целью для этой публикации.

О примере рекомендаций

Я хотел упростить задачу и создать несколько базовых объектов домена для механизма рекомендаций. В этом примере решение будет давать рекомендации для музыкальных исполнителей, а базовый объект Artist довольно прост:

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Artist {
   private String name;
}

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

Как и следовало ожидать, клиенты будут оценивать художников по шкале от 1 до 5, где значение пять представляет собой наилучший возможный результат. Конечно, возможно (и ожидается), что клиенты не будут оценивать каждого художника. Клиент будет представлен (опять же) очень простым объектом Customer:

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Customer {
   private String username;
}

Концепция оценки заказчиком исполнителя будет отражена в следующем объекте оценки:

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Rating {
   private String id;
   private double score;
   private Customer by;
   private Artist about;
}

В моих обычных усилиях по программированию на Java я, скорее всего, использовал бы private Customer customer и private Artist artist для своих объектов, но я хотел следовать шаблону, используемому графическими базами данных, где я использую переменные типа by и о вместо этого.. Это должно стать более ясным по мере продолжения статьи.

Dgraph Косая черта GraphQL

С ростом популярности графических баз данных я почувствовал, что в моем исследовании по созданию механизма рекомендаций должна использоваться графическая база данных. В конце концов, GraphQL стал популярным языком для общения с сервисами о графиках. Хотя у меня есть только некоторые знания о графических базах данных, мой анализ, похоже, привел к выводу, что графическая база данных является правильным выбором для этого проекта и часто является источником рекомендаций для реальных сервисов. Графические базы данных — отличное решение, когда связи (ребра) между вашими данными (узлами) так же важны, как и сами данные, и механизм рекомендаций является идеальным примером.

Однако, поскольку я только начинаю работать с графическими базами данных, я, конечно, не хотел беспокоиться о запуске контейнера или локальном запуске базы данных GraphQL. Вместо этого я хотел найти поставщика SaaS. Я решил использовать полностью управляемый серверный сервис Graphs, называемый Slash GraphQL . Это размещенное собственное решение GraphQL. Служба Slash GraphQL была выпущена 10 сентября 2020 года и может быть включена по следующей ссылке. Платформа предлагает бесплатную пробную версию, которая будет работать для этой статьи (затем переходит на фиксированную плату в размере 9,99 доллара США в месяц за данные объемом до 5 ГБ).

Платформа предлагает бесплатную пробную версию, которая будет работать для этой статьи (затем переходит на фиксированную плату в размере 9,99 доллара США в месяц за данные объемом до 5 ГБ).

После запуска этого URL-адреса можно создать новую учетную запись с помощью обычных служб авторизации:

В моем примере я создал серверную часть под названием “spring-boot-demo”, которая в конечном итоге привела к следующей панели мониторинга:

Процесс начала работы был быстрым и бесплатным, что облегчило настройку службы Slash GraphQL.

Настройка Slash GraphQL

Как и в случае с любым решением для баз данных, мы должны написать схему и развернуть ее в базе данных. С помощью Slash GraphQL это было быстро и легко:

type Artist {
   name: String! @id @search(by: [hash, regexp])
   ratings: [Rating] @hasInverse(field: about)
}

type Customer {
   username: String! @id @search(by: [hash, regexp])
   ratings: [Rating] @hasInverse(field: by)
}

type Rating {
   id: ID!
   about: Artist!
   by: Customer!
   score: Int @search
}

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

Имея схему на месте, я смог быстро заполнить некоторую базовую информацию об исполнителе:

mutation {
 addArtist(input: [
   {name: "Eric Johnson"},
   {name: "Genesis"},
   {name: "Led Zeppelin"},
   {name: "Rush"},
   {name: "Triumph"},
   {name: "Van Halen"},
   {name: "Yes"}]) {
   artist {
     name
   }
 }
}

В то же время я добавил несколько вымышленных записей о клиентах:

mutation {
 addCustomer(input: [
   {username: "Doug"},
   {username: "Jeff"},
   {username: "John"},
   {username: "Russell"},
   {username: "Stacy"}]) {
   customer {
     username
   }
 }
}

В результате пять клиентов предоставят оценки семи художникам, используя следующую таблицу:

Пример процесса оценки показан ниже:

mutation {
 addRating(input: [{
   by: {username: "Jeff"},
   about: { name: "Triumph"},
   score: 4}])
 {
   rating {
     score
     by { username }
     about { name }
   }
 }
}

Теперь, когда данные Slash GraphQL настроены и запущены, я могу переключать передачи и работать со службой Spring Boot.

Алгоритм Оценки Наклона Один

В 2005 году исследовательская работа Дэниела Лемира и Анны Маклахлан представила семейство алгоритмов совместной фильтрации Slope One. Эта простая форма совместной фильтрации на основе элементов, похоже, идеально подходит для службы рекомендаций, поскольку она учитывает оценки других клиентов, чтобы оценить товары, не оцененные для данного клиента.

В псевдокоде Служба рекомендаций будет достигать следующих целей:

  • получить рейтинги, доступные для всех исполнителей (по всем клиентам)
  • создайте карту<Клиент, Карта<Исполнитель, Двойной>> из данных, которая представляет собой карту клиента, содержащую всех исполнителей и их рейтинги
  • оценка от 1 до 5 будет преобразована в простой диапазон от 0,2 (худший рейтинг 1) до 1,0 (лучший рейтинг 5).

После создания карты клиента ядро обработки оценок Slope One будет выполняться путем вызова класса Slope One:

  • заполнить карту<Исполнитель, Карта<Исполнитель, Двойной>> используется для отслеживания различий в рейтингах от одного клиента к другому
  • заполнить карту<Исполнитель, Карта<Исполнитель, Целое число>> используется для отслеживания частоты подобных оценок
  • используйте существующие карты для создания карты HashMap Double>>, которая содержит прогнозируемые оценки для товаров, не оцененных для данного клиента HashMap Double>>, которая содержит прогнозируемые оценки для товаров, не оцененных для данного клиента Double>>, которая содержит прогнозируемые оценки для товаров, не оцененных для данного клиента

В этом примере выбирается случайный Клиент и анализируется соответствующий объект из карты HashMap Double>> projectedData map, чтобы вернуть следующие результаты: HashMap Double>> projectedData map, чтобы вернуть следующие результаты: Double>> projectedData map, чтобы вернуть следующие результаты:

{
   "matchedCustomer": {
       "username": "Russell"
   },
   "recommendationsMap": {
       "Artist(name=Eric Johnson)": 0.7765842245950264,
       "Artist(name=Yes)": 0.7661904474477843,
       "Artist(name=Triumph)": 0.7518039724158979,
       "Artist(name=Van Halen)": 0.7635436007978691
   },
   "ratingsMap": {
       "Artist(name=Genesis)": 0.4,
       "Artist(name=Led Zeppelin)": 1.0,
       "Artist(name=Rush)": 0.6
   },
   "resultsMap": {
       "Artist(name=Eric Johnson)": 0.7765842245950264,
       "Artist(name=Genesis)": 0.4,
       "Artist(name=Yes)": 0.7661904474477843,
       "Artist(name=Led Zeppelin)": 1.0,
       "Artist(name=Rush)": 0.6,
       "Artist(name=Triumph)": 0.7518039724158979,
       "Artist(name=Van Halen)": 0.7635436007978691
   }
}

В приведенном выше примере пользователь “Рассел” был выбран случайным образом. При взгляде на исходную таблицу (выше) Рассел предоставил оценки только для Genesis, Led Zeppelin и Rush. Единственным артистом, которым он по-настоящему восхищался, был Led Zeppelin. Эта информация включена в объект карты рейтингов, а также в объект Карты результатов.

Объект Карты результатов включает прогнозируемые рейтинги для четырех других художников: Эрика Джонсона, Yes, Triumph и Ван Халена. Чтобы упростить задачу, в полезную нагрузку включена карта рекомендаций, которая включает только исполнителей, которые не были оценены Расселом.

Основываясь на других отзывах, Служба рекомендаций немного отдала бы предпочтение Эрику Джонсону по сравнению с остальными четырьмя пунктами — с оценкой 0,78, что почти равно четырем в пятибалльной рейтинговой системе.

Служба Рекомендаций

Чтобы использовать службу рекомендаций, сервер Spring Boot просто должен быть запущен и настроен для подключения к облачному экземпляру Slash GraphQL. Конечная точка GraphQL на панели управления GraphQL с косой чертой может быть указана в приложении.yml как slash-graph-ql.hostname или путем передачи значения через переменную среды ${SLASH_GRAPH_QL_HOSTNAME}.

Механизм базовых рекомендаций можно вызвать, используя следующий RESTful URI:

GET – {spring-boot-service-host-name}/рекомендовать

Это действие настраивается контроллером рекомендаций, как показано ниже:

@GetMapping(value = "/recommend")
public ResponseEntity recommend() {
   try {
       return new ResponseEntity<>(recommendationService.recommend(), HttpStatus.OK);
   } catch (Exception e) {
       return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
   }
}

Который вызывает RecommendationService:

@Slf4j
@RequiredArgsConstructor
@Service
public class RecommendationService {
   private final ArtistService artistService;
   private final CustomerService customerService;
   private final SlashGraphQlProperties slashGraphQlProperties;

   private static final String RATING_QUERY = "query RatingQuery { queryRating { id, score, by { username }, about { name } } }";

   public Recommendation recommend() throws Exception {
       ResponseEntity responseEntity = RestTemplateUtils.query(slashGraphQlProperties.getHostname(), RATING_QUERY);
      try {
           ObjectMapper objectMapper = new ObjectMapper();
           SlashGraphQlResultRating slashGraphQlResult = objectMapper.readValue(responseEntity.getBody(), SlashGraphQlResultRating.class);
           log.debug("slashGraphQlResult={}", slashGraphQlResult);
           return makeRecommendation(slashGraphQlResult.getData());
       } catch (JsonProcessingException e) {
           throw new Exception("An error was encountered processing responseEntity=" + responseEntity.getBody(), e);
       }
   }
...
}

Пожалуйста, обратите внимание – что-то, что может быть упущено при беглом взгляде на этот код, – это мощь и простота в возможности извлечения подграфа для выполнения рекомендации. В приведенном выше примере строка slashGraphQlResult.get Data() предоставляет подграф методу make Recommendation() .

RATING_QUERY – это ожидаемый формат GraphQL с косой чертой для извлечения объектов рейтинга. Остальные шаблонные утилиты.метод query() является частью статического служебного класса, чтобы все оставалось СУХИМ (не повторяйтесь).:

public final class RestTemplateUtils {
   private RestTemplateUtils() { }
   private static final String MEDIA_TYPE_GRAPH_QL = "application/graphql";
   private static final String GRAPH_QL_URI = "/graphql";

   public static ResponseEntity query(String hostname, String query) {
       RestTemplate restTemplate = new RestTemplate();
       HttpHeaders headers = new HttpHeaders();
       headers.setContentType(MediaType.valueOf(MEDIA_TYPE_GRAPH_QL));
       HttpEntity httpEntity = new HttpEntity<>(query, headers);
       return restTemplate.exchange(hostname + GRAPH_QL_URI, HttpMethod.POST, httpEntity, String.class);
   }
}

Как только объект slashGraphQlResult извлекается, вызывается частный метод make Recommendation(), который возвращает следующий объект рекомендации. (Это было показано выше в формате JSON):

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Recommendation {
   private Customer matchedCustomer;
   private HashMap recommendationsMap;
   private HashMap ratingsMap;
   private HashMap resultsMap;
}

Вывод

В этой статье был создан экземпляр Graph Slash GraphQL с новой схемой и загружены образцы данных. Эти данные затем использовались службой Spring boot, которая служила базовым механизмом рекомендаций. Для тех, кто заинтересован в полном исходном коде, пожалуйста, ознакомьтесь с репозиторием GitLab :

С точки зрения затрат, я весьма впечатлен структурой, которую предоставляет Slash GraphQL. На экране новой учетной записи было указано, что у меня есть 10 000 кредитов для бесплатного использования в месяц. За все время, пока я использовал Slash GraphQL для создания прототипа и создания всего для этой статьи, я использовал всего 292 кредита. Для тех, кому требуется более 10 000 кредитов, 45 долларов США (USD) в месяц позволяют получить 100 000 кредитов, а 99 долларов США (USD) в месяц – 250 000 кредитов.

Использование графической базы данных в первый раз действительно представляло собой небольшую кривую обучения, и я уверен, что есть гораздо больше, чем я могу узнать, продолжая это упражнение. Я почувствовал, что Slash GraphQL превзошел мои ожидания благодаря возможности изменять схему по мере того, как я узнавал больше о своих потребностях. Как разработчик функций, это очень важный аспект, который следует учитывать, особенно по сравнению с тем же сценарием с традиционной базой данных.

В моей следующей статье я введу в этот процесс клиент Angular (или React), который будет напрямую взаимодействовать с GraphQL и службой рекомендаций, запущенной в Spring Boot.

(опубликовано с разрешения Джона Вестера)

Оригинал: “https://dev.to/mbogan/building-an-amazon-like-recommendation-engine-using-slash-graphql-473d”