Вокруг языка R сложилось отличное сообщество. По приблизительным оценкам, его используют более 2 миллионов человек в мире. Бесчисленное множество исследователей из всевозможных областей создают фантастические модели и делятся своим кодом. Мы, я имею ввиду практиков прикладных наук, очень часто создаем, сравниваем и выбираем модели в R.

Но что дальше? Что после того, когда ты, наконец, находишь наилучшую рабочую модель? Именно этот вопрос и превращает исследователя в разработчика ПО. Мы отправляем модели в продакшен. С помощью них мы контролируем процессы и прогнозируем результаты. В этом весь смысл. Но как?

Продвинутые продакшен-системы могут различаться по структуре и имени. Если вы работаете с R и хотите отправить код в продакшен, то перед вами два варианта: Shiny и Plumber.

Shiny  —  это фреймворк R, заточенный под создание веб-приложений. И хотя его популярность растет, я не большой фанат этого инструмента по ряду причин. 

Второй вариант, который я считаю лучшим способом для интеграции приложений R в любую систему ПО,  —  это Plumber. Статья посвящена именно ему. К ее завершению вы создадите в R свой первый API при помощи Plumber. 

Приступим!

Пара слов об использовании R в продакшене

Споры по поводу пригодности R в качестве языка для продакшена не умолкают. До появления Plumber особо мы эту область не затрагивали.

Быстрый поиск легко покажет вам, какие языки в индустрии разработки ПО наиболее популярны для бэкенда. R никак в этот список не входит. Для создания более устойчивых, надежных и масштабируемых серверных приложений больше подходит множество других языков. Никакая опытная команда не рассматривает использование R в среде продакшена. Но почему я все равно люблю Plumber и вообще пишу эту статью?

Мир, в котором мы живем, не поделен однозначно на черное и белое, то же касается и индустрии ПО. Невозможно четко разделить сферу разработки и продакшена. Особенно эта неделимость очевидна в стартапах, небольших компаниях, студенческих проектах и академической среде. Всего несколько гигантов могут позволить себе такую роскошь, и если вы к ним не относитесь, то вам придется использовать языки вроде R и Python в продакшене.

Что такое API?

Мы уже затронули тему необходимости отправки моделей в продакшен и в текущем разделе ее проясним.

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

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

API могут различаться в своей сложности и назначении, поэтому они подразделяются по присущим им признакам, в результате чего мы имеем разные их виды. Тот, который мы будем создавать с помощью Plumber, зовется REST API, или RESTful API. Сейчас о его понимании вам особо задумываться не стоит, просто помните, что в REST API для взаимодействия между сторонами используется простой язык в виде HTTP-методов.

Как работает Plumber?

Процесс работы в Plumber можно поделить на два основных этапа.

  1. Сначала мы создаем скрипт, который будем использовать в качестве основного сервиса API. Именно он будет выполняться при запросе к API. Подготовка такого скрипта сложностей не представляет. Для каждой из его частей мы оставляем комментарии (в данном случае они несколько отличаются от стандартных комментариев в R), обозначая выполняемую этой частью роль. Эти комментарии позволят Plumber правильным образом превратить скрипт в API.
  2. После установки Plumber можно использовать его функцию pr() для преобразования скрипта в Plumber API.

Начнем с простого скрипта

Скрипт будет состоять всего из нескольких строк. Предметная область  —  моделирование по методу Монте-Карло. Степень вашего знакомства с этой предметной областью будет отличаться в зависимости от прежнего опыта, но для большинства прикладных ученых она вполне знакома. Здесь мы используем технику Монте-Карло для решения задачи по вычислению определенного интеграла.

mcIntegration <- function(trials , mean_p , sd_p , upper_limit , lower_limit) { 
trials <- as.numeric(trials)
numbers <- rnorm(n = as.numeric(trials) , mean = as.numeric(mean_p) , sd = as.numeric(sd_p))
mc.integral <- sum(numbers >= as.numeric(lower_limit) & numbers <= as.numeric(upper_limit))/as.numeric(upper_limit)
mc.integral

}

Мы написали функцию для поиска площади под нормальной кривой с различными параметрами, которые сообщает пользователь. Мы довольны своей работой и хотим поделиться ей с другими. Проще всего для этого создать API, чем мы далее и займемся, взяв за основу написанный нами скрипт R.

Превращение скрипта в API

Для превращения кода выше в API мы внесем в него особые комментарии, которые называются “аннотациями”. В целях простоты мы используем ограниченное их число, однако можно создавать и более сложные API, добавляя более замысловатые аннотации. Подробный их список приводится в официальной документации Plumber.

Для начала назовем API и сопроводим его описанием. В этом помогут следующие аннотации:

@apiTitle
@apiDescription

API будет возвращать результат на основе предоставляемых ему входных данных. Обозначим мы эти данные с помощью такой аннотации:

@param

В завершении мы используем аннотацию, указывающую, какой тип запросов этот API выполняет. Поскольку наш API возвращает значение после выполнения кода, он выполняет запрос GET.

@get

В конечном виде код должен выглядеть так:

#* @apiTitle  Monte Carlo Integration
#* @apiDescription An API That Computes Definite Intergrals with Monte Carlo Simulation
#* @param trials
#* @param mean_p
#* @param sd_p
#* @param upper_limit
#* @param lower_limit
#* @get /area
mcIntegration <- function(trials , mean_p , sd_p , upper_limit , lower_limit) {
trials <- as.numeric(trials)
numbers <- rnorm(n = as.numeric(trials) , mean = as.numeric(mean_p) , sd = as.numeric(sd_p))
mc.integral <- sum(numbers >= as.numeric(lower_limit) & numbers <= as.numeric(upper_limit))/as.numeric(upper_limit)
mc.integral

}

Мы перестроили исходный код и сделали все, что от нас требовалось. Остальное за пакетом plumber.

mcInt <- pr("plumber2.R")
pr_run(mcInt)

Проверим

После запуска файла API всплывает новое окно, в котором мы видим основные элементы этого интерфейса.

Посмотрим, как он работает. Вы можете передать любые параметры на свое усмотрение. Я же протестирую его с такими:

На основе этих параметров он возвращает следующий результат:

Развертывание

Вот мы и создали рабочий API. Миссия выполнена! Можно сказать, что он находится в продакшене. Мы сделали это, чтобы автоматизировать скрипт R в отношении получения данных и предоставления вывода. К сожалению, доступен он лишь с нашей машины. Последним этапом будет развертывание программы на платформе, где она окажется доступна для других.

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

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

Второй этап намного проще и заключается в выборе облачного сервиса для размещения API.

Вот вы и раскрыли свой рабочий скрипт R для автоматизированной продакшен-среды.

Заключение

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

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Uğurcan Demir: Creating APIs in R With Plumber

Предыдущая статьяЧто такое закрепление сертификата в Android
Следующая статьяКак сократить время начальной загрузки веб-приложения