Scala 当使用复杂的中间类型时,聚合器速度较慢

Scala 当使用复杂的中间类型时,聚合器速度较慢,scala,apache-spark,apache-spark-dataset,Scala,Apache Spark,Apache Spark Dataset,我有一个自定义的聚合器,它可以进行计数最小草图聚合。它可以工作,但速度很慢(代码如下)。如果使用基于UserDefinedAggregateFunction类的自定义UDAF,我会获得类似的低性能 如果我使用数据集映射分区API在分区内进行聚合,然后跨分区进行缩减,则速度会快得多 问题-UDAF和聚合器API的缓慢似乎是由每行发生的序列化/反序列化(编码)引起的。UDAF和聚合器API是否不用于聚合为非平凡的数据结构(如count min sketch)?mapPartitions方法是处理此问

我有一个自定义的
聚合器
,它可以进行计数最小草图聚合。它可以工作,但速度很慢(代码如下)。如果使用基于
UserDefinedAggregateFunction
类的自定义UDAF,我会获得类似的低性能

如果我使用
数据集
映射分区
API在分区内进行聚合,然后跨分区进行缩减,则速度会快得多

问题-UDAF和
聚合器
API的缓慢似乎是由每行发生的序列化/反序列化(编码)引起的。UDAF和聚合器API是否不用于聚合为非平凡的数据结构(如count min sketch)?mapPartitions方法是处理此问题的最佳方法吗

聚合器
示例代码:

import org.apache.spark.SparkConf
import org.apache.spark.sql.{Encoder, Row, SparkSession}
import org.apache.spark.sql.expressions.Aggregator
import org.apache.spark.util.sketch.CountMinSketch

object AggTest extends App {

  val input = "2008.csv"

  val conf = new SparkConf().setMaster("local[4]").setAppName("tester")
  val sqlContext = SparkSession.builder().config(conf).getOrCreate().sqlContext

  val df = sqlContext.read.format("csv").option("header", "true").load(input)

  implicit val sketchEncoder = org.apache.spark.sql.Encoders.kryo[CountMinSketch]

  case class SketchAgg(col: String) extends Aggregator[Row, CountMinSketch, CountMinSketch] {
    def zero: CountMinSketch = CountMinSketch.create(500, 4, 2429)

    def reduce(sketch: CountMinSketch, row: Row) = {
      val a = row.getAs[Any](col)
      sketch.add(a)
      sketch
    }

    def merge(sketch1: CountMinSketch, sketch2: CountMinSketch) = {
      sketch1.mergeInPlace(sketch2)
    }

    def finish(sketch: CountMinSketch) = sketch

    def bufferEncoder: Encoder[CountMinSketch] = sketchEncoder

    def outputEncoder: Encoder[CountMinSketch] = sketchEncoder
  }

  val sketch = df.agg(SketchAgg("ArrDelay")
              .toColumn
              .alias("sketch"))
              .select("sketch")
              .as[CountMinSketch]
              .first()

}

虽然没有太大的帮助,但是spark 2.2.0中的一些搜索导致了这一点,它应该通过不对每一行的缓冲区对象进行反序列化来改进这一点。