Spark中DataFrame,Dataset和RDD之间的区别


Answers:


232

一个DataFrame很好的定义与谷歌搜索“ DataFrame定义”:

数据框是表或二维数组状结构,其中每一列包含一个变量的度量,每一行包含一个个案。

因此,DataFrame由于其表格格式,因此具有附加的元数据,这使Spark可以在最终查询中运行某些优化。

RDD,另一方面,仅仅是- [R esilient d istributed d ataset是更不能作为可以针对它要执行的操作进行优化的数据的黑盒的,不作为限制。

但是,你可以从一个数据帧到一个RDD通过它的rdd方法,你可以从一个去RDDDataFrame(如果RDD是表格形式),通过该toDF方法

通常DataFrame由于内置的​​查询优化功能,建议尽可能使用。


6
答案没有提供有关数据集的解释。根据Spark-《权威指南》,数据集是类型安全的结构化api。因此,您可以预先提供模式的类型。
Chintan Pandya

3
谢谢-在原始问题(不包括数据集)之后,对原始标题和描述进行了很好的编辑
贾斯汀·皮洪尼

219

第一件事是DataFrame从演变而来的SchemaRDD

SchemaRDD弃用的方法

是的。Dataframe和之间的转换RDD是绝对可能的。

以下是一些示例代码片段。

  • df.rddRDD[Row]

以下是一些用于创建数据框的选项。

  • 1)yourrddOffrow.toDF转换为DataFrame

  • 2)使用createDataFrameSQL上下文

    val df = spark.createDataFrame(rddOfRow, schema)

模式可以来自不错的SO post所描述的以下某些选项。.
来自scala case类和scala反射api

import org.apache.spark.sql.catalyst.ScalaReflection
val schema = ScalaReflection.schemaFor[YourScalacaseClass].dataType.asInstanceOf[StructType]

或使用 Encoders

import org.apache.spark.sql.Encoders
val mySchema = Encoders.product[MyCaseClass].schema

如Schema所述,也可以使用StructType和 创建StructField

val schema = new StructType()
  .add(StructField("id", StringType, true))
  .add(StructField("col1", DoubleType, true))
  .add(StructField("col2", DoubleType, true)) etc...

图片说明

实际上,现在有3个Apache Spark API。

在此处输入图片说明

  1. RDD API:

RDD,因为1.0版本(弹性分布式数据集)API已在火花。

所述RDDAPI提供了许多转化方法,例如map(), filter(),和reduce(),用于对数据执行计算。这些方法中的每一个都会产生一个新的RDD代表转换后的数据。但是,这些方法只是定义要执行的操作,并且只有在调用action方法之后才执行转换。动作方法的示例是collect()和 saveAsObjectFile()。

RDD示例:

rdd.filter(_.age > 21) // transformation
   .map(_.last)// transformation
.saveAsObjectFile("under21.bin") // action

示例:使用RDD按属性过滤

rdd.filter(_.age > 21)
  1. DataFrame API

DataFrame作为Tungsten计划的一部分,Spark 1.3引入了新的API,该API旨在改善Spark的性能和可伸缩性。该DataFrameAPI引入了模式的概念来描述数据,使星火管理模式和唯一的节点之间传递数据,比使用Java序列化一个更有效的方式。

DataFrameAPI与该RDDAPI 完全不同,因为它是用于构建关系查询计划的API,Spark的Catalyst优化器随后可以执行该查询计划。对于熟悉构建查询计划的开发人员来说,API是很自然的

示例SQL风格:

df.filter("age > 21");

限制: 由于代码按名称引用数据属性,因此编译器不可能捕获任何错误。如果属性名称不正确,则仅在创建查询计划时才在运行时检测到错误。

DataFrameAPI的另一个缺点是,它以Scala为中心,虽然它确实支持Java,但支持有限。

例如,当DataFrame从现有RDD的Java对象创建时,Spark的Catalyst优化器无法推断模式,并假定DataFrame中的任何对象都实现了该scala.Product接口。Scala case class解决了问题,因为他们实现了此接口。

  1. Dataset API

