DateFrame&Dataset

ぃ、小莉子 提交于 2019-12-06 16:20:59

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!