SparkSQL--基础编程

DataFrame的基础操作

创建一个DataFrame

首先看一下SparkSQL可以接受那些类型:

scala> spark.read.
csv   format   jdbc   json   load   option   options   
orc   parquet   schema   table   text   textFile

注意:

本文中的spark是sparkSession对象默认的名称

然后去spark安装目录下将people.json文件上传至hdfs:

[root@cm1 /]# cd /usr/hdk/spark2/examples/src/main/resources
[root@cm1 resources]# ll
总用量 36
-rw-r--r-- 1 root root  130 7月  13 2017 employees.json
-rw-r--r-- 1 root root  240 7月  13 2017 full_user.avsc
-rw-r--r-- 1 root root 5812 7月  13 2017 kv1.txt
-rw-r--r-- 1 root root   73 7月  13 2017 people.json
-rw-r--r-- 1 root root   32 7月  13 2017 people.txt
-rw-r--r-- 1 root root  185 7月  13 2017 user.avsc
-rw-r--r-- 1 root root  334 7月  13 2017 users.avro
-rw-r--r-- 1 root root  615 7月  13 2017 users.parquet
[root@cm1 resources]# su hdfs
[hdfs@cm1 resources]$ hdfs dfs -put  people.json /
[hdfs@cm1 resources]$ su root
[root@cm1 resources]# spark2-shell --master local[2]

从hdfs读取文件创建一个DataFrame

