我的Spark流程中有一个奇怪的行为,其行为如下:
map M
并广播地图M
值问题在于,在广播结束之前完成对M
的转换调用,然后它不能按预期工作,因为M
此时为空。
我的问题是:如何让Spark在使用之前等待加载和广播对象?
注意:我已经检查了通话时间,而且这些通话确实没有同步。然后,M确实正确加载。
参考文件加载:
object RefObjectUtil extends java.io.Serializable {
var map = Map[String, RefObject]()
def loadAndBroadcast(inputPath: String, sc: SparkContext) = {
val data = read(inputPath, sc).collect
val i = data.iterator
while (i.hasNext) {
val a = i.next
map.put(a.getValue.toString, a)
}
sc.broadcast(map)
}
@throws(classOf[RefObject])
def get(key: String): RefObject= {
isLoaded()
map.getOrElse(key, null)
}
private def isLoaded(): Unit = {
if(map.isEmpty) {
throw new RefObjectException("file has not been loaded. Add it into path argument of your job")
}
}
然后是电话:
def run() {
RefObjectUtil.loadAndBroadcast(inputPath, sc)
val data = read(inputToTransformPath, sc)
transform(data) //called without waiting end of refObject loading
}
谢谢。
答案 0 :(得分:0)
问题代码不起作用的原因与进程同步无关。代码可能在驱动程序中正确执行,但RefObjectUtil
是一个单例对象,并且在引用时将在每个执行程序中再次初始化。此时,var map = Map[String, RefObject]()
被初始化并且不包含任何数据。
在一个程序中看起来有两种Spark数据共享技术不合并。 要么我们使用'singleton object'模式来保存每个执行器上的数据,要么我们在驱动程序中组装数据并使用broadcast将其发送给执行程序。
'singleton object'模式更适合处理像DB连接这样的有状态资源,这似乎不是这里的情况。广播变量将是更好的选择。
让我们试着用一个例子说明用法:
受问题代码的启发,此代码加载一些数据,从中创建地图并广播它。然后使用该地图来解析/翻译更大的数据集。注意如何使用broadcastVar.value
在闭包内访问广播变量的内容。
// get data into map form
val dataMap = val data = read(inputPath, sc).map{elem => (a.getValue.toString, a)}.collectAsMap
// broadcast the data
val broadcastMap = sc.broadcast(dataMap)
val dataToProcessRDD = ???
dataToProcessRDD.flatMap{item =>
broadcastMap.value.get(item) //broadcastMap.value => returns the wrapped map instance
}