我有一个SparkR脚本,可以加载一些库,还可以定义其他源脚本的函数。它的头部看起来像这样:
library(SparkR, lib.loc = c(file.path(Sys.getenv("SPARK_HOME"), "R", "lib")))
library(devtools)
library(JC.utilities) # user-created
source("path/to/clean_data.R")
其中clean_data.R
使用JM.utilities
库中的某些函数,如下所示:
clean_data <- function(df) {
...
return(JC.utilities::reformat(df))
}
在基础R中,这没有问题,因为通过获取定义了此函数的R脚本应该意味着库和函数现在处于相同的范围内。但在Spark中,当我调用clean_data()
时,我收到此错误消息:
Error in loadNamespace(name) : there is no package called ‘JM.utilities’
两个问题:
答案 0 :(得分:1)
您已在驱动程序上加载库,但未在处理单独工作区的执行程序上加载。
您需要在应用于数据框的函数中导入JC.utilities。
如果执行者上没有安装库,则需要执行此操作,或者您可以尝试执行this。
我设计了一个最小的例子,用库字符串及其函数str_length来说明我的观点:
> d<-data.frame(a=c("a", "abcd", "bb"), b=c(1,2,3))
> df <- as.DataFrame(d)
让我们尝试看看它是否适用于基本R代码:
> dapplyCollect(df, function(x) {cbind(x$a, x$b, x$b*x$b+1) })
[,1] [,2] [,3]
[1,] "a" "1" "2"
[2,] "abcd" "2" "5"
[3,] "bb" "3" "10"
有效!然后让我们尝试计算第一列的字符数(我可以使用nchar,但想法是演示如何使用库)。
> import(stringr)
> str_length("abcdef")
[1] 4
它在驱动程序中工作正常。让我们尝试一下spark:
> dapplyCollect(df, function(x) {cbind(x$a, x$b, x$b*x$b+1, str_length(x$a)) })
17/11/08 18:55:17 ERROR executor.Executor: Exception in task 0.0 in stage 10.0 (TID 10)
org.apache.spark.SparkException: R computation failed with
Error in cbind(x$a, x$b, x$b * x$b + 1, str_length(x$a)) :
could not find function "str_length"
正如我所解释的那样,在驱动程序中导入库不会将其导入到worker中。然而,那就是我需要的地方。现在让我们在dapply中导入库:
> dapplyCollect(df, function(x) {library(stringr); cbind(x$a, x$b, x$b*x$b+1, str_length(x$a)) })
[,1] [,2] [,3] [,4]
[1,] "a" "1" "2" "1"
[2,] "abcd" "2" "5" "4"
[3,] "bb" "3" "10" "2"
然后你去。