scala> val df = spark.read.json("/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

scala> df.show()
+----+-------+
| age|   name|
+----+-------+
|null|Michael|
|  30|   Andy|
|  19| Justin|
+----+-------+

创建一个临时表

临时表只在当前SparkSession有效,退出后就失效了。
创建表以后,就可以使用sql语句对表进行操作。

scala> df.createOrReplaceTempView("people")

scala> val sqlDF = spark.sql("SELECT * FROM people")
sqlDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

scala> sqlDF.show
+----+-------+
| age|   name|
+----+-------+
|null|Michael|
|  30|   Andy|
|  19| Justin|
+----+-------+

注意:

什么是SparkSession


SparkSession是Spark最新的SQL查询起始点。
在最开始编写SpqrkSQL程序时需要创建一个变量包含相关配置,最开始是:

sc = SparkContext(conf=conf)
或
hivec = HiveContext(sc)

后来spark对这两个方法进行了封装,就有了SparkSession:

sess = SparkSession.builder \
   .appName("aaa") \  
   .config("spark.driver.extraClassPath", sparkClassPath) \
   .master("local") \
   .enableHiveSupport() \  # sparkSQL 连接 hive 时需要这句
   .getOrCreate()      # builder 方式必须有这句

临时表只在当前SparkSession生效,也就是临时表会随着作业的结束而释放。

创建一个全局表

创建全局表需要使用createGlobalTempView函数,在写SQL语句中需要全路径调用这个表。

scala>  df.createGlobalTempView("people")

scala> spark.sql("SELECT * FROM global_temp.people").show()
+----+-------+
| age|   name|
+----+-------+
|null|Michael|
|  30|   Andy|
|  19| Justin|
+----+-------+

查看DataFrame的Schema信息

scala> df.printSchema
root
 |-- age: long (nullable = true)
 |-- name: string (nullable = true)

数据的提取

  • 查看name列的数据
scala> df.select("name").show()
+-------+
|   name|
+-------+
|Michael|
|   Andy|
| Justin|
+-------+
  • age列的数据+1返回
scala> df.select($"age" + 1).show()
+---------+
|(age + 1)|
+---------+
|     null|
|       31|
|       20|
+---------+
  • 查询age大于21的数据
scala>  df.select($"age" > 21).show()
+----------+
|(age > 21)|
+----------+
|      null|
|      true|
|     false|
+----------+

  • 按照age分组查看
scala> df.groupBy("age").count().show()
+----+-----+
| age|count|
+----+-----+
|  19|    1|
|null|    1|
|  30|    1|
+----+-----+

RDD转换为DateFrame

无论RDD转换为DF还是DS,必须导入一个包spark.implicits._

scala> import spark.implicits._
import spark.implicits._

scala> val peopleRDD = sc.textFile("/people.txt")
peopleRDD: org.apache.spark.rdd.RDD[String] = /people.txt MapPartitionsRDD[4] at textFile at <console>:27

scala> peopleRDD.collect()
res10: Array[String] = Array(Michael, 29, Andy, 30, Justin, 19)

scala> val df = peopleRDD.map{x=>val para = x.split(",");(para(0),para(1).trim.toInt)}.toDF("name","age")
df: org.apache.spark.sql.DataFrame = [name: string, age: int]

scala> df.show()
+-------+---+
|   name|age|
+-------+---+
|Michael| 29|
|   Andy| 30|
| Justin| 19|
+-------+---+

还有一种使用映射类的方式

scala> import spark.implicits._
import spark.implicits._

scala> val peopleRDD = sc.textFile("/people.txt")
peopleRDD: org.apache.spark.rdd.RDD[String] = /people.txt MapPartitionsRDD[1] at textFile at <console>:27

scala> case class People(name:String, age:Int)
defined class People

scala> val df = peopleRDD.map{ x => val para = x.split(",");People(para(0),para(1).trim.toInt)}.toDF
df: org.apache.spark.sql.DataFrame = [name: string, age: int]

scala> df.show()
+-------+---+
|   name|age|
+-------+---+
|Michael| 29|
|   Andy| 30|
| Justin| 19|
+-------+---+

DateFrame转换为RDD

转换成RDD只需要调用一个rdd即可。

scala> val dfRDD = df.rdd
dfRDD: org.apache.spark.rdd.RDD[org.apache.spark.sql.Row] = MapPartitionsRDD[11] at rdd at <console>:33

scala> dfRDD.collect
res13: Array[org.apache.spark.sql.Row] = Array([Michael,29], [Andy,30], [Justin,19])

DataFrame转DataSet

将DF转换为DS需要使用样例类与as方法。

scala> val df = spark.read.json("/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

scala> case class Person(name: String, age: Long)
defined class Person

scala> val ds = df.as[Person]
ds: org.apache.spark.sql.Dataset[Person] = [age: bigint, name: string]

scala> ds.show()
+----+-------+
| age|   name|
+----+-------+
|null|Michael|
|  30|   Andy|
|  19| Justin|
+----+-------+

DataSet的基础操作

创建一个DataSet

DataSet的创建必须基于样例类。

scala> case class Person(name: String, age: Long)
defined class Person

scala> val caseClassDS = Seq(Person("Andy", 32)).toDS()
caseClassDS: org.apache.spark.sql.Dataset[Person] = [name: string, age: bigint]

RDD转换为DataSet

RDD转换为DataSet也需要通过case类属性进行反射。

scala> val peopleRDD = sc.textFile("/people.txt")
peopleRDD: org.apache.spark.rdd.RDD[String] = /people.txt MapPartitionsRDD[10] at textFile at <console>:24

scala> case class Person(name: String, age: Long)
defined class Person

scala> val ds = peopleRDD.map(line => {val para = line.split(",");Person(para(0),para(1).trim.toInt)}).toDS()
ds: org.apache.spark.sql.Dataset[Person] = [name: string, age: bigint]

scala> ds.show()
+-------+---+
|   name|age|
+-------+---+
|Michael| 29|
|   Andy| 30|
| Justin| 19|
+-------+---+

DataSet转换为RDD

scala> val rdd = ds.rdd
rdd: org.apache.spark.rdd.RDD[Person] = MapPartitionsRDD[16] at rdd at <console>:30

scala> rdd.collect
res2: Array[Person] = Array(Person(Michael,29), Person(Andy,30), Person(Justin,19))

DataSet转DataFrame

需要使用方法toDF

scala> val df = ds.toDF
df: org.apache.spark.sql.DataFrame = [name: string, age: bigint]

scala> df.show()
+-------+---+
|   name|age|
+-------+---+
|Michael| 29|
|   Andy| 30|
| Justin| 19|
+-------+---+

RDD、DataFrame、DataSet三者的异同

首先,DS包含DF与RDD,DF与RDD互相独立。

共性

  • RDD、DataFrame、Dataset全都是spark平台下的分布式弹性数据集,为处理超大型数据提供便利
  • 三者都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action如foreach时,三者才会开始遍历运算。
  • 三者都会根据spark的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存溢出。
  • 三者都有partition的概念
  • 三者有许多共同的函数,如filter,排序等
  • 在对DataFrame和Dataset进行操作许多操作都需要import spark.implicits._进行支持
  • DataFrame和Dataset均可使用模式匹配获取各个字段的值和类型

区别

  • RDD
    • RDD一般和spark mlib同时使用
    • RDD不支持sparksql操作
  • DataFrame:
    • 与RDD和Dataset不同,DataFrame每一行的类型固定为Row,每一列的值没法直接访问,只有通过解析才能获取各个字段的值
    • DataFrame与Dataset一般不与spark mlib同时使用
    • DataFrame与Dataset均支持sparksql的操作,比如select,groupby之类,还能注册临时表/视窗,进行sql语句操作
    • DataFrame与Dataset支持一些特别方便的保存方式,比如保存成csv,可以带上表头,这样每一列的字段名一目了然
  • Dataset:
    • Dataset和DataFrame拥有完全相同的成员函数,区别只是每一行的数据类型不同。
    • DataFrame也可以叫Dataset[Row],每一行的类型是Row,不解析,每一行究竟有哪些字段,各个字段又是什么类型都无从得知
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒 暄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值