spark获取dataframe的三种方法
将RDD转为dataframe
1.方法一:使用反射的方式去推断RDD的schema信息,这种方法的前提是你已经知道了schema。具体的操作代码如下
import org.apache.spark.sql.SparkSession
object DFApp {
def main(args: Array[String]): Unit = {
val sparkSession=SparkSession
.builder()
.appName("DFApp")
.master("local[2]")
.getOrCreate()
inferReflection(sparkSession)
sparkSession.stop()
}
//定义一个反射函数
def inferReflection(sparkSession:SparkSession)={
//创建一个RDD
val info=sparkSession.sparkContext.textFile("file:///C:\\Users\\HJ\\Desktop/secondhomework.txt")
import sparkSession.implicits._
//要转为dataframe,必须要导入隐式转换
val df=info.map(_.split("\t")).map(x=>Info(x(0),x(2).toLong)).toDF()
//x(0),x(2)要和Info(domin: String, responseSize: Long)里面的字段类型对应上,亲测不对应也会报错
//把rdd转为dataframe之后,你可以使用dataframe的APi进行操作,也可以使用sql(先注册成一张表)
df.createOrReplaceTempView("info1")//把dataframe注册成一个临时表叫做info1
// sparkSession.sql("select domin,sum(responseSize)as a from info1 group by domin").show()
val infoDF=sparkSession.sql("select domin,sum(responseSize)as a from info1 group by domin")
//sparkSession.sql的返回值是dataframe,dataframe也有map操作,dataframe里面的函数基本和RDD一样
//infoDF.map(x=>"name: "+x(0)).show()//对dataframe做map操作后返回的是dataset,通过控制台可以看到其返回的具体类型。1.6版本的时候返回值还是RDD
//infoDF.map(x=>x(0)).show()(这样写就会报错)
//infoDF.rdd.map(x=>x(0)).collect().foreach(println)//如果想这样使用map,得通过rdd把它转为RDD
infoDF.map(x=>x.get(0)).collect().foreach(println)//这种也不行
//原因是dataframe通过map后变为dataset的类型,dataset是强类型,所以会报错,
// 因为字段已经通过caseclass提前规定了类型了,所以只需要把类型强转为caseclass提前规定的类型或者转为RDD就可以解决报错 ,如下将dataframe转为rdd或者获取domin字段并将其转为String类型就可以解决报错
//infoDF.rdd.map(x=>x.get(0)).collect().foreach(println)//这样可以打印出第一个字段的值
infoDF.rdd.map(x=>x.getAs[String]("domin")).collect().foreach(println)
//这样可以得到domin字段的值
//infoDF.rdd.map(x=>x.getAs[String]("domin")).collect().foreach(println)
//这样可以得到domin字段的值
}
}
case class Info(domin: String, responseSize: Long)//该类被定义用来做反射类,定义表的schema信息
2.方法二:通过编程指定schema
据官网介绍,表结构提前不知道的情况下,就可以通过编程指定schema,将rdd转为dataframe,具体的操作diamante如下。
该方法一般有三个步骤:
a. Create an RDD of Rows from the original RDD
b. Create the schema represented by a StructType matching the structure of Rows in the RDD created in Step 1
c. Apply the schema to the RDD of Rows via createDataFrame method provided by SparkSession
import org.apache.spark.sql.types._
import org.apache.spark.sql.{Row, SparkSession}
object DFApp1 {
def main(args: Array[String]): Unit = {
val sparkSession=SparkSession
.builder()
.appName("DFApp1")
.master("local[2]")
.getOrCreate()
programmatically(sparkSession)
sparkSession.stop()
}
def programmatically(sparkSession: SparkSession)={
val info=sparkSession.sparkContext.textFile("file:///C:\\Users\\HJ\\Desktop/secondhomework.txt")
val rdd =info.map(_.split("\t")).map(x=>Row(x(0),x(2).toLong))
//步骤一:创建一个RDD[Row]类型从原始的RDD转成的
val struct=
StructType(Array(
StructField("domin", StringType,true),
StructField("responseSize", LongType, false)
))
//步骤二:创建schema
val df=sparkSession.createDataFrame(rdd,struct)
//步骤三:把schema作用到RDD[Row]上面。createDataFrame(RDD[Row],StructType)
df.show()
直接读取hive表,将读入的数据直接转为dataframe
具体的操作代码如下:
import org.apache.spark.sql.SparkSession
object DFApp2 {
def main(args: Array[String]): Unit = {
val sparkSession=SparkSession.builder()
.appName("DFApp2 ")
.enableHiveSupport()//使用到hive一定要开启这个,idea要想连接hive得在pom中加上hive
.master("local[2]")
.getOrCreate()
//val g6= sparkSession.table("product_info")//Unable to instantiate SparkSession with Hive support because Hive classes are not found 一开始报了这个错误,因为enableHiveSupport()没有加上
//括号里面直接是表,然后读出表的内容作为dataframe
val gg=sparkSession.sql("show databases")//括号里面是具体的操作表的语句
gg.show
sparkSession.stop()//具体的连接hive可以参考我之前的文章,spark通过idea连接hive
}
}
spark通过外部数据源直接获取后转为dataframe
根据官网介绍,spark可以直接读取多种格式的数据转为dataframe。操作代码如下:
import org.apache.spark.sql.{SaveMode, SparkSession}
object DataSourceAPIApp {
def main(args: Array[String]): Unit = {
val sparkSession=SparkSession.builder()
.master("local[2]")
.enableHiveSupport()
.appName("DataSourceAPIApp")
.getOrCreate()
//标准读写法,通过scala控制台演示
//sparkSession.read.format("text").load("hdfs://192.168.2.65:9000/data/users.txt").show()
//load支持传一个或者多个路径,这样读出的文本内容都放在一个value字段下面
//format里面包括有text/json/parquet/jdbc..
//简化读写法,通过scala控制台演示sparkSession用spark代替
//sparkSession.read.text().show
//text()也支持传一个或者多个路径
//这种写法默认只能读parquet格式,其他格式需要在conf中设置
//例如:[hadoop@hadoop001 bin]$./spark-shell --conf spark.sql.sources.default="text"/text
//sparkSession.read.load()
//其他读写法
//sparkSession.read.format("text").option("path","").load().show
val df=sparkSession.read.format("parquet").load("hdfs://192.168.2.65:9000/data/users.parquet")
//读jdbc文件
//以读mysql为例
/* val jdbcDF=sparkSession.read.format("jdbc")
.option("url","jdbc:mysql://192.168.2.65:3306/")
.option("dbtable","ruoze_d5.tbls")
//.option("dbtable","ruozedata5.city_info")//前面是数据库,后面是表,可以读出来
//写两个option一下读两个表是无法成功的,一次只能读一个表
.option("user","root")
.option("password","******")
.load()
sparkSession.stop()
}
}
spark将dataframe写出去
具体操作代码如下:
import org.apache.spark.sql.{SaveMode, SparkSession}
object DataSourceAPIApp {
def main(args: Array[String]): Unit = {
val sparkSession=SparkSession.builder()
.master("local[2]")
.enableHiveSupport()
.appName("DataSourceAPIApp")
.getOrCreate()
val df=sparkSession.read.format("parquet").load("hdfs://192.168.2.65:9000/data/users.parquet")
// df.write.format("json").save("")
//输出保存路径文件夹已经存在使用不同的保存格式
//mode(SaveMode.Overwrite)需要导包,里面是SaveMode类型
// df.write.format("json").mode(SaveMode.Overwrite).save("hdfs://192.168.2.65:9000/data/jsonfile")
//指定到文件夹
//mode("")不需要导包,里面是字符串类型
// df.write.format("text").mode("").save()
//把读进来的文件存为表
// df.select("name").write.saveAsTable("")
//df.write.format("parquet")
// .option("path","/user/hive/warehouse")
//做了这个操作后,/user/hive/warehouse下面只有一个TXT文件,也就是说之前的内容
// 全部被重写了,也就意味着全部丢失了
// .option("path","/user/hive/warehouse/ruoze_spark_parquett1")
// .mode("overwrite")
// .saveAsTable("ruoze_spark_parquett1")
//把表名也写到内部表的存储路径下,这样在hive里面就能够查到表了。我认为是
// 把内容写进到表里面去的原因
df.write.format("orc")
.option("path","/user/hive/warehouse/ruoze_spark_orc")
.mode("overwrite")
.saveAsTable("ruoze_spark_orc")
//读的是parquet格式,写到hive表的时候可以是parquet,也可以是其他格式,比如orc格式