spark dataframe–基础函数和Action函数
基础函数
- 说明
基础函数主要包括对dataframe的行列元数据的获取和操作函数,数据集的转换函数等。
测试的数据集如下:
$ hadoop fs -cat /user/zxh/csvdata/csvdata
id,name,subject,score
1,n1,s1,10
2,n2,s2,20
3,n3,s3,30
3,n3,s1,20
4,n4,s2,40
5,n5,s3,50
6,n6,s1,60
7,n6,s2,40
8,n8,s3,90
8,n9,s1,30
9,n9,s1,20
9,n9,s2,70
通过以下函数获取数据dataframe
import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder().appName("Spark SQL basic example").config("spark.some.config.option", "some-value").getOrCreate()
import spark.implicits._
val df = spark.read.format("csv").option("header", true).load("/user/zxh/csvdata/csvdata")
df.show()
columns
功能说明
返回所有列的列名,并按字符串数组返回。函数原型
def columns: Array[String]
- 使用例子
scala> df.columns
res1: Array[String] = Array(id, name, subject, score)
dtypes
功能说明
按元组的方式返回列名和该列的类型。函数原型
def dtypes: Array[(String, String)]
- 使用例子
scala> df.dtypes
res3: Array[(String, String)] = Array((id,StringType), (name,StringType), (subject,StringType), (score,StringType))
inputFiles
功能
返回该df对应的数据源,也就是对应的hdfs文件。
注意:返回的可能是多个文件,所以返回的是一个字符串数组。函数原型
def inputFiles: Array[String]
- 例子1
scala> df2.inputFiles
res5: Array[String] = Array(hdfs://hadoop.td.com/user/zxh/csvdata/csvdata)
printSchema
功能
打印出dataframe的表结构。
注意:该函数返回的是Unit,只是打印而不是返回。原型
def printSchema(): Unit
- 例子1
scala> df.printSchema
root
|-- id: string (nullable = true)
|-- name: string (nullable = true)
|-- subject: string (nullable = true)
|-- score: string (nullable = true)
rdd
功能
把dataframe转换成rdd。
注意:该函数返回的是一个MapPartitionsRDD原型
lazy val rdd: RDD[T]
- 例子1
scala> df.rdd
res8: org.apache.spark.rdd.RDD[org.apache.spark.sql.Row] = MapPartitionsRDD[13] at rdd at <console>:32
schema
函数功能
按StructType的格式打印出该df的表结构。函数原型
def schema: StructType
- 例子1
scala> df.schema
res9: org.apache.spark.sql.types.StructType = StructType(StructField(id,StringType,true), StructField(name,StringType,true), StructField(subject,StringType,true), StructField(score,StringType,true))
scala> df.schema.foreach(println)
StructField(id,StringType,true)
StructField(name,StringType,true)
StructField(subject,StringType,true)
StructField(score,StringType,true)
write
函数功能
把dataframe进行持久化。
注意:该函数可以指定持久化的格式,指定持久化驱动比如:jdbc,设置各种选项。函数原型
def write: DataFrameWriter[T]
注意:该函数返回的是一个DataFrameWriter类,该类提供了持久化的各种选项和参数设置。
该类的函数详细描述,请查看:这里
- 例子1:按csv格式把dataframe写入hdfs目录
scala> import org.apache.spark.sql._
import org.apache.spark.sql._
scala> df.write.format("csv").option("header", true).mode(SaveMode.Overwrite).save("/user/zxh/writedata/")
保存的文件如下:
$ hadoop fs -cat /user/zxh/writedata/*
id,name,subject,score
1,n1,s1,10
2,n2,s2,20
3,n3,s3,30
3,n3,s1,20
4,n4,s2,40
5,n5,s3,50
6,n6,s1,60
7,n6,s2,40
8,n8,s3,90
8,n9,s1,30
9,n9,s1,20
9,n9,s2,70
注意:mode中的参数有以下几个:
SaveMode.Overwrite: overwrite the existing data.
SaveMode.Append: append the data.
SaveMode.Ignore: ignore the operation (i.e. no-op).
SaveMode.ErrorIfExists: default option, throw an exception at runtime.
- 例子2 : 按csv格式写入,保留列名头,并指定分隔符
df.write
.format("csv")
.option("header", "true")
.option("delimiter",<your delimiter>)
.save(output)
- 例子3: 按parquet格式写入
例如按以下分区和模式写入s3或hdfs目录。
df.write.partitionBy("Date", "category").mode(SaveMode.Append).parquet("s3://bucket/save/path")
或
df.write.partitionBy("eventDate", "category").mode(SaveMode.Overwrite).parquet("/user/zxh/writedata/");
// 实战例子
df.write.partitionBy("subject").mode(SaveMode.Overwrite).parquet("/user/zxh/writedata/");
$ hadoop fs -lsr /user/zxh/writedata/
lsr: DEPRECATED: Please use 'ls -R' instead.
-rw-r--r-- 3 hadoop supergroup 0 2017-12-06 11:39 /user/zxh/writedata/_SUCCESS
drwxr-xr-x - hadoop supergroup 0 2017-12-06 11:39 /user/zxh/writedata/subject=s1
-rw-r--r-- 3 hadoop supergroup 763 2017-12-06 11:39 /user/zxh/writedata/subject=s1/part-00000-f87ae8ca-3cf8-48c1-a911-cdb10b66f09f.snappy.parquet
drwxr-xr-x - hadoop supergroup 0 2017-12-06 11:39 /user/zxh/writedata/subject=s2
-rw-r--r-- 3 hadoop supergroup 732 2017-12-06 11:39 /user/zxh/writedata/subject=s2/part-00000-f87ae8ca-3cf8-48c1-a911-cdb10b66f09f.snappy.parquet
drwxr-xr-x - hadoop supergroup 0 2017-12-06 11:39 /user/zxh/writedata/subject=s3
-rw-r--r-- 3 hadoop supergroup 701 2017-12-06 11:39 /user/zxh/writedata/subject=s3/part-00000-f87ae8ca-3cf8-48c1-a911-cdb10b66f09f.snappy.parquet
- 例子4
把dataframe写入到一个表中。
df.write().mode(SaveMode.Ignore).format("csv").saveAsTable("myTableName")
Action函数
说明:action函数会触发计算并返回结果。Action函数是分布式函数,在单机版的spark中可能打印不出内容。
而且action函数很多情况下是返回Unit,因为在很多时候这些函数是数据处理的最后一步。
本节使用的数据如下:
$ hadoop fs -cat /user/zxh/csvdata/csvdata
id,name,subject,score
1,n1,s1,10
2,n2,s2,20
3,n3,s3,30
3,n3,s1,20
4,n4,s2,40
5,n5,s3,50
6,n6,s1,60
7,n6,s2,40
8,n8,s3,90
8,n9,s1,30
9,n9,s1,20
9,n9,s2,70
count
功能
返回dataframe的列数。函数原型
def count(): Long
- 例子
scala> df.count()
res12: Long = 12
- 函数实现
def count(): Long = withCallback("count", groupBy().count()) {
df => df.collect(needCallback = false).head.getLong(0)
}
可见:count()是通过collect()函数来实现的。
foreachPartition
函数功能
遍历dataframe的分区,并执行遍历的函数。函数原型
def foreachPartition(f: (Iterator[T]) => Unit): Unit
- 例子1
df.foreachPartition(r=>println(r))
注意:单机版的spark能够看到输出,否则可能看不到输出。
head 和 first
函数功能
从df取一行。函数原型和实现
def first(): T = head()
def head(): T = head(1).head
// head(n)的实现
def head(n: Int): Array[T] = withTypedCallback("head", limit(n)) { df =>
df.collect(needCallback = false)
}
注意:这两个函数都会把数据加载到driver端的内存中。若数据量太大,可能会出现driver端的内存溢出。
takeAsList
函数功能
返回dataframe的前n行,其内容按list的方式返回。函数原型
def takeAsList(n: Int): List[T]
- 例子1
scala> df.takeAsList(3)
res2: java.util.List[org.apache.spark.sql.Row] = [[1,n1,s1,10], [2,n2,s2,20], [3,n3,s3,30]]