Как использовать SparkR :: read.jdb c () или sparklyr :: spark_read_jdb c () для получения результатов запроса SQL, а не всей таблицы? - PullRequest
0 голосов
/ 03 марта 2020

Я обычно использую RODB C локально для запросов к моим базам данных. Однако недавно наша компания перешла на Azure Databricks, который по своей природе не поддерживает соединения RODB C или другие odb c, но поддерживает соединения jdb c, которые я ранее не использовал.

I прочитал документацию для SparkR :: read.jdb c () и sparklyr :: spark_read_jdb c (), но похоже, что они извлекают из базы данных целую таблицу, а не только результаты запроса, что не подходит для меня, так как мне никогда не нужно извлекать целые таблицы и вместо этого запускать запросы, которые объединяют несколько таблиц вместе, но возвращают только очень небольшое подмножество данных в каждой таблице.

Я не могу найти метод для использования jdb c соединиться с:

(A) выполнить запрос, ссылающийся на несколько таблиц в одной базе данных

и

(B) сохранить результаты в виде фрейма данных R или чего-то такого, что может быть очень легко преобразован в фрейм данных R (такой как фрейм данных SparkR или sparklyr).

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

например, существует ли jdb c эквивалент следующего:

my_server="myserver.database.windows.net"
my_db="mydatabase"
my_username="database_user"
my_pwd="abc123Ineedabetterpassword"


myconnection <- RODBC::odbcDriverConnect(paste0("DRIVER={SQL Server};
                                 server=",my_server,";
                                 database=",my_db,";
                                 uid=",my_username,";
                                 pwd=",my_pwd))

df <- RODBC::sqlQuery(myconnection, 
"SELECT a.var1, b.var2, SUM(c.var3) AS Total_Things, AVG(d.var4) AS Mean_Stuff
FROM table_A as a 
JOIN table_B as b on a.id = b.a_id
JOIN table_C as c on a.id = c.a_id
JOIN table_D as d on c.id = d.c_id
Where a.filter_var IN (1, 2, 3, 4)
AND d.filter_var LIKE '%potatoes%'
GROUP BY
a.var1, b.var2
")

df2 <- RODBC::sqlQuery(myconnection,
"SELECT x.var1, y.var2, z.var3
FROM table_x as x
LEFT JOIN table_y as y on x.id = y.x_id
LEFT JOIN table_z on as z on x.id = z.x_id
WHERE z.category like '%vegetable%'
AND y.category IN ('A', 'B', 'C')
“)

Как мне сделать то, что дает те же результаты (два R-кадра данных df и df2), что и выше, используя коннекторы jdb c от SparkR или sparklyr, встроенные в Databricks?

Я знаю, что могу использовать искровой соединитель и некоторый код scala (https://docs.microsoft.com/en-us/azure/sql-database/sql-database-spark-connector), чтобы сохранить результаты запроса в виде фрейма данных искры, преобразовать его в глобальную временную таблицу, сохранить глобальную временную таблицу как файл данных SparkR и свернуть его в файл данных R, но этот код очень трудно читать, он требует от меня изменить язык на scala (что я не очень хорошо знаю) для одной из ячеек в моем блокноте и занимает очень долго из-за большого количества шагов. Поскольку мой R-скрипт часто начинается с нескольких запросов SQL - часто к нескольким различным базам данных - этот метод занимает очень много времени и делает мои сценарии практически нечитаемыми. Конечно, есть более простой способ?

(Мы используем блоки данных в основном для автоматизации с помощью LogicApps и Azure Data Factory, а иногда и для увеличения оперативной памяти, а не для параллельной обработки; наши данные (после извлечения) как правило, недостаточно велик, чтобы требовать распараллеливания, и некоторые модели, которые мы используем (например, lme4 :: lmer ()), не получают от этого выгоды.)

1 Ответ

0 голосов
/ 04 марта 2020

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

Вы можете использовать SparkR :: read.jdb c () с запросом, но вы должны окружить запрос в скобках и псевдоним результатов как-то, в противном случае вы получите неоднозначную синтаксическую ошибку. «Portnum», как мне кажется, прекрасно работает как 1433 по умолчанию, но если у вас база данных другого типа SQL, вам может потребоваться изменить это в URL. Затем вы можете вызвать SparkR :: collect () в SparkDataFrame, содержащем результаты запроса, чтобы преобразовать его в R-фрейм данных:

например,

myconnection <- "jdbc:sqlserver://myserver.database.windows.net:1433;database=mydatabase;user=database_user;password=abc123Ineedabetterpassword"

df <- read.jdbc( myconnection, "(
SELECT a.var1, b.var2, SUM(c.var3) AS Total_Things, AVG(d.var4) AS Mean_Stuff
FROM table_A as a 
JOIN table_B as b on a.id = b.a_id
JOIN table_C as c on a.id = c.a_id
JOIN table_D as d on c.id = d.c_id
Where a.filter_var IN (1, 2, 3, 4)
AND d.filter_var LIKE '%potatoes%'
GROUP BY
a.var1, b.var2) as result" ) %>% 
SparkR::collect()
...