DatasetAPI在Spark 1.6中作为API预览发布,旨在提供两全其美的方法。RDDAPI 熟悉的面向对象的编程风格和编译时类型安全性,但具有Catalyst查询优化器的性能优势。数据集还使用与DataFrameAPI 相同的高效堆外存储机制 。

在序列化数据时,DatasetAPI具有编码器的概念, 可以在JVM表示(对象)和Spark的内部二进制格式之间进行转换。Spark具有内置的编码器,这些编码器非常先进,它们生成字节码以与堆外数据进行交互,并提供按需访问单个属性的功能,而不必对整个对象进行反序列化。Spark尚未提供用于实现自定义编码器的API,但已计划在将来的版本中使用。

此外,该DatasetAPI旨在与Java和Scala均能很好地协同工作。使用Java对象时,重要的是它们必须与Bean完全兼容。

DatasetAPI SQL样式示例:

dataset.filter(_.age < 21);

评价差异。在DataFrame&之间DataSet 在此处输入图片说明

加泰罗尼亚级的流量。。(Spark Summit揭秘DataFrame和Dataset演示) 在此处输入图片说明

进一步阅读... databricks 文章-三种Apache Spark API的故事:RDD与DataFrames和Datasets


什么是强类型结构数据集?它与DataFrame有何不同?
阿文德·库玛

数据集涵盖哪些类型的分析错误?
Neeleshkumar S

5
@ neelesh-srinivasan:以数据帧语法为例df.filter("age > 21");,只能在运行时对其进行评估/分析。自其字符串。如果是数据集,则数据集符合Bean的要求。所以年龄是豆子的财产。如果bean中不存在age属性,那么您将在ie编译时就早知道了dataset.filter(_.age < 21);。分析错误可以重命名为评估错误。
拉姆·加迪亚拉姆

@NeeleshSrinivasan:有关更多信息和详细信息,请参阅apache-spark-api-comparision
Ram Ghadiyaram

第一张图片具有误导性。数据集在Python中不可用
Yeikel

135

Apache Spark提供三种类型的API

  1. RDD
  2. 数据框
  3. 数据集

比较RDD,Dataframe和Dataset API

这是RDD,Dataframe和Dataset之间的API比较。

RDD

Spark提供的主要抽象是弹性分布式数据集(RDD),它是跨集群节点划分的元素的集合,可以并行操作。

RDD功能:-

  • 分布式集合:
    RDD使用MapReduce操作,该操作被广泛用于在集群上使用并行分布式算法处理和生成大型数据集。它允许用户使用一组高级运算符来编写并行计算,而不必担心工作分配和容错性。

  • 不变的: RDD由分区的记录集合组成。分区是RDD中并行性的基本单位,每个分区是数据的一个逻辑分区,它是不可变的,并且是通过对现有分区进行一些转换而创建的。不可变性有助于实现计算的一致性。

  • 容错: 如果我们丢失了RDD的某些分区,则可以按世系在该分区上重播转换以实现相同的计算,而不是跨多个节点进行数据复制。此特性是RDD的最大优点,因为它可以节省数据管理和复制方面的大量努力,从而实现了更快的计算。

  • 惰性评估: Spark中的所有转换都是惰性的,因为它们不会立即计算出结果。相反,他们只记得应用于某些基本数据集的转换。仅当操作要求将结果返回给驱动程序时才计算转换。

  • 功能转换: RDD支持两种类型的操作:转换(从现有操作创建新数据集)和动作(在数据集上运行计算后将值返回到驱动程序)。

  • 数据处理格式:
    它可以轻松有效地处理结构化数据和非结构化数据。

  • 支持的编程语言:
    RDD API 支持 Java,Scala,Python和R。

RDD限制:-

  • 没有内置的优化引擎: 使用结构化数据时,RDD无法利用Spark的高级优化器(包括催化剂优化器和Tungsten执行引擎)的优势。开发人员需要根据其属性优化每个RDD。

  • 处理结构化数据:数据框和数据集不同,RDD不会推断已摄取数据的模式,而是需要用户指定它。

数据框

Spark在Spark 1.3版本中引入了数据帧。数据框克服了RDD所面临的主要挑战。

