Spark之 RDD、DataSet、DataFrame

本文深入探讨了Spark生态中的关键组件,包括SparkContext、SparkSession、StreamingContext的作用及相互关系,详细对比了RDD、DataFrame与DataSet的数据抽象特性,以及它们在序列化、内存管理和性能上的区别。

前言 

  1. SparkContext是RDD的环境
  2. SparkSession是DataSet和DataFrame的环境,SparkSession内部封装了SparkContext
  3. StreamingContext是Spark streaming得环境,底层封装了SparkContext
// 创建RDD 得 SparkContext 环境
val sparkConf: SparkConf = new SparkConf().setAppName("haha").setMaster("local[*]")
val sc = new SparkContext(sparkConf)

// 创建 spark sql 环境
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("haha").getOrCreate()

// 创建 Spark streaming 环境
val sparkConf: SparkConf = new SparkConf().setAppName("haha").setMaster("local[*]")

val ssc = new StreamingContext(sparkConf,Seconds(3))
  • SparkSql是将SparkSql转换成RDD然后再执行
  • SparkSql提供了两个数据抽象:DataSet和DataFrame

共性

RDD

  • 使用java序列化,序列化结果比较大,而且数据存储在java对内存中,导致gc比较频繁
  • RDD[Person],以person为类型参数,但Spark本身不了解Person的内部结构
  • 类型安全,写代码时就可以看出是否出错
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("haha").getOrCreate()
        import spark.implicits._
        val ssc: SparkContext = spark.sparkContext

        val rdd: RDD[(String, Int)] = ssc.makeRDD(Array(("a", 1), ("b", 2)))

        rdd.foreach(line => {
            println(line._1 + "_" +line._2)
        })

 DataFrame

  • 采用kryo序列化,由于数据辕信息spark已经保存,序列化时不需要带上元信息,序列化的只有数据本身。且数据保存在堆外内存中,较少了gc次数,所以运行更快
  • DataFrame提供了详细的结构信息,类似于数据库中的一张表,性能比RDD快,因为经过优化
  • 类型不安全
df.foreach{
            line=>
                // DataFrame每一行的类型固定为Row,只有通过解析才能获取各个字段的值
                val col1: Unit = line.getAs[String]("col1")
                val col2: String = line.getAs[String]("col2")
                // 第二种方法
                val col1 : String = line.getString(1)
        }

 DataSet

  • DataSet(1.6才有),和DataFrame一样,使用kryo序列化,采用堆外内存
  • 类型安全
  1. 样例类被用来在DataSet中定义数据的结构信息,样例类中的每个属性的名称直接映射到DataSet中的字段名称
  2. DaraFrame是DataSet的特例,DataFrame = DataSet[Row],Row是一个类型,可以是Car、Person,或者说样例类。
  3. DataFrame只知道字段,不知道字段的类型,所以没办法再编译的时候检查是否类型失败的。而DataSet不仅知道字段,还知道类型
object test11 {
    def main(args: Array[String]): Unit = {

        val spark: SparkSession = SparkSession.builder().master("local[*]").appName("haha").getOrCreate()
        import spark.implicits._
        val ssc: SparkContext = spark.sparkContext

        val rdd: RDD[(String, Int)] = ssc.makeRDD(Array(("a", 1), ("b", 2), ("c", 3)))
        
        val ds: Dataset[Coltest] = rdd.map(line =>
            Coltest(line._1, line._2)
        ).toDS()

        ds.map {
            line =>
                // 可以直接访问 DS 中的字段
                println(line.col1)
                println(line.col2)
        }
        
    }
}

case class Coltest(col1: String, col2: Int) extends Serializable //定义字段名和类型

 

