【Spark SQL】- RDD DataFrame Dataset 三者的优缺点 , 三者之间的创建 , 以及相互转换

一.简单介绍

1.RDD

  • RDD 是一个懒执行(只有当遇到action算子时才会真正的开始执行)的不可变的的 可以支持 lambda 表达式 的并行数据集
  • RDD 的最大优势就是简单 , 毕竟容易上手
  • RDD 的 劣势在于 , 它是一个存在于 JVM 内存中的对象 , JVM 内存是计算机内存划分的一块空间 , 所以它受到 Gc (JVM 自己的垃圾处理器 , 用来回收一些不用的对象 , 但是 Spark 框架是没法控制这个 GC 什么时候回收垃圾对象, 很可能这个RDD 已经不使用了 , 但是它仍然存在于 JVM 内存中 , 这样就会占用内存 , 而 JVM 内存又是有大小限制的 , 所以一旦内存过大 , JVM 就会崩溃) , 而且 当数据增加时 , Java 序列化的成本也相应提高 !

2.DataFrame

  • DataFrame 也是懒执行的 , 它的API 更加容易上手 , 也支持 lambda , 并且, DataFrame 没有GC的限制, 因为它是存在于堆外内存的 , 不会受到JVM虚拟机内存的限制, 并且, 垃圾回收也可以由 Spark 框架自己来控制
  • DataFrame 相比较于 RDD 增加了数据类型 , 它更像一张表格 如下图
    在这里插入图片描述
  • 对查询进行了一些优化 , 使其性能提高
  • DataFrame 的缺点 , 编译期间不会进行类型安全检查 (就是检查你传入的对象的类型是否和你正确的类型是否一致 , 比如 name 是 String 类型 , 假如你传入一个int 类型的 , 编译期间也不会报错 , 只有运行时才会报错 不知道理解的对不对?)

3.Dataset

  • 拥有 DataFrame 所有优点 , 并且性能比 DataFrame 更强 , API 更人性化 (暂时没感受到 反正资料是这样写的)
  • 拥有类型安全检查
  • Dataset支持编解码器,当需要访问非堆上的数据时可以避免反序列化整个对象,提高了效率。(因为Dataset 的数据时分布在其他不同节点上的 , 在传输过程中需要序列化成 字节流 , 而编码器可以避免反序列化 提高效率)
  • JavaBean类被用来在Dataset中定义数据的结构信息,样例类中每个属性的名称直接映射到DataSet中的字段名称。
  • (重点) Dataframe是Dataset的特列,DataFrame=Dataset[Row] ,所以可以通过as方法将Dataframe转换为Dataset。Row是一个类型,跟Car、Person这些的类型一样,所有的表结构信息我都用Row来表示。
  • DataSet是强类型的。比如可以有Dataset[Car],Dataset[Person].
  • DataFrame只是知道字段,但是不知道字段的类型,所以在执行这些操作的时候是没办法在编译的时候检查是否类型失败的,比如你可以对一个String进行减法操作,在执行的时候才报错,而DataSet不仅仅知道字段,而且知道字段类型,所以有更严格的错误检查。就跟JSON对象和类对象之间的类比。

二. 创建 RDD DataFrame Dataset

1.所用数据

  • person,json
{"name":"Michael", "age":12}
{"name":"Andy", "age":30}
{"name":"Justin", "age":19}
{"name":"kafak", "age":19}
  • person.txt
Michael, 29
Andy, 30
Justin, 19

