DateFrame&Dataset
DateFrame产生背景
DateFrame不是Spark SQL提出的,早期是在R、Pandas语言就已经有了。
Spark RDD API 和 MapReduce API
给大数据生态圈提供基于通用语言(Java、Python、Scala等)的,并且简单易用的API。
Spark处理代码量很少
R/Pandas语言
局限性非常强
只支持单机处理
DateFrame概述
DataSet是一个分部式数据集
DataFrame是一个DataSet,是以列(列名、列的类型、列值)的形式构成的分布式数据集,按照列赋予不同的名称。
可以理解为一关系数据库的一张表。
为查询、过滤、聚合和其他处理提供了一些抽象
在R和Pandas是用作单机处理小数据,它把这些经验作用到处理大数据分布式平台上。
Spark1.3之前交SchemaRDD,1.3之后改名为DataFrame
DateFrame和RDD的对比
RDD:
java/scala运行在jvm
python运行在 Python Runtime
DataFrame
java/scala/python转换成逻辑计划Logic Plant
DataFrame基本API操作
这里使用的是本地文件,文件是之前使用过的spark路径下的数据,从服务器路径
/home/hadoop/app/spark-2.2.0-bin-hadoop2.6/examples/src/main/resources/people.json下载到了Windows本地D:\data\people.json
代码如下
package com.yy.spark
import org.apache.spark.sql.SparkSession
/**
* DataFrame基本API操作
*/
object DataFrameApp extends App {
val spark = SparkSession.builder().appName("SparkSessionApp").master("local[2]").getOrCreate()
//将json文件加载成一个dataframe
val peopleDF = spark.read.format("json").load("file:///D:\\data\\people.json")
//输出dataframe对于的schema信息
peopleDF.printSchema()
//输出数据集,默认前20条,显示其他条数可以show(100)这样写
peopleDF.show()
//查询某几列所有数据:select name from people
peopleDF.select("name","age").show()
//查询某几列所有数据,并对某列进行计算:select name,age+10 from people
peopleDF.select(peopleDF.col("name"), (peopleDF.col("age") + 10).as("age2")).show()
//根据某一列的值进行过滤:select * from people where age>19
peopleDF.filter(peopleDF.col("age") > 19).show()
//根据某一列进行分组,然后进行聚合操作 select age,count(1) from people group by age
peopleDF.groupBy("age").count().show()
spark.stop()
}执行异常处理
如果windows执行报错
java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.
报错的原因是开发环境在Windows上,但Windows上并没有搭建Hadoop环境,所以配置HADOOP_HOME就可以了。
下载hadoop-common-2.6.0-bin-master.zip,忘了之前在哪下的了,下面是我云盘分享的文件
链接:https://pan.baidu.com/s/1gMByRM7ojXvBnITeVJMVOg
提取码:bgdb
把解压后的的文件放到Windows任意的目录下,我这里是放到了C:\development目录下
然后配置环境变量
系统变量 -> 新建
变量名:HADOOP_HOME
变量值:C:\development\hadoop-common-2.6.0-bin-master
Path添加
%HADOOP_HOME%\bin
DataFrame与RDD互操作的两种方式
1)反射
case class
前提:事先需要知道你的字段和字段类型
2)编程
Row
前提:如果第一种情况不能满足需求,实现不知道数据的列
建议优先考虑第一种
代码如下
这里读取的是包含ID、姓名、年龄的txt文件,文本每列用“,”隔开
package com.yy.spark
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
import org.apache.spark.sql.{Row, SparkSession}
/**
* DataFrame和RDD的互操作
*/
object DataFrameRDDApp extends App {
val spark = SparkSession.builder().appName("DataFrameRDDApp").master("local[2]").getOrCreate()
inferReflection(spark)
program(spark)
spark.stop()
//第一种方式 case class
def inferReflection(spark: SparkSession){
//将RDD转换为DataFrame
val rdd = spark.sparkContext.textFile("file:///D:\\data\\infos.txt")
//需要导入隐式转换
import spark.implicits._
val infoDF = rdd.map(_.split(",")).map(line => Info(line(0).toInt, line(1), line(2).toInt)).toDF()
infoDF.show()
infoDF.filter(infoDF.col("age") > 20).show()
//通过创建临时表,用SQL的方式操作
infoDF.createOrReplaceTempView("infos")
spark.sql("select * from infos where age < 20").show()
}
//第二种方式 Row 数据字段未知的情况下
def program(spark: SparkSession): Unit ={
//将RDD转换为DataFrame
val rdd = spark.sparkContext.textFile("file:///D:\\data\\infos.txt")
val infoRDD = rdd.map(_.split(",")).map(line => Row(line(0).toInt, line(1), line(2).toInt))
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()
}
}
case class Info(id: Int, name: String, age: Int)
DataFrame API操作案例
这里读取的是包含ID、省名称、省编码的CSV文件
package com.yy.spark
import org.apache.spark.sql.SparkSession
object DataFrameCaseApp extends App {
val spark = SparkSession.builder().appName("DataFrameCaseApp").master("local[2]").getOrCreate()
//将RDD转换为DataFrame
val rdd = spark.sparkContext.textFile("file:///D:\\data\\province.csv")
import spark.implicits._
val provinceDF = rdd.map(_.split(",")).map(line => Province(line(0).toInt, line(1), line(2))).toDF()
//默认显示20条
provinceDF.show()
//显示50条
provinceDF.show(50)
//默认数据过长时显示...,通过指定false可以全显示
provinceDF.show(50, false)
//显示前10条
provinceDF.take(10).foreach(println)
//显示第一行
provinceDF.first()
//显示前3条
provinceDF.head(3).foreach(println)
//显示指定列
provinceDF.select("provinceName").show()
//过滤
provinceDF.filter("provinceName='北京市'").show()
provinceDF.filter("SUBSTR(provinceName,0,1)='河'").show()
//排序
provinceDF.sort("id").show()
provinceDF.sort(provinceDF("id").desc).show()
provinceDF.sort(provinceDF("id").desc, provinceDF("provinceNo").asc).show()
//字段起别名
provinceDF.select(provinceDF("provinceName").as("prov_name")).show()
//join操作,默认内连接
val provinceDF2 = rdd.map(_.split(",")).map(line => Province(line(0).toInt, line(1), line(2))).toDF()
provinceDF.join(provinceDF2, provinceDF.col("id") === provinceDF2.col("id")).show()
spark.stop()
}
case class Province(id: Int, provinceName: String, provinceNo: String)Dataset概述及使用
Dataset概述
Dataset是一个分布式数据集,在Spark 1.6之后添加进来的。
提供RDD的好处,包括强类型,支持lambda表达式。
提供了Spark SQL优化的执行引擎的优点。
DataFrame能用的大部分在Dataset中也可以使用。
Dataset可以在Scala和Java中使用,Python暂时不支持。
在Scala API中,DataFrame可以等同于是一种简单的Dataset[Row]
Dataset使用
简单使用,代码如下
这里读取的是包含ID、省名称、省编码的CSV文件
package com.yy.spark
import org.apache.spark.sql.SparkSession
/**
* Dataset操作
*/
object DatasetApp extends App {
val spark = SparkSession.builder().appName("DatasetApp").master("local[2]").getOrCreate()
//导入隐式转换
import spark.implicits._
//解析csv文件
val df = spark.read.option("header","true").option("interSchema",true).csv("file:///D:\\data\\province2.csv")
df.show()
val ds = df.as[Province2]
ds.map(line => line.provinceName).show()
spark.stop()
}
case class Province2(id:String, provinceName:String, provinceNo:String)

浙公网安备 33010602011771号