<think>好的,我现在需要详细回答用户关于SparkRDDDataFrameDataset之间区别的问题。首先,我得回顾一下用户提供的引用资料,确保回答准确。 根据引用[1],RDDSpark1.0引入的,DataFrame在1.3版本出现,而Dataset则是在1.6版本加入的。这三者在处理相同数据时结果一致,但执行效率和方式不同。用户可能关心它们的演变和性能差异。 引用[4]提到,RDD是底层抽象,DataFrameDatasetRDD之上做了优化,使用更方便。RDD能做的,DataFrame/DataSet不一定能做。这说明RDD更灵活,而高层API功能受限但高效。 引用[5]指出,RDD需要开发者使用算子处理数据,开发成本高,而DataFrameDataset支持SQL操作,更适合结构化数据。这里需要强调API的易用性和适用场景。 接下来,我需要组织回答的结构,可能按版本演进、数据结构、执行优化、适用场景等方面展开。同时要比较三者的共性和差异,比如类型安全、优化机制等。 用户的问题可能还涉及转换示例,引用[3]中的代码展示了RDDDataFrameDataset之间的转换,可以引用这部分说明互操作性。需要注意Dataset的类型安全特性,比如在编译时检查类型,而DataFrame在运行时检查。 最后,生成相关问题时要围绕区别、使用场景、优化方法等方面,帮助用户深入理解。例如,如何选择三者,性能比较,转换方法等。 需要确保回答符合系统指令,正确使用LaTeX格式,如版本号写成$Spark1.0$,但根据示例,可能需要用代码块或普通文字。不过用户示例中的版本号未用LaTeX,可能直接使用数字即可。需要检查LaTeX的使用是否正确,比如独立公式用$$...$$,但这里可能不需要数学公式,更多是代码块和术语强调。 总结回答结构: 1. 版本演进 2. 数据结构差异(无结构 vs 结构) 3. 执行优化(Catalyst优化器,Tungsten) 4. 类型安全(Dataset的编译时检查) 5. 性能比较 6. 使用场景 7. 转换示例(引用代码) 8. 总结对比表格 然后生成相关问题,如性能优化、如何选择、转换方法等。</think>### SparkRDDDataFrameDataset的区别详解 #### 1. **版本演进与核心定位** - **RDD (弹性分布式数据集)**:Spark1.0引入的核心抽象,是Spark所有功能的基础。它代表一个不可变、分区的数据集合,支持并行操作,开发需通过`map`、`filter`等算子实现细粒度控制[^1][^4]。 - **DataFrame**:Spark1.3推出,基于RDD封装,以**结构化数据**为核心(类似二维表),支持SQL查询和优化器(Catalyst),但**无类型安全**(运行时检查)[^1][^5]。 - **Dataset**:Spark1.6新增,结合了RDD的类型安全和DataFrame的执行效率,支持**编译时类型检查**,适用于强类型语言(如Scala)[^1][^3]。 #### 2. **数据结构与API** | 特性 | RDD | DataFrame | Dataset | |---------------|------------------------|--------------------|--------------------| | **数据结构** | 无模式(任意对象) | 行类型(Row) | 强类型(样例类) | | **API类型** | 函数式算子(如`map`) | 声明式(SQL/DSL) | 混合式(类型安全) | - **RDD**:处理非结构化数据灵活,但需手动优化。例如: ```scala val rdd = sc.parallelize(Seq(1, 2, 3)) rdd.map(_ * 2) // 需手动实现逻辑 ``` - **DataFrame**:通过列式存储优化查询,例如: ```sql df.select("name").filter($"age" > 20) // 类似SQL操作 ``` - **Dataset**:结合两者优势,例如: ```scala case class Person(name: String, age: Int) val ds: Dataset[Person] = df.as[Person] // 类型安全转换[^3] ``` #### 3. **执行优化** - **RDD**:无内置优化,依赖开发者手动调优。 - **DataFrame/Dataset**:通过**Catalyst优化器**自动优化逻辑计划,并利用**Tungsten引擎**提升执行效率(如堆外内存、代码生成)[^4][^5]。 #### 4. **类型安全与适用场景** - **类型安全**: - RDD:编译时类型安全(如`RDD[Int]`)。 - DataFrame:无类型安全(`Row`类型字段在运行时解析)。 - Dataset:编译时类型安全(如`Dataset[User]`)[^3][^4]。 - **适用场景**: - **RDD**:非结构化数据、复杂数据处理(如图计算)。 - **DataFrame/Dataset**:结构化数据、交互式分析、ETL流程[^5]。 #### 5. **性能对比** - **执行速度**:DataFrame/Dataset通常优于RDD(Catalyst优化)。 - **内存效率**:DataFrame列式存储更节省空间[^4]。 #### 6. **互相转换** 三者可通过API互相转换(需注意类型匹配): ```scala // RDD -> DataFrame val df = rdd.toDF("id", "name") // 需指定列名[^3] // DataFrame -> Dataset case class User(id: Int, name: String) val ds = df.as[User] // 依赖样例类 // Dataset -> RDD val rdd = ds.rdd // 转为RDD[User] ``` #### 总结 | 维度 | RDD | DataFrame | Dataset | |------------|--------------|----------------|----------------| | **灵活性** | 高(无模式) | 中(结构化) | 中(强类型) | | **性能** | 低 | 高 | 高 | | **易用性** | 低 | 高(SQL支持) | 高(类型安全) | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值