以下代码有效
@throws(classOf[IKodaMLException])
def soMergeTarget1( oldTargetIdx: Double, newTargetIdx: Double): RDDLabeledPoint =
{
try
{
logger.trace("\n\n--sparseOperationRenameTargetsInNumeriOrder--\n\n")
val oldTargetIdxb=spark.sparkContext.broadcast(oldTargetIdx)
val newTargetIdxb=spark.sparkContext.broadcast(newTargetIdx)
val newdata:RDD[(LabeledPoint,Int,String)] = sparseData.map
{
r =>
val currentLabel: Double = r._1.label
currentLabel match
{
case x if x == oldTargetIdxb.value =>
val newtrgt=newTargetIdxb.value
(new LabeledPoint(newtrgt, r._1.features), r._2, r._3)
case _ => r
}
}
val newtargetmap=ilp.targetMap.filter(e=> !(e._2 == oldTargetIdx))
oldTargetIdxb.destroy
newTargetIdxb.destroy
new RDDLabeledPoint(newdata,copyColumnMap,newtargetmap,ilp.name)
}
但是,在方法末尾销毁了广播变量之后,RDD中的newtrgt
变量也被销毁了。
问题在于,一旦从此方法返回RDD,任何分析人员都可以在任何代码中使用它。因此,我似乎已经失去了对广播变量的所有控制。
问题:
如果我不销毁这些变量,当对RDD的引用消失时会火花销毁它们吗?
(也许是一个幼稚的问题,但是...。)我尝试了一点技巧val newtrgt=oldTargetIdxb.value + 1 -1
,认为这可能会创建一个不同于广播变量的新引用。没用我必须承认这让我感到惊讶。有人可以解释为什么这种黑客攻击无效吗(我并不是说这是个好主意,但我很好奇)。
答案 0 :(得分:1)
我找到了答案here
不是我的答案 ,但是值得在SO上共享...以及为什么我在Spark文档中看不到这一点。重要:
塞恩·欧文:
您要主动取消播放(或持续播放) 不再需要的变量。他们最终可能是 当驱动程序上的引用被垃圾回收时删除,但是 您通常不想依赖它。
后续问题:
感谢您的回复。唯一的问题是积极管理 广播变量要求将广播变量返回到 调用方,如果创建广播变量的函数没有 包含任何动作。那就是使用广播的范围 变量在许多情况下不能破坏广播变量。对于 例如:
==============
def perfromTransformation(rdd: RDD[int]) = {
val sharedMap = sc.broadcast(map)
rdd.map{id =>
val localMap = sharedMap.vlaue
(id, localMap(id))
}
}
def main = {
....
performTransformation(rdd).toDF("id", "i").write.parquet("dummy_example")
}
==============
在上面的示例中,我们无法在 之所以执行write.parquet是因为RDD的计算是延迟的。我们将获得 例外
塞恩·欧文:
是的,尽管持久和毁灭之间存在差异, 无论哪种方式,您都会遇到相同类型的问题。您确实必须 关于何时不再需要广播变量的原因 面对懒惰的评估,这很难。
有时候这很明显,您可以利用它来 主动释放资源。您可能需要考虑重组 计算以释放更多资源(如果是) 规模很重要。
请记住,计算和缓存的内容可能会丢失并且 即使已经确定其父RDD,也要重新计算 计算,似乎不需要。这就是为什么不持久经常出现 更好的调用是因为它允许变量为 在这种情况下,请重新播放。销毁后永久关闭 广播。