Я хотел иметь возможность упаковать DataFrames в jar файл Scala и получить к ним доступ в R. Конечной целью является создание способа доступа к определенным и часто используемым таблицам базы данных в Python, R и Scala без написания другой библиотеки для каждого.
Чтобы сделать это, я создал файл jar в Scala с функциями, которые используют библиотеку SparkSQL для запроса базы данных и получения требуемых DataFrames. Я хотел иметь возможность называть эти функции в R без создания другой JVM, поскольку Spark уже работает на JVM в R. Однако использование JVM Spark не отображается в SparkR API. Чтобы сделать его доступным и сделать Java-методы вызываемыми, я изменил "backend.R", "generics.R", "DataFrame.R" и "NAMESPACE" в пакете SparkR и перестроил пакет:
В "backend.R" я сделал формальные методы "callJMethod" и "createJObject":
setMethod("callJMethod", signature(objId="jobj", methodName="character"), function(objId, methodName, ...) {
stopifnot(class(objId) == "jobj")
if (!isValidJobj(objId)) {
stop("Invalid jobj ", objId$id,
". If SparkR was restarted, Spark operations need to be re-executed.")
}
invokeJava(isStatic = FALSE, objId$id, methodName, ...)
})
setMethod("newJObject", signature(className="character"), function(className, ...) {
invokeJava(isStatic = TRUE, className, methodName = "<init>", ...)
})
Я модифицировал "generics.R", чтобы также содержать эти функции:
#' @rdname callJMethod
#' @export
setGeneric("callJMethod", function(objId, methodName, ...) { standardGeneric("callJMethod")})
#' @rdname newJobject
#' @export
setGeneric("newJObject", function(className, ...) {standardGeneric("newJObject")})
Затем я добавил экспорт этих функций в файл NAMESPACE:
export("cacheTable",
"clearCache",
"createDataFrame",
"createExternalTable",
"dropTempTable",
"jsonFile",
"loadDF",
"parquetFile",
"read.df",
"sql",
"table",
"tableNames",
"tables",
"uncacheTable",
"callJMethod",
"newJObject")
Это позволило мне вызвать функции Scala, которые я написал, не запустив новую JVM.
В методах Scala я написал возвращаемые DataFrames, которые при возврате являются "jobj" s в R, но SparkR DataFrame - это среда + jobj. Чтобы превратить эти данные DataFrames в SparkR DataFrames, я использовал функцию dataFrame() в "DataFrame.R", которую я также сделал доступной, следуя приведенным выше шагам.
Затем я смог получить доступ к DataFrame, который я "построил" в Scala из R, и использовать все функции SparkR на этом DataFrame. Мне было интересно, есть ли лучший способ сделать такую кросс-язычную библиотеку, или если есть какая-то причина, что Spark JVM не должен быть общедоступным?