Apache Spark中RDD、DataFrame、Dataset的区别及适用场景有哪些?
Apache Spark RDD、DataFrame、Dataset 核心差异与选型指南
三类API核心差异
我们可以从几个核心维度直接区分三者的不同:
RDD(弹性分布式数据集)
作为Spark最早推出的底层API,它的特性非常明确:
- 本质是不可变的分布式原生对象集合,所有操作直接针对Java/Scala/Python的原生对象执行
- 完全类型安全,所有类型错误会在编译阶段直接抛出,比如给Int类型的RDD执行字符串拼接操作,编译直接不通过
- 没有内置执行优化,算子执行顺序完全和你写的代码一致,谓词下推、列裁剪、Join顺序调整这类优化全要自己手动实现,新手写的RDD代码通常比同等逻辑的DataFrame性能低3~10倍
- 序列化走原生Java/Kryo序列化,每次操作要序列化完整对象,序列化/反序列化开销极高
- 支持全语言(Scala/Java/Python/R),API为纯函数式风格,自由度拉满,几乎可以实现任意数据处理逻辑
DataFrame
Spark 1.3推出的结构化数据API,目前是Spark生态里使用最广泛的接口:
- 本质是带Schema约束的分布式行集合,概念和关系型数据库的表完全对齐
- 无类型安全,列名写错、列类型不匹配这类问题要到运行阶段才会暴露,比如你把
user_name拼成usre_name,代码编译完全通过,跑的时候才会抛列不存在的异常,很多新手都踩过这个坑 - 内置Catalyst优化引擎,自动做执行计划优化,不用手动写优化逻辑,性能比未优化的RDD高很多
- 序列化基于Tungsten二进制格式,只序列化需要用到的字段,内存开销比RDD低一个数量级
- 支持全语言,API偏向SQL风格,熟悉SQL的开发者半天就能上手,也可以直接写Spark SQL操作DataFrame
- 对结构化数据源的适配最完善,读写JDBC、JSON、Parquet、Hive表都只需要几行代码
Dataset
Spark 1.6推出的API,相当于RDD和DataFrame的结合体,目前仅支持Scala和Java(Python/R是动态类型语言,没有对应实现):
- 结合了RDD的类型安全特性和DataFrame的性能优化能力,编译阶段就能捕获类型错误,同时享受Catalyst优化和Tungsten序列化的性能红利,性能和DataFrame几乎持平
- 可以直接操作自定义的类对象,比如Scala里你定义了
case class User(id:Int, name:String, age:Int),就可以直接对Dataset[User]里的User对象调用自定义方法,不用像DataFrame一样只能操作Row对象 - API同时支持函数式风格和SQL风格,开发体验非常友好
选型判断标准与适用场景
你只需要对照下面几个维度判断,就能快速选到合适的API:
优先选RDD的场景
- 处理非结构化数据(比如原始日志文本、二进制媒体文件),需要做非常灵活的自定义处理,结构化API的约束满足不了需求
- 需要对执行过程做细粒度控制,比如自定义分区规则、自定义累加器、自定义Shuffle逻辑,自动优化引擎的能力达不到你的定制要求
- 维护Spark 1.3之前版本的老项目(目前这类场景已经非常少)
优先选DataFrame的场景
- 用Python/R开发,没有Dataset可选
- 做临时数据分析、普通ETL任务、报表开发,团队成员更熟悉SQL语法,对开发效率的要求高于强类型校验
- 对接多种结构化数据源,DataFrame的原生数据源支持能帮你省很多对接代码
- 处理TB/PB级超大规模数据,自动优化能帮你省去大量手动调优的时间
- 90%的常规大数据处理场景用DataFrame都能很好的满足,也是现在生产环境用的最多的API
优先选Dataset的场景
- 用Scala/Java开发,核心业务逻辑对稳定性要求极高,要尽可能把错误拦截在编译阶段,避免线上故障
- 既要写复杂的函数式数据处理逻辑,又不想牺牲执行性能
- 做Spark Structured Streaming流式处理任务,强类型校验能帮你规避很多流处理运行时的诡异问题
内容的提问来源于stack exchange,提问作者Arjunlal M.A
相关产品推荐
相关产品推荐