2. 创建 RDD DataFrame Dataset

  • JavaBean 用来封装数据
	// 切记 需要实现 Serializable !!! Person 的类修饰符是public
    public static class Person implements Serializable {

        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public Person() {
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
  • 创建RDD
    这个比较简单 , 直接使用 对应方法读取数据即可返回一个RDD
    这里注意 直接 spark.read().textFile() 读取返回的是一个 DataFrame 对象
 // 1.从一个已经存在的文件读取数据 并创建一个存储 Person 对象的RDD
        JavaRDD<String> dataRDD = spark
                .read()
                .textFile("SparkSql/src/main/resources/people.txt")
                .javaRDD(); 
  • 创建一个 DataFrame
   JavaRDD<String> dataRDD = spark
                .read()
                .textFile("SparkSql/src/main/resources/people.txt");
  • RDD 转化为 DataFrame
// 2.将 people.txt 进行切分 , 并将对应的 数据封装到 Person
        /**
         * 将读取到的数据封装到 Person对象中 , 然后再将 Person 存储到新的RDD 中
         * dataRDD -> Michael, 29 -> Person(Michael, 29) -> peopleRDD<Person>
         */
        /*JavaRDD<Person> peopleRDD = dataRDD.map(new Function<String, Person>() {
            @Override
            public Person call(String v1) throws Exception {
                // 对数据进行切分
                String[] parts = v1.split(",");
                Person person = new Person();
                person.setName(parts[0]);
                person.setAge(Integer.parseInt(parts[1].trim())); // 注意去除空格
                return person;
            }
        });*/
        // 注意 上面注释的是以前的写法 , 这里我们可以使用 lamda 表达式 如下 : 用法和 scala 相似
        JavaRDD<Person> peopleRDD = dataRDD
                .map(line ->{
                    String[] parts = line.split(",");
                    Person person = new Person();
                    person.setName(parts[0]);
                    person.setAge(Integer.parseInt(parts[1].trim())); // 注意去除空格
                    return person;
                });

        // 将 RDD 转化为一个DataFrame
        // 为了容易区分 命名时 : peopleDF 代表 DataFrame peopleDS 代表Dataset
        Dataset<Row> peopleDF = spark
                // 这里 CreateDataFrame(RDD , JavaBean对象.class) 如下
                // JavaBean 对象就是你把数据封装到的那个对象
                .createDataFrame(peopleRDD, Person.class);

如上 : 这里需要注意的是 , 因为我把读取的数据封装到 Person 对象中 所以代码比较多
实际上转化很简单 完整代码如下

 JavaRDD<String> dataRDD = spark
                .read()
                .textFile("SparkSql/src/main/resources/people.txt")
                .javaRDD(); 
	// 注意 RDD 内存储是xxx类型的 , 后面就写 xxx.class
    Dataset<Row> peopleDF = spark.createDataFrame(dataRDD, String.class);
	
	// 创建一个临时表
        peopleDF.createOrReplaceTempView("people");

        // 进行查询
        // 注意 : 必须先创建表才能查询 , 查询语句的方法在 SparkSession
        // SparkSession的理解 : 可以认为是你在 windows 用 连接数据库工具的一次连接
        // 然后SparkSession的一些方法可以理解成对应的 一些功能 , 比如 sql()
        // 可以理解成开启了一个查询窗口 ..

        // 使用Sql 语句进行查询
        // 注意 这个结果是包含所有 年龄在 13 到 19 的人的名字
        Dataset<Row> teenagersDF = spark
                .sql("SELECT name FROM people WERE age BETWEEN 13 AND 19");
  • DataFrame 转化成 Dataset
// 重点 !!!!! 如何将 DataFrame 转化为 Dataset

        // 1) 第一步 需要有个对应类型的编码器
        // 这里,由于name都是String 类型的 我们可以使用一个 String 类型的编码器
        // 1.创建一个String类型的编码器
        // 创建方式都是一样的 这里我多举几个例子 , 便于理解
        Encoder<String> stringEncoder = Encoders.STRING();
        // 2.创建一个 Integer 类型的编码器
        Encoder<Integer> integerEncoder = Encoders.INT();
        // 3.创建一个 自定义类型的编码器 , 比如 Person 这里需要特别注意 参数填的是 类名.class
        Encoder<Person> personEncoder = Encoders.bean(Person.class);

        // 2) 第二步 , 将对应的DataFrame 转化为 Dataset
        Dataset<String> teenagersDS = teenagersDF.as(stringEncoder);

这里特别注意 : DataFrame 是特殊的Dataset 因为所有的数据都只有一个类型就是
Dataset<Row> 这一个类型 , 而 Dataset有很多类型 比如 Dataset<String> Dataset<Person>

暂时更新到这

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兀坐晴窗独饮茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值