SparkSQL——Dataset

Dataset

  • Dataset 是什么?

    @Test
      def dataset1():Unit ={
        // 1. 创建 SparkSession
        val spark = new SparkSession.Builder()
          .master("local[6]")
          .appName("dataset1")
          .getOrCreate()
        // 2. 导入隐式转换
        import spark.implicits._
        // 3. 演示
        val sourceRDD = spark.sparkContext.parallelize(Seq(Person("zhangsan", 10), Person("lisi", 15)))
        val dataset:Dataset[Person] = sourceRDD.toDS()
    
        // DataSet 支持强类型的 API
        dataset.filter(item=> item.age>10).show()
        // Dataset 支持弱类型的API
        dataset.filter('age>10).show()
        dataset.filter($"age">10).show()
        // DataSet 支持 直接写 SQL 表达式
        dataset.filter("age>10").show()
      }
    
    case class Person(name: String, age: Int)
    

    问题1: Person 是什么?

    Person 是一个强类型的类

    问题2: 这个 Dataset 中是结构化的数据吗?

    非常明显是的, 因为 Person 对象中有结构信息, 例如字段名和字段类型

    问题3: 这个 Dataset 能够使用类似 SQL 这样声明式结构化查询语句的形式来查询吗?

    当然可以, 已经演示过了

    问题4: Dataset 是什么?

    Dataset 是一个强类型, 并且类型安全的数据容器, 并且提供了结构化查询 API 和类似 RDD 一样的命令式 API

  • Dataset 底层是什么

    即使使用 Dataset 的命令式 API, 执行计划也依然会被优化

    Dataset 具有 RDD 的方便, 同时也具有 DataFrame 的性能优势, 并且 Dataset 还是强类型的, 能做到类型安全.

    @Test
      def dataset2():Unit = {
        // 1. 创建 SparkSession
        val spark = new SparkSession.Builder()
          .master("local[6]")
          .appName("dataset2")
          .getOrCreate()
        // 2. 导入隐式转换
        import spark.implicits._
        // 3. 演示
        val sourceRDD = spark.sparkContext.parallelize(Seq(Person("zhangsan", 10), Person("lisi", 15)))
        val dataset: Dataset[Person] = sourceRDD.toDS()
        //优化
    		dataset.explain(true) // 查看其逻辑计划和物理计划,运行会直接打印
        
    }
    case class Person(name: String, age: Int)
    

    Dataset 的底层是什么?

    Dataset 最底层处理的是对象的序列化形式, 通过查看 Dataset 生成的物理执行计划, 也就是最终所处理的 RDD, 就可以判定 Dataset 底层处理的是什么形式的数据

    val dataset: Dataset[People] = spark.createDataset(Seq(Person("zhangsan", 10), Person("lisi", 15)))
    val internalRDD: RDD[InternalRow] = dataset.queryExecution.toRdd
    
    case class Person(name: String, age: Int)
    

    dataset.queryExecution.toRdd 这个 API 可以看到 Dataset 底层执行的 RDD, 这个 RDD 中的范型是 InternalRow, InternalRow 又称之为 Catalyst Row, 是 Dataset 底层的数据结构, 也就是说, 无论 Dataset 的范型是什么, 无论是 Dataset[Person] 还是其它的, 其最底层进行处理的数据结构都是 InternalRow
    所以, Dataset 的范型对象在执行之前, 需要通过 Encoder 转换为 InternalRow, 在输入之前, 需要把 InternalRow 通过 Decoder 转换为范型对象

    在这里插入图片描述

    可以获取 Dataset 对应的 RDD 表示

    在 Dataset 中, 可以使用一个属性 rdd 来得到它的 RDD 表示, 例如 Dataset[T] → RDD[T]

    @Test
      def dataset2():Unit = {
        // 1. 创建 SparkSession
        val spark = new SparkSession.Builder()
          .master("local[6]")
          .appName("dataset2")
          .getOrCreate()
        // 2. 导入隐式转换
        import spark.implicits._
        // 3. 演示
    //    val sourceRDD = spark.sparkContext.parallelize(Seq(Person("zhangsan", 10), Person("lisi", 15)))
    //    val dataset: Dataset[Person] = sourceRDD.toDS()
        //优化
    
        val dataset: Dataset[Person] = spark.createDataset(Seq(Person("zhangsan", 10), Person("lisi", 15)))
        //    dataset.explain(true) // 查看其逻辑计划和物理计划,运行会直接打印
        // 无论DataSet 放置的是什么类型对象,最终执行计划中的RDD 上都是InternalRow
        // 直接获取到已经分析和解析过的DataSet的执行计划,从中拿到RDD
        val executionRdd:RDD[InternalRow] = dataset.queryExecution.toRdd // 把生成的计划转为rdd
    
        //通过将DataSet 底层的RDD[InternalRow] 通过Decoder 转成了DataSet一样的类型RDD
        val typeRDD: RDD[Person] = dataset.rdd
    		// (1)
        println(executionRdd.toDebugString)
        /*
        * (2) MapPartitionsRDD[1] at toRdd at Intro.scala:97 []
        *  |  ParallelCollectionRDD[0] at toRdd at Intro.scala:97 []
        * */
        println("-------------------------")
    		// (2)// 这段代码的执行计划为什么多了两个步骤?
        println(typeRDD.toDebugString)
        /*
        * (2) MapPartitionsRDD[5] at rdd at Intro.scala:102 []
        *  |  MapPartitionsRDD[4] at rdd at Intro.scala:102 []
        *  |  MapPartitionsRDD[3] at rdd at Intro.scala:102 []
        *  |  ParallelCollectionRDD[2] at rdd at Intro.scala:102 []
        * */
    
      }
    
    case class Person(name: String, age: Int) // 放在class 外
    

    (1)Dataset 的执行计划底层的 RDD

    (2)使用 Dataset.rdd 将 Dataset 转为 RDD 的形式

    可以看到 (1) 对比 (2) 对了两个步骤, 这两个步骤的本质就是将 Dataset 底层的 InternalRow 转为 RDD 中的对象形式, 这个操作还是会有点重的, 所以慎重使用 rdd 属性来转换 Dataset 为 RDD

总结

  • Dataset 是一个新的 Spark 组件, 其底层还是 RDD
  • Dataset 提供了访问对象中某个特定字段的能力, 不用像 RDD 一样每次都要针对整个对象做操作
  • Dataset 和 RDD 不同, 如果想把 Dataset[T] 转为 RDD[T], 则需要对 Dataset 底层的 InternalRow 做转换, 是一个比价重量级的操作
  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spark SQL中的DataFrame和Dataset是两种非常重要的数据结构,它们都是基于RDD的分布式数据集,但是它们提供了更高级别的API,可以更方便地进行数据处理和分析。 DataFrame是一种类似于系型数据库中表的数据结构,它由一组有命名的列组成,每个列都有一个数据类型。DataFrame可以通过SQL语句或者DataFrame API进行查询和操作,支持类似于SQL的聚合、过滤、排序等操作,同时也支持复杂的数据类型和嵌套结构。 DatasetSpark 1.6版本引入的新概念,它是一个类型安全的分布式数据集,可以通过编译时检查来避免类型错误。Dataset可以看作是DataFrame的扩展,它支持更多的操作和更高级别的API,同时也提供了更好的性能和可维护性。 总的来说,DataFrame和Dataset都是Spark SQL中非常重要的数据结构,它们提供了更高级别的API和更好的性能,可以帮助我们更方便地进行数据处理和分析。 ### 回答2: DataFrame和DataSetSpark SQL中处理数据的两种最常用的API。在这两个API中,数据使用的是表格形式,而且API的使用非常类似。然而,在很多情况下,DataFrame和DataSet还是有些不同的。 DataFrame是Spark SQL中的一个系数据,可以从各种数据源中读取数据,例如:结构化数据文件、Hive中的表、外部系数据库中的表、Avro文件等等。DataFrame是基于分布式数据集的一组数据结构,每个数据集都分为行和列,并且有一个命名的列。DataFrame在 Spark SQL中作为一种概念,表示分布式的数据集,就像一个表格一样,它具有由向量组成的列,每一列都有一个名称和数据类型。 DataSetSpark 1.6中引入并在Spark 2.0中得到加强。DataSet是强类型API,它提供了类似于RDD的泛型编程接口,同时也继承了DataFrame的一些理念。与DataFrame不同的是,DataSet具有额外的类型安全和更好的性能。其中,DataSet是有类型的,也就是说,在DataSet中存储的数据必须要指定一个类,使用该类的实例来表示数据。 在使用的过程中,DataFrame和DataSet的区别表现在: 1. 类型:DataFrame是一组分布式数据集合,是无类型的 (untyped),因为它们只是在特定的列名和数据类型上进行了验证。而DataSet是强类型的 (typed),因为DataSet可以在编译时对数据的类型进行验证。 2. 优化:DataFrame提供了基于第一代Tungsten的基于列的计算引擎来优化计算,以支持高性能计算。而DataSet提供了基于第二代Tungsten的代码生成器,产生了比DataFrame更优化的代码。 3. 开发复杂度:代码开发的复杂度上,DataSet需要在类型定义中显式声明模式 (schemas),这会增加一些重复的代码,而DataFrame不需要这样做。 在实际使用过程中,一般情况下,若处理数据时进行数值处理、聚合操作或者切片取部分数据,可以使用 DataFrame。而当数据需要更多的定制操作、需要常规编程的工作时,就要使用 DataSet。 因此,对于数据的处理操作而言,DataFrame和DataSet都是非常重要的API,我们可以根据具体的业务需求来选择使用哪一种API。在使用这两个API时我们要根据自己的需求选择哪一种更适合自己的场景。 ### 回答3: Spark是当前最流行的大数据处理框架之一,它有着强大的处理能力和高效的分布式计算能力。在 Spark 中,DataFrame 和 DataSet 是两种常用的数据结构,它们提供了很多操作特性,使 Spark SQL 变得更加方便、快捷和高效。 DataFrame 是一种有结构的分布式数据集合,它是以列为中心的数据结构,具有传统上的行和列的属性。DataFrame 是使用 Spark SQL 系统中非常重要的概念,主要用于处理结构化数据。DataFrame 支持多种数据源:csv 文件、JSON、Hive、ORC、Parquet、Apache Hive 和 JDBC 数据库等。另外,DataFrame 比 RDD 操作更加高效,在实现上采用了更高级的方法,例如使用 Catalyst 引擎进行优化和查询计划处理,同时还支持 SQL 操作。 DataSetSpark 2.0 版本新增的数据结构,它是一个类型化的分布式数据集合,与 RDD 不同,它需要在编译期间就确定类型。DataSet 数据集合支持 Scala 和 Java 两种语言,并兼容 Spark 原有的操作特性,例如分布式处理、错误容错、高效计算等操作。DataSet 在类型安全和语言特性的支持上比 DataFrame 更加强大,因此可以避免在运行时出现类型匹配错误的问题。 与 DataFrame 相比,DataSet 具有更强的类型安全性和启发式优化特性,因此在某些情况下会比 DataFrame 更加高效和快速。但是,DataSet 操作有时会变得比较复杂,并且需要程序员具备额外的类型知识。因此,根据实际需求来选择适当的数据集合是非常重要的。 总的来说,DataFrame 和 DataSet 都是很重要的 Spark SQL 数据结构,在 Spark 编程中都有着不可替代的作用。使用 DataFrame 和 DataSet 可以帮助我们更加快速、方便地处理分布式数据,提高我们的开发效率和代码质量。建议根据项目的需要来选择使用哪种数据集合,在具体操作中尽量避免数据类型转换和类型匹配错误等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值