Spark SQL是Spark中的一个模块,主要用于进行结构化数据的处理,它提供的最核心的编程抽象,就是DataFrame;
DataFrame,其实是针对数据查询这种应用,提供的一种基于RDD之上的全新概念,但是,其底层还是基于RDD的;
同时,Spark SQL还可以作为分布式的SQL查询引擎,Spark SQL最重要的功能之一,就是从hive中查询数据。
1、DataFrame简介
DataFrame:可以理解为是,以列的形式组织的,分布式的数据集合;它其实和关系型数据库中的表非常类似,但是底层做了很多的优化,DataFrame可以通过很多来源进行构建,包括:结构化的数据文件,Hive中的表,外部的关系型数据库,RDD。
2、Spark SQL初步使用
-
1、SQLContext
要使用Spark SQL,首先就得创建一个SQLContext对象,或者是它的子类的对象,比如HiveContext的对象。#Java版本 SparkConf conf = new SparkConf() .setAppName("DataFrameCreate"); JavaSparkContext sc = new JavaSparkContext(conf); SQLContext sqlContext = new SQLContext(sc); #Scala版本 val conf = new SparkConf() .setAppName("DataFrameCreate") val sc = new SparkContext(conf) val sqlContext = new SQLContext(sc)
2、HiveContext
除了基本的SQLContext以外,还可以使用它的子类——HiveContext。
HiveContext的功能除了包含SQLContext提供的所有功能之外,还包括了额外的专门针对Hive的一些功能:使用HiveSQL语法来编写和执行SQL,使用Hive中的UDF函数,从Hive表中读取数据。
要使用HiveContext,就必须预先安装好Hive,SQLContext支持的数据源,HiveContext也同样支持,对于Spark 1.3.x以上的版本,都推荐使用HiveContext,因为其功能更加丰富和完善。
Spark SQL还支持用spark.sql.dialect参数设置SQL的方言。使用SQLContext的setConf()即可进行设置。对于SQLContext,它只支持“sql”一种方言。对于HiveContext,它默认的方言是“hiveql”。3、创建DataFrame
使用SQLContext,可以从RDD、hive表或者其他数据源,来创建一个DataFrame,下面以Json文件为例:
package cn.spark.study.sql;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
/**
* 使用json文件创建DataFrame
*
*/
public class DataFrameCreate {
public static void main(String[] args) {
SparkConf conf = new SparkConf()
.setAppName("DataFrameCreate");
JavaSparkContext sc = new JavaSparkContext(conf);
SQLContext sqlContext = new SQLContext(sc);
DataFrame df = sqlContext.read().
json("hdfs://hadoop1:9000/students.json");
df.show();
}
}
package cn.spark.study.sql
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
object DataFrameCreate {
def main(args: Array[String]) {
val conf = new SparkConf()
.setAppName("DataFrameCreate")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
val df = sqlContext.read.json("hdfs://hadoop1:9000/students.json")
df.show()
}
}
- 4、DataFrame的常用操作
package cn.spark.study.sql;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
/**
* DataFrame的常用操作
*
*/
public class DataFrameOperation {
public static void main(String[] args) {
// 创建DataFrame
SparkConf conf = new SparkConf()
.setAppName("DataFrameCreate");
JavaSparkContext sc = new JavaSparkContext(conf);
SQLContext sqlContext = new SQLContext(sc);
// 创建出来的DataFrame完全可以理解为一张表
DataFrame df = sqlContext.read()
.json("hdfs://hadoop1:9000/students.json");
// 打印DataFrame中所有的数据(select * from ...)
df.show();
// 打印DataFrame的元数据(Schema)
df.printSchema();
// 查询某列所有的数据
df.select("name").show();
// 查询某几列所有的数据,并对列进行计算
df.select(df.col("name"), df.col("age").plus(1)).show();
// 根据某一列的值进行过滤
df.filter(df.col("age").gt(18)).show();
// 根据某一列进行分组,然后进行聚合
df.groupBy(df.col("age")).count().show();
}
}
package cn.spark.study.sql
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
object DataFrameOperation {
def main(args: Array[String]) {
val conf = new SparkConf()
.setAppName("DataFrameCreate")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
val df = sqlContext.read.json("hdfs://hadoop1:9000/students.json")
df.show()
df.printSchema()
df.select("name").show()
df.select(df("name"), df("age") + 1).show()
df.filter(df("age") > 18).show()
df.groupBy("age").count().show()
}
}
3、load和save操作
对于spark sql的dataframe来说,无论是从什么数据源创建出来的DataFrame,都有一些共同的load和save操作。
load操作,主要是用于加载数据,创建出DataFrame;
save操作,主要是用于将DataFrame中的数据保存到文件中
- 1、通用的load和save操作
package cn.spark.study.sql;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
/**
* 通用的load和save操作
*
*/
public class GenericLoadSave {
public static void main(String[] args) {
SparkConf conf = new SparkConf()
.setAppName("GenericLoadSave");
JavaSparkContext sc = new JavaSparkContext(conf);
SQLContext sqlContext = new SQLContext(sc);
DataFrame usersDF = sqlContext.read().load(
"hdfs://hadoop1:9000/users.parquet");
usersDF.select("name", "favorite_color").write()
.save("hdfs://hadoop1:9000/namesAndFavColors.parquet");
}
}
package cn.spark.study.sql
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
import org.apache.spark.sql.DataFrame
object GenericLoadSave {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName("GenericLoadSave")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
val usersDF = sqlContext.read.load("hdfs://hadoop1:9000/users.parquet")
usersDF.write.save("hdfs://hadoop1:9000/namesAndFavColors_scala")
}
}
- 2、指定数据源类型
我们也可以手动指定用于操作的数据源类型,数据源通常需要使用其全限定名来指定,比如,parquet是org.apache.spark.sql.parquet;
通过这个功能,就可以在不同类型的数据源之间进行转换,比如将json文件中的数据保存到parquet文件中;
默认情况下,如果不指定数据源类型,那么就是parquet。
package cn.spark.study.sql;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
/**
* 手动指定数据源类型
*/
public class ManuallySpecifyOptions {
public static void main(String[] args) {
SparkConf conf = new SparkConf()
.setAppName("ManuallySpecifyOptions");
JavaSparkContext sc = new JavaSparkContext(conf);
SQLContext sqlContext = new SQLContext(sc);
DataFrame peopleDF = sqlContext.read().format("json")
.load("hdfs://hadoop1:9000/people.json");
peopleDF.select("name").write().format("parquet")
.save("hdfs://hadoop1:9000/peopleName_java");
}
}
package cn.spark.study.sql
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
object ManuallySpecifyOptions {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName("ManuallySpecifyOptions")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
val peopleDF = sqlContext.read.format("json").load("hdfs://hadoop1:9000/people.json")
peopleDF.select("name").write.format("parquet").save("hdfs://hadoop1:9000/peopleName_scala")
}
}
-
3、SaveMode
Spark SQL对于save操作,提供了不同的save mode,主要用来处理,当目标位置已经有该数据时,应该如何处理;而且save操作并不会执行锁操作,不是原子的,因此是有一定风险出现脏数据的。
package cn.spark.study.sql;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.SaveMode;
/**
* SaveModel示例
*/
public class SaveModeTest {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
SparkConf conf = new SparkConf()
.setAppName("SaveModeTest");
JavaSparkContext sc = new JavaSparkContext(conf);
SQLContext sqlContext = new SQLContext(sc);
DataFrame peopleDF = sqlContext.read().format("json")
.load("hdfs://spark1:9000/people.json");
peopleDF.save("hdfs://spark1:9000/people_savemode_test", "json", SaveMode.Append);
}
}