記一次使用spark累加器來實現流程數據量監控功能

業務場景

    採集工具採集的文件中以日期爲標識,但是該文件中卻可能包含了多天的數據,所以在統計當天推送文件記錄總數時,需要記錄當天的文件錄入了詳單表的哪些分區。後續業務開發利用這種映射關係,就可以縮小詳單表分區範圍,儘快的統計出當天入庫記錄數。(這僅僅是該業務統計的一個指標,利用此處的累加器,還可以高效率的統計過濾,髒數據條數)

解決方案

方案一、再觸發一次action

    採即對落地的dataframe提取出分區時間列和文件全路徑列,再進行去重,最終調用一次collect,即可獲取上述的映射關係。

方案二、利用spark累加器

    採此處定義的累加器數據結構爲【String,String】其中:key爲文件全路徑,value爲該文件的記錄數。自定義累加器,主要是重寫add、merge方法,累加器的add方法是針對於一個task,merge方法針對的是各個task運算結果的累加。
累加器代碼樣例如下:

class FilterAccumulator extends AccumulatorV2[String,mutable.Map[String,Long]]{
  private val _result =  mutable.Map[String,Long]();

  override def isZero: Boolean = true

  override def copy(): AccumulatorV2[String, mutable.Map[String, Long]] = {
    val copy = new FilterAccumulator
    copy.merge(this)
    copy
  }

  override def reset(): Unit = _result.clear()

  override def add(v: String): Unit = {
    _result.synchronized {
      var dd = _result.get(v) match {
        case Some(x) => x
        case _       =>
          val tmp = 0L
          tmp
      }
      dd += 1
      _result.put(v,dd)
    }
  }

  override def merge(other: AccumulatorV2[String, mutable.Map[String, Long]]): Unit = other match{
    case o: FilterAccumulator =>
      _result.synchronized(
        o._result.foreach(x => {
          var temp :Long = _result.get(x._1) match {
            case Some(y) => y
            case _       =>
              val tmp = 0L
              tmp
          }
          temp += x._2
          _result.put(x._1, temp)
        }))
    case _                  =>
      throw new UnsupportedOperationException(
        s"Cannot merge ${this.getClass.getName} with ${other.getClass.getName}")
  }

  override def value: mutable.Map[String, Long] = _result
}

說明:
1、 此處定義key爲文件全路徑,是考慮到task重算時,避免記錄數重複,但是這邊有一個問題——一個文件不止拆成一個任務執行時,累加器中的記錄數會不對。(考慮到現場這種文件很少,如果有這種文件,也可以手動的將他們split成小文件)

累加器總結

1、 累加器放在foreach動作中使用時,計算結果不會有誤;但是放在map等轉換函數中使用時,需要考慮任務重算導致計算結果有誤;
2、 累加器工作時,可以看做每個task都有一個“副本”,在任務執行結束後,就執行merge操作,最終在driver端調用accumulator.value方法時,獲取累加器執行結果。
3、從DAG圖上來看,如果累加器部分代碼的dataset/rdd被多個action觸發,那麼累加器統計結果也會重複,這種情況下,如果不想統計重複,就需要添加cache/persist函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章