DataFrame是组织为命名列的分布式数据集合。从概念上讲,它等效于关系数据库或R / Python数据框中的表。与Dataframe一起,Spark还引入了催化剂优化器,它利用高级编程功能来构建可扩展的查询优化器。

数据框功能:-

  • 行对象的分布式集合: DataFrame是组织为命名列的数据的分布式集合。它在概念上等效于关系数据库中的表,但是在后台进行了更丰富的优化。

  • 数据处理: 处理结构化和非结构化数据格式(Avro,CSV,弹性搜索和Cassandra)和存储系统(HDFS,HIVE表,MySQL等)。它可以从所有这些各种数据源读取和写入。

  • 使用催化剂优化器进行优化: 它支持SQL查询和DataFrame API。数据框分四个阶段使用催化剂树转换框架,

     1.Analyzing a logical plan to resolve references
     2.Logical plan optimization
     3.Physical planning
     4.Code generation to compile parts of the query to Java bytecode.
    
  • Hive兼容性: 使用Spark SQL,您可以在现有Hive仓库上运行未修改的Hive查询。它重用了Hive前端和MetaStore,并为您提供了与现有Hive数据,查询和UDF的完全兼容性。

  • Tungsten: Tungsten提供了一个物理执行后端,该后端可以显式管理内存并动态生成字节码以进行表达式求值。

  • 支持的编程语言:
    Dataframe API 支持 Java,Scala,Python和R。

数据框限制:-

  • 编译时类型安全性: 如前所述,Dataframe API不支持编译时安全性,这会限制您在结构未知时操作数据。以下示例在编译时起作用。但是,执行此代码时,您将获得运行时异常。

例:

case class Person(name : String , age : Int) 
val dataframe = sqlContext.read.json("people.json") 
dataframe.filter("salary > 10000").show 
=> throws Exception : cannot resolve 'salary' given input age , name

当您使用多个转换和聚合步骤时,这尤其具有挑战性。

  • 无法对域对象(丢失的域对象)进行操作: 将域对象转换为数据框后,将无法从中重新生成它。在下面的示例中,一旦从personRDD创建personDF,就不会恢复Person类(RDD [Person])的原始RDD。

例:

case class Person(name : String , age : Int)
val personRDD = sc.makeRDD(Seq(Person("A",10),Person("B",20)))
val personDF = sqlContext.createDataframe(personRDD)
personDF.rdd // returns RDD[Row] , does not returns RDD[Person]

数据集API

数据集API是DataFrames的扩展,它提供了类型安全的,面向对象的编程接口。它是映射到关系模式的对象的强类型,不可变的集合。

API是数据集的核心,是一个称为编码器的新概念,它负责在JVM对象和表格表示形式之间进行转换。该表格表示形式使用Spark内部钨二进制格式存储,从而允许对序列化数据进行操作并提高内存利用率。Spark 1.6支持自动生成多种类型的编码器,包括原始类型(例如String,Integer,Long),Scala案例类和Java Bean。

数据集功能:-

  • 同时提供RDD和Dataframe的优点: RDD(功能编程,类型安全),DataFrame(关系模型,查询优化,钨执行,排序和混排)

  • 编码器: 通过使用编码器,可以轻松地将任何JVM对象转换为数据集,从而允许用户与数据帧不同地使用结构化和非结构化数据。

  • 支持的编程语言: Datasets API当前仅在Scala和Java中可用。当前在1.6版中不支持Python和R。Python支持版本2.0。

  • 类型安全性: Datasets API提供了编译时安全性,这在Dataframes中是不可用的。在下面的示例中,我们可以看到数据集如何通过编译lambda函数对域对象进行操作。

例:

case class Person(name : String , age : Int)
val personRDD = sc.makeRDD(Seq(Person("A",10),Person("B",20)))
val personDF = sqlContext.createDataframe(personRDD)
val ds:Dataset[Person] = personDF.as[Person]
ds.filter(p => p.age > 25)
ds.filter(p => p.salary > 25)
 // error : value salary is not a member of person
