В этом материале я хочу подробно показать, как можно при помощи R в Microsoft SQL Server реализовать получение данных из Google Analytics (и вообще из любого API).
Благодарности:
Поскольку я ни разу не маркетолог мне требовалась помощь специалиста. Тестовый кабинет и доступ Google Analytics (GA) организовал Алексей Селезнёв , а также давал дельные консультации.
Он профессионально занимается аналитикой в маркетинге. И в качестве благодарности за помощь упоминается здесь телеграмм канал Алексея, где он ведет свою активность.
Задача — у нас есть сервер MS SQL и мы хотим получать данные в DWH по API
Для подключения к Google Analytics (GA) будем использовать пакет googleAnalyticsR.
Данный пакет выбран, для примера в силу своей популярности. Вы можете использовать другой пакет, например: RGoogleAnalytic.
Подходы к решению задачи будут одинаковыми.
Устанавливаем R на сервере MS SQL
делается это через стандартный интерфейс установки компонентов MS SQL.
- Это R с которым будет работать непосредственно SQL Server (вызываться в SQL запросах).
- Клиентская копия R с ним можно будет работать из RStudio не боясь сломать что-то на сервере базы данных.
Соглашаемся с лицензией и обращаем внимание что будет установлен не обыкновенный R, а Microsoft R Open
В двух словах что это такое:
Microsoft берет R Open его облагораживает своими пакетами и так же бесплатно распространяет.
Соответственно пакеты этой версии R доступны для скачивания не в CRAN а в MRAN.
Но и это еще не всё. На самом деле при установке MS SQL мы получаем не чистый MRAN, а нечто большее — Microsoft ML Server.
Для нас это означает, что в комплекте библиотек R будут еще дополнительные пакеты – RevoScaleR.
RevoScaleR предназначен, для обработки больших данных и построение моделей машинного обучения на значительных датасетах.
Эту информацию надо иметь в виду потому, что велика вероятность вопросов связанных с разными версиями пакетов R.
После установки компонентов мы получаем дефолтный интерфейс взаимодействия с R от Microsoft.
Эта консоль не самое удобное что можно использовать, поэтому сразу скачиваем и устанавливаем бесплатную версию RStudio.
Настраиваем SQL server на работу с R
В SSMS выполняем следующие скрипты:
Разрешаем на SQL сервере выполнять скрипты
sp_configure 'external scripts enabled', 1;
RECONFIGURE WITH OVERRIDE;
Рестартуем Server SQL
Убеждаемся, что скрипты R скрипты выполняются
EXECUTE sp_execute_external_script
@language =N'R',
@script=N'print(version)';
Находим расположение R пакетов, которые используются SQL сервером
declare @Rscript nvarchar(max)
set @Rscript = N'
InstaledLibrary <- library()
InstaledLibrary <- as.data.frame(InstaledLibrary$results )
OutputDataSet <- InstaledLibrary
'
EXECUTE sp_execute_external_script
@language = N'R'
, @script = @Rscript
WITH RESULT SETS (([Package] varchar(255) NOT NULL,
[LibPath] varchar(255) NOT NULL,
[Title] varchar(255) NOT NULL));
В моем случае путь до R пакетов MS SQL:
C:/Program Files/Microsoft SQL Server/MSSQL14.MSSQLSERVER/R_SERVICES/library
Запускаем RStudio.
Не исключено, что на компьютере будет установлено несколько версий R и надо убедиться, что мы работаем с версией SQL сервера.
Настройки применятся после рестарта RStudio.
Устанавливаем пакет googleAnalyticsR
В RStudio командой
library()
узнаем путь до библиотеки пакетов клиентской версии R (с которой работает RStudio)
В моем случае этот путь:
C:/Program Files/Microsoft SQL Server/140/R_SERVER/library
Через RStudio устанавливаем пакет googleAnalyticsR
Вот тут есть неочевидный нюанс:
Нельзя взять и просто так что-то записать в системные папки MS SQL. Пакеты будут сохранены во временной директории в виде ZIP архивов.
В проводнике заходим во временную папку и разархивируем все пакеты.
Разархивированные пакеты надо скопировать в директорию библиотек R Services (с которыми работает сервер MS SQL).
В моем примере это папка
C:/Program Files/Microsoft SQL Server/MSSQL14.MSSQLSERVER/R_SERVICES/library
Так же разархивированные пакеты надо скопировать в клиентскую версию R (c которой работает RStudio)
В моем примере это папка
C:/Program Files/Microsoft SQL Server/140/R_SERVER/library
(эти пути мы узнали из ранее выполненных скриптов)
Перед копированием в папку R Services лучше сохранить копию папки library, как показывает практика, случаи бывают разные и лучше иметь возможность вернуться к имеющимся пакетам.
При копировании заменяем все имеющиеся пакеты.
Что бы закрепить полученный навык повторяем упражнение.
Только теперь не устанавливаем пакеты, а обновляем все имеющиеся.
(для подключения к GA это не обязательно, но лучше иметь свежие версии всех пакетов)
В RStudio проверяемся на наличие новых пакетов
Пакеты будут загружены во временную папку.
Проделываем с ними такие же действия, как и при установке новых пакетов.
Проверяем доступ MS SQL в интернет
declare @Rscript nvarchar(max)
set @Rscript = N'
library(httr)
HEAD("https://www.yandex.ru", verbose())
'
EXECUTE sp_execute_external_script
@language = N'R'
, @script = @Rscript
Поскольку SQL Server по умолчанию не имеет доступа в интернет, скорее всего у Вас предыдущий скрипт вызовет следующую ошибку.
Открываем доступ в интернет для R скриптов из SQL.
SQL 2017
SQL2019
В SSMS
-- Создаем базу данных для примера
create database Demo
go
use Demo
go
-- Создаем схему, для объектов базы данных связанных с Google Analytics
create schema GA
go
-- Создаем таблицу для сохранения токена доступа к GA
drop table if exists [GA].[token]
create table [GA].[token](
[id] varchar(200) not null,
[value] varbinary(max)
constraint unique_id unique (id))
Получаем токен Google Analytics
В RStudio выполняем следующий код:
При этом в браузере откроется окно аутентификации в Google сервисах, надо будет выполнить вход и дать разрешение на доступ к Google Analytics.
# На всякий случай укажем тайм зону
Sys.setenv(TZ="Europe/Berlin")
library(googleAnalyticsR)
# Получаем токен
ga_auth()
PathTokenFile <- paste ( getwd(),"/", ".httr-oauth" , sep="")
TokenFile <- readBin(PathTokenFile, "raw", file.info(PathTokenFile)$size)
# Создали подключение к базе
conStr <- 'Driver={SQL Server};Server=EC2AMAZ-68OQ7JV;Database=Demo;Uid=Sa;Pwd=SaSql123'
ds <- RxOdbcData(table="ga.token", connectionString=conStr)
# Записываем токен в базу
rxWriteObject(ds, "ga_TokenFile", TokenFile)
В SSMS убеждаемся что токен от Google получен и записан в базе
Select * from [GA].[token]
Проверяем подключение к GA через RStudio
# Проверяем подключение В RStudio
Sys.setenv(TZ="Europe/Berlin")
library(googleAnalyticsR)
# Получаем токен из базы
conStr <- 'Driver={SQL Server};Server=EC2AMAZ-68OQ7JV;Database=Demo;Uid=Sa;Pwd=SaSql123' # Аутентификация в базе по пользователю
ds <- RxOdbcData(table="ga.token", connectionString=conStr)
PathTokenFile <- paste ( getwd(),"/", ".httr-oauth" , sep="")
TokenFile <- rxReadObject(ds, "ga_TokenFile")
write.filename = file(PathTokenFile, "wb")
writeBin(TokenFile, write.filename)
close(write.filename)
Sys.setenv("GA_AUTH_FILE" = PathTokenFile)
# Прошли аутентификацию
ga_auth()
# определили ga_id
account_list <- ga_account_list()
ga_id <- account_list$viewId
# Сохранили результат запроса
OutputDataSet <-google_analytics(ga_id,
start="2019-01-01",
end="2019-08-01",
metrics = "sessions",
dimensions = "date")
OutputDataSet
Если всё прошло удачно добавляем R скрипт в SQL и выполняем запрос.
drop table if exists #GA_session
create table #GA_session
(
[date] date,
[sessions] int
)
declare @Rscript nvarchar(max)
set @Rscript = N'
# Проверяем подключение В RStudio
Sys.setenv(TZ="Europe/Berlin")
library(googleAnalyticsR)
# Получаем токен из базы
conStr <- ''Driver={SQL Server};Server=EC2AMAZ-68OQ7JV;Database=Demo;Uid=Sa;Pwd=SaSql123'' # Аутентификация в базе по пользователю
ds <- RxOdbcData(table="ga.token", connectionString=conStr)
PathTokenFile <- paste ( getwd(),"/", ".httr-oauth" , sep="")
TokenFile <- rxReadObject(ds, "ga_TokenFile")
write.filename = file(PathTokenFile, "wb")
writeBin(TokenFile, write.filename)
close(write.filename)
Sys.setenv("GA_AUTH_FILE" = PathTokenFile)
# Прошли аутентификацию
ga_auth()
# определили ga_id
account_list <- ga_account_list()
ga_id <- account_list$viewId
# Сохранили результат запроса
OutputDataSet <-google_analytics(ga_id,
start="2019-01-01",
end="2019-08-01",
metrics = "sessions",
dimensions = "date")
OutputDataSet$date <- as.character(OutputDataSet$date)
'
-- print @Rscript
insert into #GA_session ([date],[sessions])
EXECUTE sp_execute_external_script
@language = N'R',
@script = @Rscript
Select *
from #GA_session
order by [date] asc
Обращаем внимание что в скрипте используется Логин и Пароль – это не очень хорошо.
Поэтому изменяем строку подключения на виндовс аутентификацию.
conStr <- ''Driver={SQL Server};Server=EC2AMAZ-68OQ7JV;Database=Demo;Trusted_Connection=true'' # Виндовс аутентификация <<<=== Лучше выбирать этот вариант – хранить пароли в скриптах неправильно
После изменения метода аутентификации надо будет добавить сервису вызывающему R права на доступ к базе.
(Конечно, лучше использовать группы пользователей, в рамках демонстрации я упростил решение)
Оформляем SQL запрос в виде процедуры
Create procedure Ga.Get_session
@Date_start date ='2019-01-01',
@Date_End date ='2019-08-01'
as
drop table if exists #GA_session
create table #GA_session
(
[date] date,
[sessions] int
)
declare @Rscript nvarchar(max)
set @Rscript =CONCAT( N'
# Проверяем подключение В RStudio
Sys.setenv(TZ="Europe/Berlin")
library(googleAnalyticsR)
# Получаем токен из базы
conStr <- ''Driver={SQL Server};Server=EC2AMAZ-68OQ7JV;Database=Demo;Trusted_Connection=true'' # Виндовс аутентификация <<<=== Лучше выбирать этот вариант - никто пароля неувидит
ds <- RxOdbcData(table="ga.token", connectionString=conStr)
PathTokenFile <- paste ( getwd(),"/", ".httr-oauth" , sep="")
TokenFile <- rxReadObject(ds, "ga_TokenFile")
write.filename = file(PathTokenFile, "wb")
writeBin(TokenFile, write.filename)
close(write.filename)
Sys.setenv("GA_AUTH_FILE" = PathTokenFile)
# Прошли аутентификацию
ga_auth()
# определили ga_id
account_list <- ga_account_list()
ga_id <- account_list$viewId
# Сохранили результат запроса
OutputDataSet <-google_analytics(ga_id,
start="' , @Date_start ,N'",
end="' , @Date_End ,N'",
metrics = "sessions",
dimensions = "date")
OutputDataSet$date <- as.character(OutputDataSet$date)
'
)
-- print @Rscript
insert into #GA_session ([date],[sessions])
EXECUTE sp_execute_external_script
@language = N'R',
@script = @Rscript
Select *
from #GA_session
order by [date] asc
Проверяем работу процедуры
-- Параметры по умолчанию
exec Ga.Get_session
-- Получаем сессии за заданный период
exec Ga.Get_session
@Date_start ='2019-08-01',
@Date_End ='2019-09-01'
R скрипт не сложный его всегда можно скопировать в R Studio. Доработать и сохранить в SQL процедуре.
Например я поменял только параметр dimensions и уже могу загружать landingPage по датам.
Create procedure [GA].[Get_landingPage_session]
@Date_start date ='2019-01-01',
@Date_End date ='2019-08-01'
as
drop table if exists #GA_session
create table #GA_session
(
[date] date,
landingPagePath nvarchar(max),
[sessions] int
)
declare @Rscript nvarchar(max)
set @Rscript =CONCAT( N'
# Проверяем подключение В RStudio
Sys.setenv(TZ="Europe/Berlin")
library(googleAnalyticsR)
# Получаем токен из базы
conStr <- ''Driver={SQL Server};Server=EC2AMAZ-68OQ7JV;Database=Demo;Trusted_Connection=true'' # Виндовс аутентификация <<<=== Лучше выбирать этот вариант - никто пароля неувидит
ds <- RxOdbcData(table="ga.token", connectionString=conStr)
PathTokenFile <- paste ( getwd(),"/", ".httr-oauth" , sep="")
TokenFile <- rxReadObject(ds, "ga_TokenFile")
write.filename = file(PathTokenFile, "wb")
writeBin(TokenFile, write.filename)
close(write.filename)
Sys.setenv("GA_AUTH_FILE" = PathTokenFile)
# Прошли аутентификацию
ga_auth()
# определили ga_id
account_list <- ga_account_list()
ga_id <- account_list$viewId
# Сохранили результат запроса
OutputDataSet <-google_analytics(ga_id,
start="' , @Date_start ,N'",
end="' , @Date_End ,N'",
metrics = "sessions",
dimensions = c("date" ,"landingPagePath"))
OutputDataSet$date <- as.character(OutputDataSet$date)
'
)
-- print @Rscript
insert into #GA_session ([date],landingPagePath,[sessions])
EXECUTE sp_execute_external_script
@language = N'R',
@script = @Rscript
Select *
from #GA_session
order by [date] asc
проверяемся
exec [GA].[Get_landingPage_session]
В принципе всё готово.
Хотелось бы отметить, что про помощи R через SQL можно получать данные из любого API
Например: получение курса валют
-- https://www.cbr-xml-daily.ru
Declare @script nvarchar(max)
set @script = N'
encoding = "utf-8"
Sys.setlocale("LC_CTYPE", "russian")
Sys.setenv(TZ="Europe/Berlin")
library(httr)
url <- "https://www.cbr-xml-daily.ru/daily_json.js"
resp <- GET(url)
library(jsonlite)
Response <- fromJSON(content(resp, as = "text"))
OutputDataSet <- data.frame(matrix(unlist(Response$Valute$USD), nrow=1, byrow=T),stringsAsFactors=FALSE)
OutputDataSet <- rbind(OutputDataSet,data.frame(matrix(unlist(Response$Valute$EUR), nrow=1, byrow=T),stringsAsFactors=FALSE))
'
EXEC sp_execute_external_script
@language = N'R'
, @script = @script
with result SETS UNDEFINED
или получение данных из первого попавшегося API, какие-то фермы в австралии …
-- https://dev.socrata.com/
Declare @script nvarchar(max)
set @script = N'
library(httr)
url <- "https://data.ct.gov/resource/y6p2-px98.json?category=Fruit&item=Peaches"
resp <- GET(url)
library(jsonlite)
Response <- fromJSON(content(resp, as = "text"))
OutputDataSet <- as.data.frame(Response)
OutputDataSet <- OutputDataSet [,
c("category" ,
"item" ,
"farmer_id" ,
"zipcode" ,
"business" ,
"l" ,
"location_1_location",
"location_1_city" ,
"location_1_state" ,
"farm_name",
"phone1" ,
"website",
"suite")]
'
EXEC sp_execute_external_script
@language = N'R'
, @script = @script
with result SETS UNDEFINED
Итого:
- пароли подключения нигде не хранятся
- права раздаются централизовано через учетные записи active directory
- дополнительных файлов настройки нет
- нет никаких питоновских файликов со скрипками, содержащими пароли к базе данных
- весь код находится в процедурах и сохраняется при бэкапировании базы данных
Бэкап базы MS SQL 2017 со всем кодом доступен тут
(для воспроизведения необходимо установить пакеты, раздать права, указать название своего сервера)
Комментарии (7)
dude_sam
06.09.2019 10:16А что если ответ от API будет в JSON размеров в 3Gb, то R спокойно его переварит, разберёт и сложит в таблицу?
FoxisII Автор
06.09.2019 10:26Конечно, желательно не запрашивать такой объем данных.
Можно выбирать данные по порциям, например по дням
Но в общем случае ответ:
Да, а почему нет?
Роль R здесь сводится к получению ответа от API и преобразование JSON.
Непосредственно в таблицу будет складывать MS SQL — а ему таблички в 3 GB это мелочи :)dude_sam
06.09.2019 13:18Такой вот хитрый API, отдающий только весь набор данных за всю историю без возможности фильтра по датам (и без уникальных ключей, так что запросить по одному полю, а затем склейить по столбцам не вариант). :(
Таблички в 3Gb, то да, а вот NVARCHAR(MAX) имеет ограничение в 2GB. И такой JSON он (MS SQL Server) уже не переваривает. :(
Вот я и хотел понять: таки R разбирает содержимое JSON в свой объект dataset, а затем из него уже вставляет в таблицу?FoxisII Автор
06.09.2019 13:22+1R разбирает содержимое JSON в свой объект dataset, а затем из него уже вставляет в таблицу?
Да, сначала JSON разбирается в DataSet
И в случае такого хитрого API это Ваш вариант
честно говоря строку в 3GB я не пробовал — но по логике если оперативки хватит, то проглотит :)
попробуйте сначала в RStudio
Naves
Пару лет назад в какой-то версии SQL Server пытался установить компонент R. Сначала потребовалась одна библиотека, потом другая, потом третья. А третья сказала, что на вашей версии windows я ставиться не буду.
Еще однажды был забавный проект с Google Analytics. Нужно было из базы MS SQL выгружать данные в GA, а именно чеки оплаты по кассе с помощью Measurement Protocol. Недолго думая просто использовал какой-то вариант вида
sp_OACreate 'MSXML2.ServerXMLHTTP'
В GA упорно не отображались транзакции после отправки POST или GET запроса. Если открыть ту же самую URL c с теми же самыми параметрами через браузер, то все появлялось.
Общались тогда через Skype, когда отправлял через чат сгенеренные скриптом строки url, то они тоже появлялись в аналитике. (кто бы сомневался)
В какой-то момент уже начал запускать wget на сервере через EXEC xp_cmdshell, все равно не отображались. Потом случайно выяснилось, что в урл нужно добавлять параметры dh и uip. Осталось непонятным, почему через браузер транзакции успешно отправлялись без этих параметров.
Потом маркетологи недоумевали, а почему же в аналитике так много клиентов без идентификаторов гугла, откуда же они берутся…
FoxisII Автор
Надеюсь моя статья поможет справляться с подобными проблемами :)