Java 在ApacheSpark中,使用mapPartitions和结合使用广播变量和map有什么区别

Java 在ApacheSpark中,使用mapPartitions和结合使用广播变量和map有什么区别,java,scala,apache-spark,Java,Scala,Apache Spark,在Spark中,我们使用广播变量使每台机器都有一个变量的只读副本。我们通常在闭包外部创建广播变量(例如闭包所需的查找表)以提高性能 我们还有一个名为mapPartitions的spark转换操作符,它试图实现同样的目标(使用共享变量来提高性能)。例如,在mapPartitions中,我们可以为每个分区共享一个数据库连接 那么这两者之间有什么区别呢?我们是否可以仅在共享变量中互换使用它 广播用于将对象发送到每个工作节点。该对象将在该节点上的所有分区之间共享(集群中每个节点的值/即对象相同)。广播的

在Spark中,我们使用广播变量使每台机器都有一个变量的只读副本。我们通常在闭包外部创建广播变量(例如闭包所需的查找表)以提高性能

我们还有一个名为mapPartitions的spark转换操作符,它试图实现同样的目标(使用共享变量来提高性能)。例如,在mapPartitions中,我们可以为每个分区共享一个数据库连接


那么这两者之间有什么区别呢?我们是否可以仅在共享变量中互换使用它

广播
用于将对象发送到每个工作节点。该对象将在该节点上的所有分区之间共享(集群中每个节点的值/即对象相同)。广播的目标是在工作节点上的许多不同任务/分区中使用相同的数据时节省网络成本


相比之下,
mapPartitions
是一种在RDD上可用的方法,其工作原理类似于
map
,仅在分区上可用。是的,您可以定义新的对象,例如jdbc连接,它对每个分区都是唯一的。但是,您不能在不同的分区之间共享它,更不能在不同的节点之间共享它

虽然KrisP提供的答案强调了所有重要的差异,但我认为值得注意的是,
mapPartitions
只是更高级别转换背后的一个低级构建块,而不是实现共享状态的方法

尽管可以使用
mapPartitions
使共享状态显式化,但它在技术上是不共享的(它的生存期限于
mapPartitions
closure`),而且还有其他方法可以实现它。特别是,闭包内引用的变量在分区内共享。为了说明这一点,让我们玩一玩单人游戏:

对象DummySharedState{
变量i=0升
def get(x:Any)={
i+=1L
我
}
}
sc.parallelize(1到100,1).map(DummySharedState.get).max
//res3:Long=100
sc.parallelize(1到100,2).map(DummySharedState.get).max
//res4:Long=50
sc.parallelize(1到100,50).map(DummySharedState.get).max
//res5:Long=2
PySpark中也有类似的情况:

  • 单例模块
    虚拟共享\u状态.py

    i=0
    def get(x):
    全球i
    i+=1
    返回i
    
  • 主脚本:

    从pyspark导入SparkConf,SparkContext
    导入虚拟\u共享\u状态
    主人=”spark://..."
    conf=(SparkConf()
    .setMaster(master)
    .set(“spark.python.worker.reuse”、“false”))
    sc.addPyFile(“dummy\u shared\u state.py”)
    sc.parallelize(范围(100),1).map(dummy\u shared\u state.get).max()
    ## 100
    sc.parallelize(范围(100),2).map(dummy\u shared\u state.get).max()
    ## 50 
    
请注意,
spark.python.worker.reuse
选项设置为false。如果保留默认值,实际上会看到如下内容:

sc.parallelize(range(100), 2).map(dummy_shared_state.get).max()
## 50
sc.parallelize(range(100), 2).map(dummy_shared_state.get).max()
## 100
sc.parallelize(range(100), 2).map(dummy_shared_state.get).max()
## 150
一天结束时,你必须区分三件不同的事情:

  • 广播变量,其设计目的是通过将变量的副本保留在工作程序上而不是随每个任务一起发送来减少网络流量和内存占用
  • 在闭包外部定义并在闭包内部引用的变量,这些变量必须随每个任务一起提供并为此任务共享
  • 闭包内定义的未共享变量
除此之外,还有一些与持久性解释器的使用相关的特定于Python的问题


在变量生存期方面,
map
filter
或其他转换)和
mapPartitions
之间仍然没有实际的区别。

我明白了,所以主要的区别是级别正确吗?广播在节点级别,但mapPartitions在分区级别。从某种意义上说,是的。然而,用法(特别是语法)是如此的不同,以至于我不愿意在这两种情况之间进行比较。通常广播现有的数据数组,但在mapPartitions中,在该级别创建一个新对象。顺便说一句,广播是群集级别的,而不是节点级别的。这非常有用。我想知道map和mapPartitions之间的另一个区别。map以单行为基础运行,而mapPartitions可以通过迭代器访问发送到该分区的所有行。根据上面的例子,是否有可能访问全局变量以及发送到分区的所有行?我假设mapPartition不能使用全局范围变量,正如您在这里所示。@retrocookie
map
是使用
mapPartitions
实现的,所以这里没有区别。不过我会小心的。它更能说明保持持久解释器的意义,而不是其他任何东西。那么,通过mapPartition访问的全局文件是否在节点级别而不是分区级别共享?它比这稍微复杂一点。如果你问PySpark,答案是否定的。Worker是一个JVM进程,它使用套接字与Python执行器通信。所以没有全局Python,所以使用默认选项,每个执行器有一个Python解释器,可以用于多个分区,对吗?