ds.rdd // returns RDD[Person]
  • 互操作性:数据集可让您轻松地将现有的RDD和数据框转换为无需样板代码的数据集。

数据集API限制:-

  • 需要将类型强制转换为String: 当前从数据集中查询数据需要我们将类中的字段指定为字符串。查询数据后,我们将不得不将列强制转换为所需的数据类型。另一方面,如果我们在数据集上使用映射操作,则不会使用Catalyst优化程序。

例:

ds.select(col("name").as[String], $"age".as[Int]).collect()

不支持Python和R:从1.6版开始,数据集仅支持Scala和Java。将在Spark 2.0中引入Python支持。

与现有的RDD和Dataframe API相比,Datasets API具有更好的类型安全性和功能性编程带来的多个优势。由于API中对类型强制转换要求的挑战,您仍然不是必需的类型安全性,并且会使代码变脆。


2
spark.apache.org/docs/latest/…中,在Scala API中,DataFrame只是Dataset [Row]的类型别名。
Dean Chen

因此可以肯定地说,有了数据集,我们可以获得类型安全性而失去了优化器?
Khoa

@BlueSky获得类型安全性,并且仍然具有优化器
Gabber

@AmitDubey那不是真的。Dataset不是LINQ,lambda表达式不能解释为表达式树。因此,存在黑匣子,您几乎失去了所有(如果不是全部)优化器收益。可能缺点的一小部分:Spark 2.0数据集与DataFrame。另外,只是重复我多次声明的内容-通常,DatasetAPI 无法进行端到端类型检查。联接只是最突出的例子。
Zero323 '18

52

全部(RDD,DataFrame和DataSet)在一张图片中。

RDD与DataFrame与DataSet

图片学分

RDD

RDD 是可以并行操作的元素的容错集合。

DataFrame

DataFrame是按命名列组织的数据集。从概念上讲,它等效于关系数据库中的表或R / Python中的数据框,但在底层具有更丰富的优化

Dataset

Dataset是数据的分布式集合。数据集是Spark 1.6中添加的新接口,它具有RDD优点 (强类型输入,使用强大的lambda函数的能力)以及Spark SQL的优化执行引擎优点


注意:

Dataset[Row]Scala / Java中的行数据集()通常称为DataFrames


Nice comparison of all of them with a code snippet.

使用代码的RDD vs DataFrame vs DataSet

资源


问:能否将RDD转换为DataFrame或将RDD转换为DataFrame?

是的,两者都有可能

1。 RDDDataFrame.toDF()

val rowsRdd: RDD[Row] = sc.parallelize(
  Seq(
    Row("first", 2.0, 7.0),
    Row("second", 3.5, 2.5),
    Row("third", 7.0, 5.9)
  )
)

val df = spark.createDataFrame(rowsRdd).toDF("id", "val1", "val2")

df.show()
+------+----+----+
|    id|val1|val2|
+------+----+----+
| first| 2.0| 7.0|
|second| 3.5| 2.5|
| third| 7.0| 5.9|
+------+----+----+

更多方法:在Spark中将RDD对象转换为Dataframe

2. DataFrame/ DataSetRDDwith .rdd()方法

val rowsRdd: RDD[Row] = df.rdd() // DataFrame to RDD

27

因为它DataFrame是弱类型的,开发人员没有从类型系统中获得好处。例如,假设您要从SQL读取某些内容并对其进行一些聚合:

val people = sqlContext.read.parquet("...")
val department = sqlContext.read.parquet("...")

people.filter("age > 30")
  .join(department, people("deptId") === department("id"))
  .groupBy(department("name"), "gender")
  .agg(avg(people("salary")), max(people("age")))

当你说people("deptId"),你没有回头看看Int,或者Long,你要回Column需要对其进行操作对象。在具有丰富类型系统的语言(例如Scala)中,您最终会失去所有类型安全性,从而增加了在编译时可能发现的事物的运行时错误数量。

相反,DataSet[T]是打字。当您这样做时:

val people: People = val people = sqlContext.read.parquet("...").as[People]

您实际上是在找回一个People对象,该对象deptId是实际的整数类型而不是列类型,因此可以利用类型系统。

