其他更多java基础文章:
java基础学习(目录)
学习资料:Spark-SQL之DataFrame基本操作
Spark SQL 函数全集
再谈RDD、DataFrame、DataSet关系以及相互转换(JAVA API)
DataFrame常用方法(代码详细)
DataSet常用方法(代码详细)
DataFrame基本原理
我们知道,RDD是spark早期很重要的一个概念,是数据的immutable distributed的集合,由不同节点上的partition组成。DataFrame和RDD类似,也是数据的不可变分布式集合。不同的是,数据被组织成带名字的列,就像关系型数据库中的表。是一种有结构的高级别抽象,与之相应的提供了一种领域特定语言(DSL)API来操作这些分布式数据。

在spark2.0后,DataFrame的API和DataSet的API合并统一了,DataFrame相当于DataSet[Row]。现在只需要处理DataSet相关API即可。
DataFrame的限制
- 没有编译阶段的类型检查: 不能在编译时刻对安全性做出检查,而且限制了用户对于未知结构的数据进行操作。比如下面代码在编译时没有错误,但是在执行时会出现异常:
case class Person(name : String , age : Int)
val dataframe = sqlContect.read.json("people.json")
dataframe.filter("salary > 10000").show
=> throws Exception : cannot resolve 'salary' given input age , name
- 不能保留类对象的结构: 一旦把一个类结构的对象转成了Dataframe,就不能转回去了。下面这个栗子就是指出了:
case class Person(name : String , age : Int)
val personRDD = sc.makeRDD(Seq(Person("A",10),Person("B",20)))
val personDF = sqlContect.createDataframe(personRDD)
personDF.rdd // returns RDD[Row] , does not returns RDD[Person]
DataSet
Dataset API是对DataFrame的一个扩展,使得可以支持类型安全的检查,并且对类结构的对象支持程序接口。它是强类型的,不可变collection,并映射成一个相关的schema。 Dataset API的核心是一个被称为Encoder的概念。它是负责对JVM的对象以及表格化的表达(tabular representation)之间的相互转化。 表格化的表达在存储时使用了Spark内置的Tungsten二进制形式,允许对序列化数据操作并改进了内存使用。在Spark 1.6版本之后,支持自动化生成Encoder,可以对广泛的primitive类型(比如String,Integer,Long等)、Scala的case class以及Java Bean自动生成对应的Encoder。
DataFrame也可以叫Dataset[Row],每一行的类型是Row,不解析,每一行究竟有哪些字段,各个字段又是什么类型都无从得知,只能用上面提到的getAS方法或者共性中的第七条提到的模式匹配拿出特定字段
而Dataset中,每一行是什么类型是不一定的,在自定义了case class之后可以很自由的获得每一行的信息
DataFrame和DataSet的创建
park2.0以前,使用不同的数据类型,需要采用不同的入口类,如RDD对应的入口类是SparkContext,DataFrame对应的入口类是SQLContext或者HiveContext,入口类用于指定Spark集群的各种参数,并与资源管理器做交互。
Spark2.0开始及之后,提出了一个统一的入口类SparkSession,封装了SparkContext、SQLContext和HiveContext。具体代码可以看学习资料中的再谈RDD、DataFrame、DataSet关系以及相互转换(JAVA API)
- 如果要创建RDD,需要通过SparkSession入口类获取SparkContext入口类
- 如果要创建DataFrame和DataSet,通过 SparkSession入口类即可。
创建DataFrame的几种方式
- 1、读取json格式的文件创建DataFrame
- 2、通过json格式的RDD创建DataFrame
- 非json格式的RDD创建DataFrame(重要)
- 通过反射的方式将非json格式的RDD转换成DataFrame
- 动态创建Schema将非json格式的RDD转换成DataFrame(建议使用)
通过反射的方式将非json格式的RDD转换成DataFrame
/**
* 传入进去Person.class的时候,sqlContext是通过反射的方式创建DataFrame
* 在底层通过反射的方式获得Person的所有field,结合RDD本身,就生成了DataFrame
*/
DataFrame df = sqlContext.createDataFrame(personRDD, Person.class);
df.show();
df.registerTempTable("person");
sqlContext.sql("select name from person where id = 2").show();
动态创建Schema将非json格式的RDD转换成DataFrame
/**
* 动态构建DataFrame中的元数据,一般来说这里的字段可以来源自字符串,也可以来源于外部数据库
*/
List<StructField> asList =Arrays.asList(//这里字段顺序一定要和上边对应起来
DataTypes.createStructField("id", DataTypes.StringType, true),
DataTypes.createStructField("name", DataTypes.StringType, true),
DataTypes.createStructField("age", DataTypes.IntegerType, true)
);
StructType schema = DataTypes.createStructType(asList);
DataFrame df = sqlContext.createDataFrame(rowRDD, schema);
df.show();