DataSet相对于RDD的性能优势

时间:2016-12-26 16:15:06

标签: apache-spark rdd apache-spark-dataset

在阅读了几篇关于Spark的DataSet的精彩文章(thisthisthis)后,我完成了下一个DataSet相对于RDD的性能优势:

  1. 逻辑和物理计划优化;
  2. 严格的典型化;
  3. 矢量化操作;
  4. 低级别内存管理。
  5. 问题:

    1. Spark的RDD还可以构建物理计划,并可以在同一阶段组合/优化多个转换。那么 DataSet相对于RDD有什么好处?
    2. the first link,您可以看到RDD[Person]的示例。 DataSet是否具有高级典型化?
    3. “矢量化操作”是什么意思?
    4. 据我所知,DataSet的低内存管理=高级序列化。这意味着可序列化对象的堆外存储,您可以在其中只读取对象的一个​​字段而不进行反序列化。 但是,当你有IN_MEMORY_ONLY持久性策略时,情况怎么样?无论如何,DataSet会将所有内容序列化吗?它会比RDD有任何性能优势吗?

1 个答案:

答案 0 :(得分:5)

  

Spark的RDD还可以构建物理计划,并可以在同一阶段组合/优化多个转换。比DataSet相对于RDD有什么好处?

使用RDD时,你所写的是你得到的。虽然通过链接优化了某些转换,但执行计划是DAG的直接转换。例如:

rdd.mapPartitions(f).mapPartitions(g).mapPartitions(h).shuffle()

其中shuffle是任意改组转换(*byKeyrepartition等)所有三个mapPartitionsmapflatMap, <{1}})将被链接而不创建中间对象,但不能重新排列。

filter相比,使用明显更具限制性的编程模型,但可以使用多种技术优化执行,包括:

  • 选择(Datasets)下推。例如,如果你有:

    filter

    可以执行:

    df.withColumn("foo", col("bar") + 1).where(col("bar").isNotNull())
    
  • 早期预测(df.where(col("bar").isNotNull()).withColumn("foo", col("bar") + 1) )和淘汰。例如:

    select

    可以改写为:

    df.withColumn("foo", col("bar") + 1).select("foo", "bar")
    

    以避免获取和传递过时的数据。在极端情况下,它可以完全消除特定的转换:

    df.select("foo", "bar").withColumn("foo", col("bar") + 1)
    

    可以优化到

    df.withColumn("foo", col("bar") + 1).select("bar")
    

这些优化可能有两个原因:

  • 限制性数据模型,可以进行依赖性分析,无需复杂和不可靠的静态代码分析。
  • 清除运算符语义。操作员无副作用,我们清楚地区分确定性和非确定性。

为了说清楚,我们假设我们有以下数据模型:

df.select("bar")

我们希望检索21岁以上所有人的姓氏。case class Person(name: String, surname: String, age: Int) val people: RDD[Person] = ??? 可以表示为:

RDD

现在让我们问几个问题:

  • people .map(p => (p.surname, p.age)) // f .filter { case (_, age) => age > 21 } // g 中的输入agef的{​​{1}}变量之间的关系是什么?
  • age然后gf相同,然后是g吗?
  • gf副作用是否免费?

虽然答案对于人类读者来说是显而易见的,但它不适用于假设的优化器。与f版本相比:

g

优化者和人类读者都明白答案。

使用静态类型DataframeSpark 2.0 Dataset vs DataFrame)时会产生一些进一步的后果。

  

让DataSet获得更高级的典型化吗?

  • 不 - 如果您关心优化。最高级的优化仅限于people.toDF .select(col("surname"), col("age")) // f' .where(col("age") > 21) // g' ,目前无法对复杂类型层次结构进行编码。
  • 也许 - 如果你接受Kryo或Java编码器的开销。
  

“矢量化操作”是什么意思?

在优化的上下文中,我们通常意味着循环矢量化/循环展开。 Spark SQL使用代码生成来创建高级转换的编译器友好版本,可以进一步优化以利用向量化指令集。

  

据我所知,DataSet的低内存管理=高级序列化。

不完全是。使用本机分配的最大优点是转义垃圾收集器循环。由于垃圾收集通常是Spark中的一个限制因素,因此这是一个巨大的改进,特别是在需要大型数据结构(如准备shuffle)的环境中。

另一个重要方面是柱状存储,它可以实现有效压缩(可能更低的内存占用)和对压缩数据的优化操作。

通常,您可以在普通Datasets上使用手工制作的代码应用完全相同类型的优化。所有Dataset[Row]都由RDDs支持。不同之处仅在于需要多少努力。

  • 手工制作的执行计划优化实现起来相对简单。
  • 使代码编译器友好,需要更深入的知识,并且容易出错并且冗长。
  • 使用Datasets本机内存分配不适合胆小的人。

尽管它的所有优点RDDs API并不普及。虽然某些类型的常见任务可以在许多情况下从其优化中受益,但与RDD等效项相比,您可能无论如何都没有任何改进甚至性能下降。