从Spark 2.0开始,DataFrame和DataSet API将统一,其中DataFrame将是的类型别名DataSet[Row]


5
确切地说,Spark 2.0 Dataframe 只是Dataset[Row]
零323

1
@ zero323是的,的确如此,但这仍然是微弱的类型,这就是我试图传达的内容。
Yuval Itzchakov

是的,但是更多的是存储值,而不是容器本身。即使在1.6中,这两个从技术上讲也是相同的,并且保持分开的主要原因DataFrame是避免破坏API更改。无论如何,只是想指出这一点。感谢您的编辑和支持。
zero323 '16

25

Simply RDD是核心组件,但是DataFramespark 1.30中引入的API。

RDD

称为的数据分区的集合RDD。这些RDD必须遵循一些属性,例如:

  • 一成不变
  • 容错
  • 分散式,
  • 更多。

RDD是结构化的或非结构化的。

数据框

DataFrame是Scala,Java,Python和R中可用的API。它允许处理任何类型的结构化和半结构化数据。首先,定义DataFrame为称为的命名列的分布式数据集合DataFrame。您可以轻松地优化RDDs中的DataFrame。您可以使用来一次处理JSON数据,镶木地板数据,HiveQL数据DataFrame

val sampleRDD = sqlContext.jsonFile("hdfs://localhost:9000/jsondata.json")

val sample_DF = sampleRDD.toDF()

这里Sample_DF认为是DataFramesampleRDD(原始数据)称为RDD


12

大多数答案都是正确的,只想在这里加一点

在Spark 2.0中,两个API(DataFrame + DataSet)将被统一为一个API。

“统一数据框架和数据集:在Scala和Java中,数据框架和数据集已经统一,即数据框架只是Row数据集的类型别名。在Python和R中,由于缺乏类型安全性,数据框架是主要的编程接口。”

数据集与RDD相似,但是,它们不使用Java序列化或Kryo,而是使用专用的Encoder对对象进行序列化以进行网络处理或传输。

Spark SQL支持两种将现有RDD转换为数据集的方法。第一种方法使用反射来推断包含特定对象类型的RDD的架构。这种基于反射的方法可以使代码更简洁,当您在编写Spark应用程序时已经了解架构时,可以很好地工作。

创建数据集的第二种方法是通过编程界面,该界面允许您构造模式,然后将其应用于现有的RDD。尽管此方法较为冗长,但可以在运行时才知道列及其类型的情况下构造数据集。

在这里您可以找到RDD tof数据框对话答案

如何在火花中将rdd对象转换为数据帧


8

DataFrame等效于RDBMS中的表,并且还可以通过与RDD中的“本机”分布式集合类似的方式进行操作。与RDD不同,数据框跟踪模式并支持各种关系操作,这些操作可导致更优化的执行。每个DataFrame对象都代表一个逻辑计划,但是由于它们的“懒惰”性质,除非用户调用特定的“输出操作”,否则不会执行任何操作。


2
顺便说一下,R​​DD也很懒。
2016年

6

从使用角度来看,RDD与DataFrame的见解很少:

  1. RDD很棒!因为它们使我们所有人都能灵活地处理几乎任何类型的数据;非结构化,半结构化和结构化数据。由于很多时候数据还没有准备好适合数据框架(甚至是JSON),因此可以使用RDD对数据进行预处理,以使其适合数据框架。RDD是Spark中的核心数据抽象。
  2. 并非在RDD上可能进行的所有转换在DataFrames上都可能进行,例如减去()用于RDD,而exception()用于DataFrame。
  3. 由于DataFrame就像一个关系表,因此在使用集合/关系理论转换时它们遵循严格的规则,例如,如果您想合并两个数据帧,则要求两个df都具有相同数量的列和关联的列数据类型。列名可以不同。这些规则不适用于RDD。这是一个很好的教程,解释了这些事实。
  4. 使用DataFrames可以提高性能,因为其他方面已经对此进行了深入说明。
  5. 使用DataFrame,您不需要像使用RDD进行编程时那样传递任意函数。
  6. 您需要使用SQLContext / HiveContext对数据框架进行编程,因为它们位于Spark生态系统的SparkSQL区域中,但对于RDD,您只需要位于Spark Core库中的SparkContext / JavaSparkContext。
  7. 如果可以为其定义架构,则可以从RDD创建df。
  8. 您也可以将df转换为rdd,将rdd转换为df。

