火花蓄能器

时间:2019-02-12 14:51:40

标签: java scala apache-spark

我对Spark中的累加器是陌生的。我创建了一个累加器,它将一个数据帧中所有列的总和和计数信息收集到一个Map中。 哪个没有按预期运行,所以我有一些疑问。

当我在本地模式下运行此类(粘贴在下面)时,可以看到累加器正在更新,但最终值仍然为空。出于调试目的,我在add()中添加了一条print语句。

Q1)为什么在添加累加器时不更新最终累加器?

作为参考,我研究了CollectionsAccumulator,他们在其中使用了Java Collections中的SynchronizedList。

问题2)累加器是否需要是同步/并发集合才能更新?

Q3)哪个集合最适合此目的?

我将我的执行流程和spark ui快照附加在一起进行分析。

谢谢。

执行:

输入数据帧-

+-------+-------+
|Column1|Column2|
+-------+-------+
|1      |2      |
|3      |4      |
+-------+-------+

输出-

添加-映射(列1->映射(求和-> 1,1,计数-> 1),列2->映射(求和-> 2,2,计数-> 1))

添加-映射(列1->映射(求和-> 4,计数-> 2),列2->映射(求和-> 6,计数-> 2))

TestRowAccumulator(id:1,name:Some(求和计数的测试累加器),值:Map())

SPARK UI快照-

SPARK UI -

CLASS:

class TestRowAccumulator extends AccumulatorV2[Row,Map[String,Map[String,Int]]]{

  private var colMetrics: Map[String, Map[String, Int]] = Map[String , Map[String , Int]]()


  override def isZero: Boolean = this.colMetrics.isEmpty

  override def copy(): AccumulatorV2[Row, Map[String,Map[String,Int]]] = {
    val racc = new TestRowAccumulator
    racc.colMetrics = colMetrics
    racc
  }

  override def reset(): Unit = {
    colMetrics = Map[String,Map[String,Int]]()
  }

  override def add(v: Row): Unit = {

    v.schema.foreach(field => {
      val name: String = field.name
      val value: Int = v.getAs[Int](name)
      if(!colMetrics.contains(name))
        {
          colMetrics = colMetrics ++ Map(name -> Map("sum" -> value , "count" -> 1 ))
        }else
        {
          val metric = colMetrics(name)
          val sum = metric("sum") + value
          val count = metric("count") + 1

          colMetrics = colMetrics ++ Map(name -> Map("sum" -> sum , "count" -> count))
        }
    })
  }

  override def merge(other: AccumulatorV2[Row, Map[String,Map[String,Int]]]): Unit = {
    other match {
      case t:TestRowAccumulator => {
        colMetrics.map(col => {
          val map2: Map[String, Int] = t.colMetrics.getOrElse(col._1 , Map())
          val map1: Map[String, Int] = col._2
          map1 ++ map2.map{ case (k,v) => k -> (v + map1.getOrElse(k,0)) }
        } )
      }
      case _ => throw new UnsupportedOperationException(s"Cannot merge ${this.getClass.getName} with ${other.getClass.getName}")
    }
  }

  override def value: Map[String, Map[String, Int]] = {
    colMetrics
  }
}

1 个答案:

答案 0 :(得分:0)

经过一些调试,我发现正在调用merge函数。 它的代码错误,因此可累积的值为Map()

蓄能器执行流量(本地模式): 加 加 合并

一旦我纠正了合并功能,累加器就会按预期工作