Spark SQL概述
Spark SQL 是一个用来处理结构化数据的spark组件。它提供了一个叫做DataFrames的可编程抽象数据模型,并且可被视为一个分布式的SQL查询引擎。
Spark SQL的基础数据模型—–DataFrames
DataFrame是由命名列所组织起来的一个分布式数据集合。你可以把它看成是一个关系型数据库的表。
DataFrame可以通过多种来源创建:结构化数据文件,hive的表,外部数据库,或者RDDsSpark SQL如何使用
首先,利用sqlContext从外部数据源加载数据为DataFrame
然后,利用DataFrame上丰富的api进行查询、转换
DataFrame是一个以命名列方式组织的分布式数据集,等同于关系型数据库中的一个表,也相当于R/Python中的data frames(但是进行了更多的优化)。
DataFrames可以由结构化数据文件转换而来,也可以从Hive中的表得来,以及可以转换自外部数据库或现有的RDD。
DataFrame与生俱来就支持读取最流行的格式,包括JSON文件、Parquet文件和Hive表格。DataFrame还支持从多种类型的文件系统中读取,比如本地文件系统、分布式文件系统(HDFS)以及云存储(S3)。同时,配合JDBC,它还可以读取外部关系型数据库系统。
DataFrames对数据源的支持能力允许应用程序可以轻松地组合来自不同数据源的数据。
比如,以下代码展示了将一个文本数据和mysql数据库join的操作
sqlContext = new SQLContext(sc)
users = sqlContext .jdbc(“jdbc:postgresql:production”, “users”)
logs = sqlContext .load(“/path/to/traffic.log”)
logs.join(users, logs.userId == users.userId, “left_outer”) \
.groupBy(“userId”).agg({“*”: “count”})
与RDD类似,DataFrame也是一个分布式数据容器。
DataFrame更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即schema。
与Hive类似,DataFrame也支持嵌套数据类型(struct、array和map)。从API易用性的角度上 看,DataFrame API提供的是一套高层的关系操作,比函数式的RDD API要更加友好,门槛更低。
由于与R和Pandas的DataFrame类似,Spark DataFrame很好地继承了传统单机数据分析的开发体验。
RDD转换为DF的关键是为RDD数据定义schema,有两种方式:
定义一个caseclass,利用反射机制来推断
手动定义一个schema StructType,套用到RDD上
反射方式示例:
1、从HDFS中加载文件为普通RDD
val lineRDD = sc.textFile(“hdfs://hdp-node-01:9000/person.txt”).map(_.split(” “))
2.定义case class(相当于表的schema)
case class Person(id:Int, name:String, age:Int)
3.将RDD和case class关联
val personRDD = lineRDD.map(x => Person(x(0).toInt, x(1), x(2).toInt))
4.将RDD转换成DataFrame
val personDF = personRDD.toDF
5.对DataFrame进行处理
personDF.show
自定义schema方式,代码如下:
//使用structType定义schema来转换RDD
// val schema = StructType(Array(StructField(“name”,StringType,true),StructField(“age”,StringType,true)))
val schemaString =”name age height weight married”
val schema = StructType(schemaString.split(” “).map(fieldName => StructField(fieldName, StringType, true)))
val rowRdd = peopleRdd.map(p=>Row(p(0),p(1)))
val peopleDF = sqlContext.createDataFrame(rowRdd,schema)*/
加载Json
df = sqlContext.read.json(“examples/src/main/resources/people.json”)
//或者指定类型
df = sqlContext.read.format(“json”).load(“examples/src/main/resources/people.json”)
df.show()
加载parquet
val df = sqlContext.read.parquet(“examples/src/main/resources/users.parquet”)
df = sqlContext.read.format(“parquet”).load(“examples/src/main/resources/people.json”)
甚至,可以直接查询parquet文件
val df = sqlContext.sql(“SELECT * FROM parquet.examples/src/main/resources/users.parquet
“)
1.启动Spark Shell,必须指定mysql连接驱动jar包
/usr/local/spark-1.5.2-bin-hadoop2.6/bin/spark-shell \
–master spark://hdp-node-01:7077 \
–jars /usr/local/spark-1.5.2-bin-hadoop2.6/mysql-connector-java-5.1.35-bin.jar \
–driver-class-path /usr/local/spark-1.5.2-bin-hadoop2.6/mysql-connector-java-5.1.35-bin.jar
2.从mysql中加载数据
val jdbcDF = sqlContext.read.format(“jdbc”).options(Map(“url” -> “jdbc:mysql://192.168.10.1:3306/bigdata”, “driver” -> “com.mysql.jdbc.Driver”, “dbtable” -> “person”, “user” -> “root”, “password” -> “123456”)).load()
3.执行查询
jdbcDF.show()
保存为parquet
df.select(“name”, “favorite_color”).write.save(“namesAndFavColors.parquet”)
df.select(“name”, “age”).write.format(“parquet”).save(“namesAndAges.parquet”)
保存为Json
df.select(“name”, “favorite_color”).write.save(“namesAndFavColors.json”)
df.select(“name”, “age”).write.format(“json”).save(“namesAndAges.parquet”)
保存到jdbc数据库
df.createJDBCTable(“jdbc:mysql://host:port/db”, “t_table”, allowExisting: Boolean)
df.insertIntoJDBC(“jdbc:mysql://host:port/db”, “t_table”, overwrite: Boolean)
DSL(domain-specific language )来自于R语言中的DATAFRAME-API
//查看DataFrame中的内容
personDF.show
//查看DataFrame部分列中的内容
personDF.select(personDF.col(“name”)).show
personDF.select(col(“name”), col(“age”)).show
personDF.select(“name”).show
//打印DataFrame的Schema信息
personDF.printSchema
//查询所有的name和age,并将age+1
personDF.select(col(“id”), col(“name”), col(“age”) + 1).show
personDF.select(personDF(“id”), personDF(“name”), personDF(“age”) + 1).show
//过滤age大于等于18的
personDF.filter(col(“age”) >= 18).show
//按年龄进行分组并统计相同年龄的人数
personDF.groupBy(“age”).count().show()
如果想使用SQL风格的语法,需要将DataFrame注册成表
personDF.registerTempTable(“t_person”)
//查询年龄最大的前两名
sqlContext.sql(“select * from t_person order by age desc limit 2”).show
//显示表的Schema信息
sqlContext.sql(“desc t_person”).show