spark编程基础(三)-- Spark SQL

Spark SQL

DataFrame与RDD的区别

  • DataFrame的推出,让Spark具备了处理大规模结构化数据的能力,不仅比原有的RDD转化方式更加简单易用,而且获得了更高的计算性能。
  • Spark能够轻松实现从MySQL到DataFrame的转化,并且支持SQL查询
  • RDD是分布式的Java对象的集合,但是,对象内部结构对于RDD而言却是不可知的。
  • DataFrame是一种以RDD为基础的分布式数据集,提供了详细的结构信息。

DataFrame的创建

SparkSession实现了SQLContext及HiveContext的所有功能,支持从不同的数据源加载数据,并把数据转换成DataFrame,并且支持把DataFrame转换成SQLContext自身中的表,然后使用SQL语句来操作数据。SparkSession亦提供了HiveQL以及其他依赖于Hive的功能的支持。

import spark.implicts._ 支持RDDs转换为DataFrmaes及后续SQL操作,用于Scala中,

//以下两种命令在scala中可正确执行,但在pyspark中返回错误

df.select(df("name"), df("age")+1).show()
df.filter(df("age") > 20).show

pyspark中的命令:
df.select(df["name"], df["age"]+1).show()
df.filter(df["age"] > 20).show

理解:在pyspark中指明某一列如“age”,需使用df.age或df[“age”],而在scala中需使用df(“age”)

 df.select(df("name").as("username"),df("age")).show()

pyspark中的命令:
1. as变为alias
 df.select(df["name"].alias("username"), df.age).show() 
2. 通过临时表,执行sql命令
>>> df.createOrReplaceTempView("people")
>>> sqlDF = spark.sql("SELECT name AS username , age FROM people")
>>> sqlDF.show()
该结果即sqlDF返回的是DataFrame

利用反射机制推断RDD模式(预先定义结构)

优点:代码简洁
缺点:需已知原数据

  • 在利用反射机制推断RDD模式时,需要首先定义一个case class
  • 必须注册一个临时表,才能进行sql语句查询
case class Person(name: String, age: Long)
val peopleDF = spark.sparkContext.textFile("file:///user/local/spark/examples/src/main/respirces/people.txt").map(_.spilt(",").map(attributes => Person(attributes(0),attributes(1).trim.toint)).toDF()

val personsRDD = spark.sql("select name,age from people where age > 20")
personsRDD.map(t => "Name:" + t(0) + "age:" + t(1)).show()

利用编程方式定义RDD模式(无法预先定义结构)

优点:无需提前获取元数据,可在程序在运行中获取元数据。
缺点:代码复杂
types支持生成关系模式的对象或变量,Row支持将每一行数据生成一个对象

import org.apache.spark.sql.types._
import org.apache.spark.sql.Row
val schemaString = "name age"
val fields = schemaString.split(" ").map(fieldName => StructField(fieldName, StringType, nullable=true)) //将结构字符串转换为数组,再将其转换为StructField对象。
val schema = StructType(fields) //schema描述了模式信息,模式中包含name和age两个字段
val rowRDD = peopleRDD.map(_.split(",").map(attriutes => Row(attributes(0),attributes(1).trim)) //对peopleRDD这个RDD中的每一行元素都进行解析
val peopleDF = spark.createDataFrame(rowRDD,schema)

将RDD保存为文件

val peopleDF = spark.read.format("json").load("file:///usr/local/spark/examples/main/resources/people.json")
方法一:peopleDF.select("name","age").write.format("file:///usr/local/spark/mycode/newpeople.csv")
方法二:
df.rdd.saveAsTextFile("file:///usr/local/spark/newpeople.txt")

读写Parquet

dfx想进行sql语句查询,必须首先创建临时表

val parquetFileDF = spark.read.parquet('file:///usr/local/spark/examples/src/main/resources/users.parquet")
peopleDF.write.qarquet("file:///usr/local/spark/mycode/users.qarquet")

通过JDBC连接数据库

1. 读数据
val jdbcDF = spark.read.format("jdbc").option("url","jdbc://localhost:3306/spark").option("driver","com.mysql.jdbc.Driver").option("dbtable","student").option("user","root").option("password","hadoop").load()
jdbcDF.show()

2. 写数据
import java.util.Properties
import org.apache.spark.sql.types._
import org.apache.spark.sql.Row

val studentRDD = spark.sparkContext.parallelize(Array("3 Rongcheng M 25","4 Guanhua M 25")).map(_.split(" ")) //将数组生成RDD,包含两个元素,每一行为一个元素
val schema = StructType(List(StructField("id",IntergerType,true),StructField("name",StringType,true),StructField("gender",StringType,true),StructField("age",IntergerType,true)))

val rowRDD = studentRDD.map(p => Row(p(0)).toint,p(1).trim,p(2).trim,p(3).toint))//将数组生成ROW对象
val studentDF = spark.createDataFrame(rowRDD,schema)

//创建一个prop变量用来保存JDBC连接参数
val prop = new Properties()
prop.put("user","root")
prop.put("password","hadoop")
prop.put("driver","com.mysql.jdbc.Driver"))

//下面就可以连接数据库,采用append模式,表示追加纪录到数据库spark的student表中
studentDF.write.mode("append").jdbc("jdbc:mysql://localhost:3306/spark","spark.student",prop)
发布了21 篇原创文章 · 获赞 0 · 访问量 395

猜你喜欢

转载自blog.csdn.net/leemusk/article/details/103496598
今日推荐