DataSet 相对于 RDD 的性能优势

Performance benefits of DataSet over RDD

在阅读了几篇关于 Spark 的 DataSet 的精彩文章 (this, and this) 之后,我总结了下一个 DataSet 相对于 RDD 的性能优势:

  1. 逻辑和物理计划优化;
  2. 严格类型化;
  3. 矢量化操作;
  4. 低级内存管理。

问题:

  1. Spark 的 RDD 也构建物理计划,并且可以 combine/optimize 在同一阶段进行多次转换。那么DataSet相对于RDD的优势是什么?
  2. the first link可以看到RDD[Person]的例子。 DataSet 有高级类型化吗?
  3. "vectorized operations"是什么意思?
  4. 据我了解,DataSet 的低内存管理 = 高级序列化。这意味着可序列化对象的堆外存储,您可以在其中仅读取对象的一个​​字段而无需反序列化。 但是当你有 IN_MEMORY_ONLY 持久性策略时情况如何? DataSet 会在任何情况下序列化所有内容吗?它会比 RDD 有任何性能优势吗?

Spark's RDD also builds physical plan and can combine/optimize multiple transformations at the same stage. Than what is the benefit of DataSet over RDD?

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

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

其中 shuffle 是任意洗牌转换(*byKeyrepartition 等)所有三个 mapPartitionsmapflatMap, 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")
    

这些优化之所以可行,有两个原因:

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

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

case class Person(name: String, surname: String, age: Int)

val people: RDD[Person] = ???

而我们要检索所有21岁以上的人的姓氏。用RDD可以表示为:

people
  .map(p => (p.surname, p.age))          // f
  .filter { case (_, age) => age > 21 }  // g

现在让我们问自己几个问题:

  • f中的输入ageg中的age变量有什么关系?
  • f然后gg然后f是一样的吗?
  • fg 没有副作用吗?

虽然答案对于人类来说是显而易见的 reader 但对于假设的优化器而言却并非如此。与 Dataframe 版本相比:

people.toDF
  .select(col("surname"), col("age"))    // f'
  .where(col("age") > 21)                // g'

优化器和人类的答案都很明确 reader。

这在使用静态类型 Datasets () 时会产生一些进一步的后果。

Have DataSet got more advanced typization?

  • 否 - 如果您关心优化。最高级的优化仅限于 Dataset[Row],目前无法对复杂类型层次结构进行编码。
  • 也许 - 如果您接受 Kryo 或 Java 编码器的开销。

What does they mean by "vectorized operations"?

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

As I understand, DataSet's low memory management = advanced serialization.

不完全是。使用本机分配的最大优势是逃避垃圾收集器循环。由于垃圾收集通常是 Spark 中的一个限制因素,这是一个巨大的改进,特别是在需要大型数据结构的上下文中(比如准备洗牌)。

另一个重要方面是列式存储,它支持有效压缩(可能减少内存占用)和优化压缩数据操作。

一般来说 您可以在纯 RDDs 上使用手工编写的代码应用完全相同类型的优化。毕竟 Datasets 得到了 RDDs 的支持。不同的只是需要付出多少努力。

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

尽管有很多优点 Dataset API 并不通用。虽然某些类型的常见任务可以在许多情况下受益于它的优化,但与等效的 RDD 相比,您可能没有任何改进甚至性能下降。