Dataset 是一个分布式的数据集
DataFrame ,是以列(列名,列的类型,列值)的形式构成的分布式数据集(Dataset),按照列赋予不同的名称。可以理解为一张表
例如:
student 表 有id,name等列名,列类型
id:int
name:string
city:string
一、DataFrame API基本操作
package com.kinglone.bigscala
import org.apache.spark.sql.SparkSession
/**
* DataFrame API基本操作
*/
object DataFrameApp {
def main(args: Array[String]) {
val spark = SparkSession.builder().appName("DataFrameApp").master("local[2]").getOrCreate()
// 将json文件加载成一个dataframe
val peopleDF = spark.read.format("json").load("file:///Users/rocky/data/people.json")
// 输出dataframe对应的schema信息
peopleDF.printSchema()
// 输出数据集的前20条记录
peopleDF.show()
//查询某列所有的数据: select name from table
peopleDF.select("name").show()
// 查询某几列所有的数据,并对列进行计算: select name, age+10 as age2 from table
peopleDF.select(peopleDF.col("name"), (peopleDF.col("age") + 10).as("age2")).show()
//根据某一列的值进行过滤: select * from table where age>19
peopleDF.filter(peopleDF.col("age") > 19).show()
//根据某一列进行分组,然后再进行聚合操作: select age,count(1) from table group by age
peopleDF.groupBy("age").count().show()
spark.stop()
}
}
二、DataFrame API 操作案例实战
学生信息统计案例
数据格式:
统计代码:
package com.kinglone.bigscala
import org.apache.spark.sql.SparkSession
/**
* DataFrame中的操作操作
*/
object DataFrameCase {
def main(args: Array[String]) {
val spark = SparkSession.builder().appName("DataFrameRDDApp").master("local[2]").getOrCreate()
// RDD ==> DataFrame
val rdd = spark.sparkContext.textFile("file:///Users/rocky/data/student.data")
//注意:需要导入隐式转换
import spark.implicits._
val studentDF = rdd.map(_.split("\\|")).map(line => Student(line(0).toInt, line(1), line(2), line(3))).toDF()
//---------------show默认只显示前20条
studentDF.show 图一
studentDF.show(30) ## 指定显示条数
studentDF.show(30, false) ## 指定条数以及不截取数据 图二
studentDF.take(10) ##前10条记录
studentDF.first() # 返回第一条记录
studentDF.head(3)
studentDF.select("email").show(30,false) ## 指定查询列
studentDF.filter("name=''").show
studentDF.filter("name='' OR name='NULL'").show
//name以M开头的人
studentDF.filter("SUBSTR(name,0,1)='M'").show
studentDF.sort(studentDF("name")).show
studentDF.sort(studentDF("name").desc).show
studentDF.sort("name","id").show
studentDF.sort(studentDF("name").asc, studentDF("id").desc).show # 按name升序 ,id降序
studentDF.select(studentDF("name").as("student_name")).show ##改别名
val studentDF2 = rdd.map(_.split("\\|")).map(line => Student(line(0).toInt, line(1), line(2), line(3))).toDF()
// join 图三
studentDF.join(studentDF2, studentDF.col("id") === studentDF2.col("id")).show
spark.stop()
}
case class Student(id: Int, name: String, phone: String, email: String)
}
图一:
图二:
图三:
通过脚本执行上面的代码比较方便查看结果
./spark-shell --master local[2] --jars /opt/mysql-connector-java-5.1.22-bin.jar
三、Dataset API 操作
数据格式:
代码:
package com.kinglone.bigscala
import org.apache.spark.sql.SparkSession
/**
* Dataset操作
*/
object DatasetApp {
def main(args: Array[String]) {
val spark = SparkSession.builder().appName("DatasetApp")
.master("local[2]").getOrCreate()
//注意:需要导入隐式转换
import spark.implicits._
val path = "file:///Users/rocky/data/sales.csv"
//spark如何解析csv文件? 解析头部
val df = spark.read.option("header","true").option("inferSchema","true").csv(path)
df.show ###图一
// DataFrame 转换成 Dataset
val ds = df.as[Sales]
ds.map(line => line.itemId).show
spark.sql("seletc name from person").show
//df.seletc("name")
df.select("nname") ## 假如DataFrame 字母写错编译不报错,执行时报错
//假如Dataset 写错字母,编译时就报错
ds.map(line => line.itemId)
spark.stop()
}
case class Sales(transactionId:Int,customerId:Int,itemId:Int,amountPaid:Double)
}
图一:
总结:
DataFrame 是强类型,假如DataFrame 字母写错编译不报错,执行时报错
Dataset是弱类型,假如Dataset 写错字母,编译时就报错
三、DataFrame和RDD的互操作
DataFrame和RDD的互操作 的两种方式
1)反射方式:cass class 前提:事先需要知道字段,字段类型
2)编程方式:Row 如果第一种情况不满足(事先不知道列)
3)选型:优先考虑第一种方式
/**
* DataFrame和RDD的互操作
*/
object DataFrameRDDApp {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().appName("DataFrameRDDApp").master("local[2]").getOrCreate()
//1.反射的方式
//inferReflection(spark)
//2.编程的方式
program(spark)
spark.close()
}
def program(spark: SparkSession): Unit = {
// RDD ==> DataFrame
val rdd = spark.sparkContext.textFile("file:///D://test/infos.txt")
//转换成Row
val infoRDD = rdd.map(_.split(",")).map(line => Row(line(0).toInt, line(1), line(2).toInt))
//指定Row里的数据结构
val structType = StructType(Array(StructField("id", IntegerType, true),
StructField("name", StringType, true),
StructField("age", IntegerType, true)))
val infoDF = spark.createDataFrame(infoRDD,structType)
infoDF.printSchema()
infoDF.show()
//通过df的api进行操作
infoDF.filter(infoDF.col("age") > 30).show
//通过sql的方式进行操作
infoDF.createOrReplaceTempView("infos")
spark.sql("select * from infos where age > 30").show()
}
def inferReflection(spark: SparkSession) = {
// RDD ==> DataFrame
val rdd = spark.sparkContext.textFile("file:///D://test/infos.txt")
//注意:需要导入隐式转换
import spark.implicits._
//转换成DataFrame
val infoDF = rdd.map(_.split(",")).map(line => Info(line(0).toInt, line(1), line(2).toInt)).toDF()
infoDF.show()
//查询年龄大于30的
infoDF.filter(infoDF.col("age") > 30).show
//将DataFrame转换成一张表来查询
infoDF.createOrReplaceTempView("infos")
spark.sql("select * from infos where age > 30").show()
}
//定义一个类
case class Info(id: Int, name: String, age: Int)
}
数据格式: