我正在尝试使用Spark累加器来删除性能较差的查询组。
import org.apache.spark._
object CountPairsParam extends AccumulatorParam[Map[Int, Set[Int]]] {
def zero(initialValue: Map[Int, Set[Int]]): Map[Int, Set[Int]] = {
Map.empty[Int, Set[Int]]
}
def addInPlace(m1: Map[Int, Set[Int]], m2: Map[Int, Set[Int]]): Map[Int, Set[Int]] = {
val keys = m1.keys ++ m2.keys
keys.map((k: Int) => (k -> (m1.getOrElse(k, Set.empty[Int]) ++ m2.getOrElse(k, Set.empty[Int])))).toMap
}
}
val accum = sc.accumulator(Map.empty[Int, Set[Int]])(CountPairsParam)
srch_destination_id_distinct.foreach(r => try{accum += Map(r(0).toString.toInt -> Set(r(1).toString.toInt))} catch {case ioe: NumberFormatException => Map.empty[Int, Set[Int]]})
在我的累加器中,我假设m2不会总是在我的foreach循环中创建的单个项目集,并且有时Spark将使用此方法添加两个具有多个键的不同地图。但正因如此,我的表现很低。正确的Map是否总是通过一个项目进入累加器,从每个循环的my设置,或者我是否需要将此性能权交换掉?
答案 0 :(得分:3)
一般情况下,您应该避免使用Accumulators
进行调试,因为据我所知,RDD
的每个条目只会被添加到" #34;完全进入Accumulator
一次。
也许尝试这样的事情:
import scala.collection.mutable.HashSet
import scala.util.Try
val result = srch_destination_id_distinct.flatMap(r =>
Try((r(0).toString.toInt, r(1).toString.toInt)).toOption
).aggregateByKey(HashSet.empty[Int])(
(set, n) => set += n,
(set1, set2) => set1 union set2
).mapValues(_.toSet).collectAsMap
seqOp
方法的combOp
和aggregate
参数之间的区别也允许我们避免&#34;包装&#34; <{1}}中RDD
的每个元素与您的方法一样。