希望对您有所帮助!


5

数据框是行对象的RDD,每个对象代表一条记录。数据框还知道其行的架构(即数据字段)。尽管数据框看起来像常规的RDD,但它们在内部利用其架构以更有效的方式存储数据。此外,它们提供了RDD上不可用的新操作,例如运行SQL查询的能力。可以从外部数据源,查询结果或常规RDD创建数据框。

参考:Zaharia M.等。学习火花(O'Reilly,2015)


1

Spark RDD (resilient distributed dataset)

RDD是核心数据抽象API,自Spark的第一个发行版(Spark 1.0)起可用。它是用于处理分布式数据收集的较低级别的API。RDD API公开了一些非常有用的方法,这些方法可用于对底层物理数据结构进行非常严格的控制。它是分布在不同计算机上的分区数据的不可变(只读)集合。RDD支持在大型群集上进行内存中计算,从而以容错方式加快大数据处理速度。为了实现容错,RDD使用DAG(有向无环图),它由一组顶点和边组成。DAG中的顶点和边缘分别表示RDD和要在该RDD上应用的操作。在RDD上定义的转换是惰性的,仅在调用操作时执行

Spark DataFrame

Spark 1.3引入了两个新的数据抽象API – DataFrame和DataSet。DataFrame API将数据组织到命名列中,例如关系数据库中的表。它使程序员能够在分布式数据集合上定义架构。DataFrame中的每一行都是对象类型行。与SQL表一样,每一列在DataFrame中必须具有相同数量的行。简而言之,DataFrame是延迟评估的计划,该计划指定需要对数据的分布式集合执行的操作。DataFrame也是一个不可变的集合。

Spark DataSet

作为对DataFrame API的扩展,Spark 1.3还引入了DataSet API,该API在Spark中提供了严格类型化和面向对象的编程接口。它是不可变的,类型安全的分布式数据集合。与DataFrame一样,DataSet API也使用Catalyst引擎来启用执行优化。DataSet是DataFrame API的扩展。

Other Differences --

在此处输入图片说明


0

一个数据帧是有模式的RDD。您可以将其视为关系数据库表,因为每一列都有一个名称和一个已知类型。DataFrames的强大功能来自以下事实:当您从结构化数据集(Json,Parquet ..)创建DataFrame时,Spark可以通过传递整个(Json,Parquet ..)数据集来推断模式。正在加载。然后,在计算执行计划时,Spark可以使用该架构并进行更好的计算优化。请注意,Spark v1.3.0之前将DataFrame称为SchemaRDD


0

Apache Spark – RDD,DataFrame和DataSet

Spark RDD

RDD代表弹性分布式数据集。它是记录的只读分区集合。RDD是Spark的基本数据结构。它允许程序员以容错的方式在大型群集上执行内存中计算。因此,加快了任务。

Spark数据框

与RDD不同,数据组织为命名列。例如,关系数据库中的表。它是不可变的分布式数据集合。Spark中的DataFrame允许开发人员将结构强加到分布式数据集合上,从而实现更高级别的抽象。

Spark数据集

Apache Spark中的数据集是DataFrame API的扩展,它提供了类型安全的,面向对象的编程接口。数据集通过将表达式和数据字段公开给查询计划者,从而利用了Spark的Catalyst优化器。


-1

您可以将RDD与结构化和非结构化一起使用,因为数据框/数据集只能处理结构化和半结构化数据(具有正确的架构)


-2

所有不错的答案,并且使用每个API都有一定的取舍。数据集被构建为超级API,可以解决很多问题,但是如果您了解自己的数据,并且如果处理算法经过优化可以在单次传递到大型数据中完成很多事情,那么RDD在许多情况下仍然效果最佳。RDD似乎是最佳选择。

使用数据集API进行聚合仍会消耗内存,并且随着时间的推移会变得更好。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.