spark进阶(五):DataFrame和DataSet使用
DataFrame是Spark SQL提供的一个编程抽象,与RDD类似,也是一个分布式的数据集合。但与RDD不同的是,DataFrame的数据都被组织到有名字的列中,就像关系型数据库中的表一样。此外,多种数据都可以转化为DataFrame,例如Spark计算过程中生成的RDD、结构化数据文件、Hive中的表、外部数据库等。
在Spark中,一个DataFrame所代表的是一个元素类型为Row的Dataset,即DataFrame只是Dataset[Row]的一个类型别名。相对于RDD,Dataset提供了强类型支持,在RDD的每行数据加了类型约束。而且使用DatasetAPI同样会经过Spark SQL优化器的优化,从而提高程序执行效率。
DataFrame和R的数据结构以及python pandas DataFrame的数据结构和操作基本一致。
一、创建DataFrame、DataSet
- 创建RDD
- RDD转化为ROW
- 通过ROW和元数据信息生成DataFrame
- 然后通过DataFrame和对应的类转化为DataSet
- 也就是说DataFrame是DataSet[Row],这里可以通过指定的类将其转化,DataSet[User]
- 需要注意的事转化使用的类需要时内部类,然后就是类里的变量名要和元数据信息的列名保持对齐
/**
* @author: ffzs
* @Date: 2021/10/7 上午8:33
*/
object MovieLenDataSet {
case class User(UserID:String, Gender:String, Age:String, Occupation:String, Zip_Code:String)
def main(args: Array[String]): Unit = {
Logger.getLogger("org").setLevel(Level.ERROR)
val spark = SparkSession.builder()
.appName("MovieLenDataSet")
.master("local[*]")
.getOrCreate()
import spark.implicits._
val dataPath = "/home/ffzs/data/ml-1m"
val schema4users = StructType(
"UserID::Gender::Age::Occupation::Zip_code"
.split("::")
.map(it => StructField(it, StringType, nullable = true))
)
val usersRdd = spark.sparkContext.textFile(f"$dataPath/users.dat")
val usersRows = usersRdd.map(_.split("::"))
.map(it => {
it.map(_.trim)
})
.map(it => Row(it(0), it(1), it(2), it(3), it(4)))
val usersDF: DataFrame = spark.createDataFrame(usersRows, schema4users)
val usersDataSet = usersDF.as[User]
usersDataSet.show(5)
}
}
二、DataSet使用练习
1.最常见电影类型
- 对电影类型进行split,然后再聚合计数
- 然后再通过计数进行排序
println("最常见电影类型:"