jvm Apache Spark中的Dataframe、Dataset和RDD之间有什么区别?

ig9co6j1  于 2022-11-07  发布在  Apache
关注(0)|答案(2)|浏览(124)

在Apache Spark中,这些API之间有什么区别?为什么以及何时我们应该选择其中一个?

xytpbqjk

xytpbqjk1#

首先,让我们定义Spark的作用

  • 简单地说,它所做的就是对分布式数据执行操作。因此,这些操作也需要是分布式的。有些操作很简单,比如过滤掉所有不遵守某个规则的项。有些操作则比较复杂,比如groupBy需要移动数据,join需要关联两个或更多数据集中的项。
  • 另一个重要的事实是,输入和输出以不同的格式存储,spark有连接器来读取和写入它们。但这意味着要对它们进行序列化和反序列化。虽然是透明的,但序列化通常是最昂贵的操作。
  • 最后,spark会尝试将数据保存在内存中进行处理,但当内存中容纳不下数据时,它会在本地对每个工作线程上的数据进行[ser/deser]化。同样,这是透明的,但代价可能会很高。Interesting fact: estimating the data size can take time
    API
  • RDD

它是spark提供的第一个API,简单地说,它是分布在集群上的scala/java对象的无序序列,在其上执行的所有操作都是JVM方法(传递给map,flatmap,groupBy,...),这些需要被序列化,发送给所有的worker,并应用到那里的jvm对象。这与使用scala Seq非常相似,但是是分布式的。它是强类型的,意思是“如果它编译了,那么它就能工作”(如果你不作弊的话)。然而,有很多分发问题可能会出现。特别是如果spark不知道如何[反]序列化jvm类和方法的话。

  • Dataframe

它是在RDD之后出现的,在语义上与RDD有很大的不同,数据被认为是表,可以对其进行操作,比如sql操作,它完全没有类型化,所以在执行过程中随时可能出错,但是我认为有两个优点:(1)许多人习惯于table/sql的语义和操作,(2)如果数据格式提供了合适的列访问,spark不需要反序列化整行来处理它的一个列,而许多人都这样做,比如最常用的parquet文件格式。

  • 数据集

这是Dataframe的一个改进,它带来了一些类型安全。数据集是一个 Dataframe ,我们将它与一个与JVM类相关的“编码器”相关联。因此,spark可以在执行代码之前检查数据模式是否正确。然而,请注意,我们有时可以读到数据集是强类型的,但它不是:它带来了一些很强的类型安全性,在这种情况下,你不能编译使用数据集的代码,而数据集的类型不是已经声明的类型。但是,很容易让代码编译后在运行时仍然失败。这是因为许多数据集操作会丢失类型(除了filter之外的几乎所有操作)。尽管如此,这仍然是一个巨大的改进,因为即使我们犯了错误,它也会很快失败:当解释SparkDAG时(即在开始时)而不是在数据处理期间发生故障。
注意: Dataframe 现在只是无类型的数据集(Dataset<Row>
注2:数据集提供RDD的主要API,如map和flatMap。据我所知,转换为rdd,然后应用map/flatMap,再转换为数据集是一条捷径。这是实用的,但也隐藏了转换,使人们难以意识到可能发生的代价高昂的ser/deserialization。

正反两方面

  • 数据集:

  • 优点:与面向列的存储相比,优化了操作

  • 优点:许多操作也不需要反序列化

  • 优点:如果您喜欢话,可以提供表/SQL语义(我不喜欢;)

  • 优点:数据集操作附带了一个优化引擎“催化剂”,可以提高代码的性能。但是我不确定它是否真的那么好。如果你知道你写了什么,也就是说,对数据做了什么,你的代码应该自己优化。

  • 缺点:大多数操作类型松散

  • 缺点:数据集操作对于不适合它的复杂算法来说可能变得太复杂了。我知道的两个主要限制是管理无效数据和复杂的数学算法。

  • Dataframe :

  • 优点:在丢失类型的数据集操作之间是必需的

  • 缺点:只需使用Dataset,它具有所有优点,甚至更多

  • RDD:

  • 优点:(真的)强类型

  • 优点:scala/java语义。您可以像设计处理内存中集合的单JVM应用程序一样设计代码。好吧,使用函数语义:)

  • 缺点:在前面提到的任何步骤中,都需要完整的JVM反序列化来处理数据:在阅读输入之后,以及在需要在工作者之间移动数据或本地存储数据以管理内存限制的所有处理步骤之间。
    结论

  • 默认情况下仅使用数据集:

  • 使用Encoder读取输入,如果数据格式允许,它将在开始时验证输入模式

  • 使用数据集操作,当你丢失类型时,回到类型化数据集。2通常,使用类型化数据集作为所有方法的输入和输出。

  • 有些情况下,你想编写的代码太复杂,无法用数据集运算来表达。大多数应用程序都不会这样,但在我实现复杂数学模型的工作中,这种情况经常发生。在这种情况下:

  • 从数据集开始

  • 使用数据集操作尽可能多地过滤和混洗(groupBy、join)数据

  • 一旦你只有所需的数据,并且不需要移动它们,转换为rdd并应用你的复杂计算。

fzsnzjdm

fzsnzjdm2#

简而言之:

*RDD来自Spark的早期版本。仍然被Dataframes“在引擎盖下”使用。
*Dataframe在Spark 1.x后期引入,在Spark 2.x中真正成熟。它们现在是首选的存储。它们在Java中实现为数据集。
*数据集是通用实现,例如,您可以有一个数据集。

我使用 Dataframe ,并强烈推荐它们:Spark的优化器Catalyst能够更好地理解数据集(也就是 Dataframe ),而Row是一个比纯JVM对象更好的存储容器。

相关问题