Spark 分布式计算

sparklyr支持在Spark Cluster中通过大规模运行任意R代码spark_apply()。

spark_apply()将R函数应用于Spark对象(通常是Spark DataFrame)。Spark对象是分区的,因此可以跨群集分布。你可以使用spark_apply默认分区,也可以使用group_by参数定义自己的分区。你的R函数必须返回另一个Spark DataFrame。spark_apply将在每个分区上运行您的R函数并输出单个Spark DataFrame

将R函数应用于SPARK对象

让我们举一个简单的例子。我们将使用函数I()创建的数字列表应用识别sdf_len函数。

library(sparklyr)

sc <- spark_connect(master = "local")

sdf_len(sc, 5, repartition = 1) %>%
  spark_apply(function(e) I(e))
# Source: spark [?? x 1]
     id
* 
1     1
2     2
3     3
4     4
5     5

你的R功能应设计为在R 数据帧上运行。传递的R函数spark_apply需要一个DataFrame,并返回一个可以转换为DataFrame的对象。我们可以使用该class函数来验证数据类。

sdf_len(sc, 10, repartition = 1) %>%
  spark_apply(function(e) class(e))
# Source: spark [?? x 1]
  result    
*      
1 data.frame

Spark将按散列或范围对数据进行分区,以便可以在群集中分布。在下面的示例中,我们创建了两个分区并计算每个分区中的行数。然后我们打印每个分区中的第一条记录。


trees_tbl <- sdf_copy_to(sc, trees, repartition = 2)

> trees_tbl %>%
+     spark_apply(function(e) nrow(e), names = "n")
# Source: spark [?? x 1]
      n
* 
1    15
2    16
> 
> 
> trees_tbl %>%
+     spark_apply(function(e) head(e, 1))
# Source: spark [?? x 3]
  Girth Height Volume
*     
1  8.30   70.0   10.3
2 12.9    74.0   22.2

我们可以将任意函数应用于Spark DataFrame中的分区。例如,我们可以缩放或抖动列。请注意,spark_apply将R函数应用于所有分区并返回单个DataFrame。

> trees_tbl %>%
+   spark_apply(function(e) scale(e))
# Source: spark [?? x 3]
     Girth Height  Volume
 *        
 1 -2.05   -0.607 -1.69  
 2 -1.79   -1.43  -1.69  
 3 -1.62   -1.76  -1.71  
 4 -0.134  -0.276 -0.339 
 5  0.0407  1.21   0.191 
 6  0.128   1.54   0.390 
 7  0.302  -1.27  -0.515 
 8  0.302   0.221  0.0589
 9  0.389   1.05   1.03  
10  0.477   0.221  0.434 
# ... with more rows

本质上就是传入一个DataFrame 进入spark_apply

> trees_tbl %>%
+     spark_apply(function(e) lapply(e, jitter))
# Source: spark [?? x 3]
   Girth Height Volume
 *     
 1  8.30   70.1   10.3
 2  8.58   64.9   10.3
 3  8.79   63.2   10.2
 4 10.5    72.1   16.4
 5 10.7    80.8   18.8
 6 10.8    83.0   19.7
 7 11.0    66.1   15.6
 8 11.0    74.9   18.2
 9 11.1    80.0   22.6
10 11.2    75.1   19.9
# ... with more rows

默认情况下spark_apply(),从输入Spark数据框中派生列名。使用names参数重命名或添加新列。

> trees_tbl %>%
+     spark_apply(
+         function(e) data.frame(2.54 * e$Girth, e),
+         names = c("Girth(cm)", colnames(trees)))
# Source: spark [?? x 4]
   `Girth(cm)` Girth Height Volume
 *            
 1        21.1  8.30   70.0   10.3
 2        21.8  8.60   65.0   10.3
 3        22.4  8.80   63.0   10.2
 4        26.7 10.5    72.0   16.4
 5        27.2 10.7    81.0   18.8
 6        27.4 10.8    83.0   19.7
 7        27.9 11.0    66.0   15.6
 8        27.9 11.0    75.0   18.2
 9        28.2 11.1    80.0   22.6
10        28.4 11.2    75.0   19.9
# ... with more rows

group by

在某些情况下,你可能希望将R函数应用于数据中的特定组。例如,假设您要针对特定​​子组计算回归模型。要解决此问题,您可以指定group_by参数。此示例计算iris按物种划分的行数,然后为每个物种拟合一个简单的线性模型。

iris_tbl <- sdf_copy_to(sc, iris)
> iris_tbl %>%
+     spark_apply(nrow, group_by = "Species")
# Source: spark [?? x 2]
  Species    result
*        
1 versicolor     50
2 virginica      50
3 setosa         50
> 
> 
> 
> iris_tbl %>%
+     spark_apply(
+         function(e) summary(lm(Petal_Length ~ Petal_Width, e))$r.squared,
+         names = "r.squared",
+         group_by = "Species")
# Source: spark [?? x 2]
  Species    r.squared
*           
1 versicolor     0.619
2 virginica      0.104
3 setosa         0.110

调用R包

有了spark_apply()你可以在spark中使用任何R包。例如,你可以使用broom包从线性回归输出创建整洁的数据框。

> spark_apply(
+     iris_tbl,
+     function(e) broom::tidy(lm(Petal_Length ~ Petal_Width, e)),
+     names = c("term", "estimate", "std.error", "statistic", "p.value"),
+     group_by = "Species")
# Source: spark [?? x 6]
  Species    term        estimate std.error statistic             p.value
*                                          
1 versicolor (Intercept)    1.78     0.284       6.28          9.48e⁻   ⁸
2 versicolor Petal_Width    1.87     0.212       8.83            1.27e⁻¹¹
3 virginica  (Intercept)    4.24     0.561       7.56          1.04e⁻   ⁹
4 virginica  Petal_Width    0.647    0.275       2.36           2.25e⁻  ²
5 setosa     (Intercept)    1.33     0.0600     22.1            7.68e⁻ ²⁷
6 setosa     Petal_Width    0.546    0.224       2.44           1.86e⁻  ²

要在Spark中使用R包,必须在工作节点上安装包。第一次调用spark_apply本地中的所有内容时,.libPaths()将通过该SparkConf.addFile()函数将其复制到每个Spark工作节点。软件包只会被复制一次,只要连接保持打开状态,软件包就会一直存在。R库的大小为几千兆字节并不罕见,因此在将R软件包复制到Spark集群时,请准备一次性税。您可以通过设置禁用包分发packages = FALSE。注意:程序包不会以本地模式(master="local")复制,因为程序包已存在于系统

异常处理

对群集中的R问题进行故障排除比在本地模式下更难。例如,以下R代码导致分布式执行失败,建议您检查日志以获取详细信息。

spark_apply(iris_tbl, function(e) stop("Make this fail"))

在本地模式下,sparklyr将为你检索日志。日志指出了ERROR sparklyr: RScript (4190) Make this fail您可能期望的真正故障。

你可能感兴趣的:(Spark 分布式计算)