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)