一、使用 DataFrame 进行编程
1、创建 DataFrame
1.1 通过 Spark 的数据源创建
Spark支持的数据源:
// 读取 json 文件
scala> val df = spark.read.json("/opt/module/spark-local/examples/src/main/resources/employees.json")
df: org.apache.spark.sql.DataFrame = [name: string, salary: bigint]
// 展示结果
scala> df.show
+-------+------+
| name|salary|
+-------+------+
|Michael| 3000|
| Andy| 4500|
| Justin| 3500|
| Berta| 4000|
+-------+------+
1.2 通过已知的 RDD 来创建:通过 RDD 进行转换
1.2.1 RDD 转为 DataFrame
import org.apache.spark.SparkContext
import org.apache.spark.sql.SparkSession
object RDD2DF01 {
def main(args: Array[String]): Unit = {
val sparkWhx: SparkSession = SparkSession.builder().master("local[2]").appName("RDD2DF").getOrCreate()
import sparkWhx.implicits._
val sc: SparkContext = sparkWhx.sparkContext
val rdd = sc.parallelize(("lisi", 10):: ("zs", 20)::Nil)
rdd.toDF("name", "age").show()
sparkWhx.stop()
}
}
打印结果:
+----+---+
|name|age|
+----+---+
|lisi| 10|
| zs| 20|
+----+---+
提供样例类:
import org.apache.spark.SparkContext
import org.apache.spark.sql.SparkSession
case class User(name: String, age: Int)
object RDD2DF01_2 {
def main(args: Array[String]): Unit = {
val sparkWhx: SparkSession = SparkSession.builder().master("local[2]").appName("RDD2DF").getOrCreate()
import sparkWhx.implicits._
val sc: SparkContext = sparkWhx.sparkContext
val rdd = sc.parallelize(Array(User("lisi", 10), User("zs", 20), User("ww", 15)))
// rdd.toDF.show
rdd.toDF("name02", "age02").show
sparkWhx.stop()
}
}
打印结果:
+------+-----+
|name02|age02|
+------+-----+
| lisi| 10|
| zs| 20|
| ww| 15|
+------+-----+
1.2.2 DataFrame 转为 RDD
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
object DF2RDD01 {
def main(args: Array[String]): Unit = {
val sparkWhx: SparkSession = SparkSession.builder().master("local[*]").appName("DF2RDD").getOrCreate()
// 直接从一个scala的集合到df
val df: DataFrame = (1 to 10).toDF("number")
// DataFrame转RDD RDD中存储的一定是Row
val rdd = df.rdd
val rdd1 = rdd.map(row => row.getInt(0))
val result = rdd1.collect.toList
println("result = " + result)
sparkWhx.close()
}
}
打印结果:
result = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
1.3 通过查询一个 Hive 表来创建
2、DataFrame编程
import org.apache.spark.sql.SparkSession
object CreateDF {
def main(args: Array[String]): Unit = {
// 1. 先创建及SparkSession
val spark = SparkSession.builder().appName("CreateDF").master("local[2]").getOrCreate()
// 2. 通过SparkSession创建DF
val df = spark.read.json("c:/users.json")
// 3. 对DF做操作(sql)
// 3.1 创建临时表
df.createOrReplaceTempView("user")
df.cache()
// 3.2 查询临时表
spark.sql(
"""
|select
|name,
|age
|from user
|""".stripMargin).show
// 4. 关闭SparkSession
spark.stop()
}
}
二、使用 DataSet 进行编程
DataSet 和 RDD 类似, 但是DataSet没有使用 Java 序列化或者 Kryo序列化, 而是使用一种专门的编码器去序列化对象, 然后在网络上处理或者传输.
虽然编码器和标准序列化都负责将对象转换成字节,但编码器是动态生成的代码,使用的格式允许Spark执行许多操作,如过滤、排序和哈希,而无需将字节反序列化回对象。
DataSet是具有强类型的数据集合,需要提供对应的类型信息。
1、创建 DataSet
1.1 使用scala的序列得到DataSet
需要隐式转换
import org.apache.spark.sql.{DataFrame, Dataset, SparkSession}
object CreateDS01 {
def main(args: Array[String]): Unit = {
val sparkWhx: SparkSession = SparkSession.builder().master("local[*]").appName("CreateDS").getOrCreate()
import sparkWhx.implicits._
val list1 = List(30, 50, 70, 60, 10, 20)
// 把集合转成ds
val ds: Dataset[Int] = list1.toDS()
// df能用的ds一定可以用
ds.show
sparkWhx.close()
}
}
打印结果:
+-----+
|value|
+-----+
| 30|
| 50|
| 70|
| 60|
| 10|
| 20|
+-----+
import org.apache.spark.sql.SparkSession
case class User(name: String, age: Int)
object CreateDS02 {
def main(args: Array[String]): Unit = {
val sparkWhx: SparkSession = SparkSession.builder().master("local[*]").appName("CreateDS").getOrCreate()
import sparkWhx.implicits._
val list = List(User("zs", 10), User("lisi", 20), User("ww", 15))
val ds= list.toDS()
// 在ds做sql查询
ds.createOrReplaceTempView("user")
sparkWhx.sql("select * from user where age > 15").show
sparkWhx.stop()
sparkWhx.close()
}
}
打印结果:
+----+---+
|name|age|
+----+---+
|lisi| 20|
+----+---+
1.2 使用RDD转换得到DataSet
1.2.1 RDD转为DataSet
需要隐式转换
import org.apache.spark.sql.{Dataset, SparkSession}
case class User(name: String, age: Int)
object RDD2DS {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("RDD2DS").getOrCreate()
import spark.implicits._
val rdd = spark.sparkContext.parallelize(Array(User("lisi", 10), User("zs", 20), User("ww", 15)))
val ds: Dataset[User] = rdd.toDS()
ds.show()
spark.close()
}
}
打印结果:
+----+---+
|name|age|
+----+---+
|lisi| 10|
| zs| 20|
| ww| 15|
+----+---+
1.2.2 DataSet转为RDD
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession
case class User(name: String, age: Int)
object DS2RDD {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("DS2RDD").getOrCreate()
import spark.implicits._
val ds = Seq(User("lisi", 40), User("zs", 20)).toDS
val rdd: RDD[User] = ds.rdd
rdd.collect.foreach(println)
spark.stop()
}
}
打印结果:
User(lisi,40)
User(zs,20)
1.3使用DataFrame转换得到DataSet
1.3.1 DataFrame转为DataSet
要先有一个样例类;需要隐式转换
import org.apache.spark.sql.{DataFrame, SparkSession}
case class People(name: String, age: Long)
object DFDS {
def main(args: Array[String]): Unit = {
val sparkWhx = SparkSession.builder().master("local[*]").appName("DFDS").getOrCreate()
val sc = sparkWhx.sparkContext
val rdd = sc.parallelize(("lisi", 10):: ("zs", 20)::Nil)
import sparkWhx.implicits._
val df = rdd.toDF("name", "age")
// 先有一个样例类,DataFrame转为DataSet
val ds = df.as[People]
ds.show()
sparkWhx.close()
}
}
打印结果:
+----+---+
|name|age|
+----+---+
|lisi| 10|
| zs| 20|
+----+---+
1.3.2 DataSet转为DataFrame
不需要隐式转换
import org.apache.spark.sql.{DataFrame, SparkSession}
case class Student(name: String, age: Long)
object DFDS02 {
def main(args: Array[String]): Unit = {
val sparkWhx = SparkSession.builder().master("local[*]").appName("DFDS").getOrCreate()
val sc = sparkWhx.sparkContext
val rdd = sc.parallelize(("lisi", 10):: ("zs", 20)::Nil)
import sparkWhx.implicits._
val df = rdd.toDF("name", "age")
// 先有一个样例类,DataFrame转为DataSet
val ds = df.as[Student]
val df1: DataFrame = ds.toDF() // DataSet转为DataFrame
df1.show
sparkWhx.close()
}
}
打印结果:
+----+---+
|name|age|
+----+---+
|lisi| 10|
| zs| 20|
+----+---+
三、RDD, DataFrame和 DataSet 之间的关系
在 SparkSQL 中 Spark 为我们提供了两个新的抽象,分别是DataFrame和DataSet。
RDD (Spark1.0) —> Dataframe(Spark1.3) —> Dataset(Spark1.6)
如果同样的数据都给到这三个数据结构,他们分别计算之后,都会给出相同的结果。不同是的他们的执行效率和执行方式。
在后期的 Spark 版本中,DataSet会逐步取代RDD和DataFrame成为唯一的 API 接口。
1、三者的共性
- RDD、DataFrame、Dataset全都是 Spark 平台下的分布式弹性数据集,为处理超大型数据提供便利
- 三者都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action如foreach时,三者才会开始遍历运算。
- 三者都会根据 Spark 的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存溢出
- 三者都有partition的概念
- 三者有许多共同的函数,如map, filter,排序等
- 在对 DataFrame和Dataset进行操作许多操作都需要这个包进行支持 import spark.implicits._
- DataFrame和Dataset均可使用模式匹配获取各个字段的值和类型
2、三者的区别
2.1 RDD
- RDD一般和 spark mlib 同时使用
- RDD不支持sparksql操作
2.2 DataFrame
- 与RDD和Dataset不同,DataFrame每一行的类型固定为Row,每一列的值没法直接访问,只有通过解析才能获取各个字段的值,
- DataFrame与DataSet一般不与 spark mlib 同时使用
- DataFrame与DataSet均支持 SparkSQL 的操作,比如select,groupby之类,还能注册临时表/视窗,进行 sql 语句操作
- DataFrame与DataSet支持一些特别方便的保存方式,比如保存成csv,可以带上表头,这样每一列的字段名一目了然。
2.3 DataSet
- Dataset和DataFrame拥有完全相同的成员函数,区别只是每一行的数据类型不同。 DataFrame其实就是DataSet的一个特例
- DataFrame也可以叫Dataset[Row],每一行的类型是Row,不解析,每一行究竟有哪些字段,各个字段又是什么类型都无从得知,只能用上面提到的getAS方法或者共性中的第七条提到的模式匹配拿出特定字段。而Dataset中,每一行是什么类型是不一定的,在自定义了case class之后可以很自由的获得每一行的信息
四、自定义聚合函数
强类型的Dataset和弱类型的DataFrame都提供了相关的聚合函数, 如 count(),countDistinct(),avg(),max(),min()。除此之外,用户可以设定自己的自定义聚合函数
继承UserDefinedAggregateFunction
五、Spark数据源一:Hive之外的数据源(使用SparkSQL)
1、SparkSQL读取数据源
1.1 通用方法:spark.read.load
默认是parquet数据格式
可以手动给数据源指定一些额外的选项. 数据源应该用全名称来指定, 但是对一些内置的数据源也可以使用短名称:json, parquet, jdbc, orc, libsvm, csv, text
spark.read.format(“格式”).load(路径),比如:spark.read.format(“json”).load(“/src/resources/people.json”)
1.2 通用方法:可以直接在文件上执行sql语句
spark.sql("select * from json.`examples/src/main/resources/employees.json`")
1.3 通用方法:JDBC读取Mysql里的数据
import org.apache.spark.sql.SparkSession
object JDBCRead {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("JDBCRead").getOrCreate()
val df = spark.read
.option("url", "jdbc:mysql://hadoop102:3306/rdd")
.option("user", "root")
.option("password", "123456")
.option("dbtable", "user")
.format("jdbc").load()
df.show
spark.close()
}
}
1.4 专用方法:加载数据的专用读法
- spark.read.json(“json文件地址”)
- spark.read.text(“text文件地址”)
- spark.read.csv(“csv文件地址”)
- spark.read.orc(“orc文件地址”)
- spark.read.jdbc()
- …
import java.util.Properties
import org.apache.spark.sql.SparkSession
object JDBCRead02 {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("JDBCRead").getOrCreate()
val props = new Properties()
props.put("user", "root")
props.put("password", "123456")
val df = spark.read.jdbc(url="jdbc:mysql://hadoop102:3306/rdd", table="user", properties = props)
df.show
spark.close()
}
}
2、SparkSQL写入数据
2.1 通用方法:df.write.save
df.write.format(“格式”).save(路径)
模式:error(默认)、overwrite、append、ignore
df.write.format(“格式”).mode(“append”).save(路径)
2.2 通用方法:JDBC向Mysql里写入数据
import org.apache.spark.sql.SparkSession
object JDBCWrite {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("JDBCWrite").getOrCreate()
val df = spark.read.json("c:/users.json")
// 写到jdbc中
df.write
.format("jdbc")
.option("url", "jdbc:mysql://hadoop102:3306/rdd")
.option("user", "root")
.option("password", "123456")
.option("dbtable", "usre1015")
.mode("append")
.save()
spark.close()
}
}
2.3 专用方法:保存数据
- df.write.json(地址)
- df.write.text(地址)
- df.write.csv(地址)
- df.write.orc(地址)
- df.write.jdbc(地址)
- …
2.4 专用方法:JDBC向Mysql里写入数据
import java.util.Properties
import org.apache.spark.sql.SparkSession
object JDBCWrite02 {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("JDBCWrite").getOrCreate()
val df = spark.read.json("c:/users.json")
// 写到jdbc中
val props = new Properties()
props.put("user", "root")
props.put("password", "123456")
df.write.jdbc(url="jdbc:mysql://hadoop102:3306/rdd", table="user1016", connectionProperties = props)
spark.close()
}
}
六、Spark数据源二:Hive数据源(使用HiveSQL)
Hive 是 Hadoop 上的 SQL 引擎,Spark SQ L编译时可以包含 Hive 支持,也可以不包含。
包含 Hive 支持的 Spark SQL 可以支持 Hive 表访问、UDF (用户自定义函数)以及 Hive 查询语言(HiveQL/HQL)等。
SparkSQL并不能完全替代Hive,它替代的是Hive的查询引擎,SparkSQL由于其底层基于Spark自身的基于内存的特点,因此速度是Hive查询引擎的数倍以上,Spark本身是不提供存储的,所以不可能替代Hive作为数据仓库的这个功能。
需要强调的一点是,如果要在 Spark SQL 中包含Hive 的库,并不需要事先安装 Hive。一般来说,最好还是在编译Spark SQL时引入Hive支持,这样就可以使用这些特性了。如果你下载的是二进制版本的 Spark,它应该已经在编译时添加了 Hive 支持。
即使没有部署好 Hive,Spark SQL 也可以运行。 需要注意的是,如果你没有部署好Hive,Spark SQL 会在当前的工作目录中创建出自己的 Hive 元数据仓库,叫作 metastore_db。
此外,如果你尝试使用 HiveQL 中的 CREATE TABLE (并非 CREATE EXTERNAL TABLE)语句来创建表,这些表会被放在你默认的文件系统中的 /user/hive/warehouse 目录中(如果你的 classpath 中有配好的 hdfs-site.xml,默认的文件系统就是 HDFS,否则就是本地文件系统)。
1、使用内嵌的 Hive
如果使用 Spark 内嵌的 Hive, 则什么都不用做, 直接使用即可.
Hive 的元数据存储在 derby 中, 仓库地址:$SPARK_HOME/spark-warehouse
然而在实际使用中, 几乎没有任何人会使用内置的 Hive
2、使用外置的 Hive
Spark 要接管 Hive 需要把 hive-site.xml 复制到 Spark的配置文件目录中($SPARK_HOME/conf)
把 Mysql 的驱动 拷贝 到 jars/目录下.
如果访问不到hdfs, 则需要把core-site.xml和hdfs-site.xml 拷贝到conf/目录下.
3、Spark使用HiveSQL语句调用Hive数据仓库方式
3.1 在Scala交互界面(Spark内置Scala)使用HiveSQL语句调用Hive数据仓库
在spark-shell执行 hive 方面的查询比较麻烦.spark.sql(“”).show
[whx@hadoop102 spark-local]$ bin/spark-shell
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
21/02/07 18:59:06 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
21/02/07 18:59:10 WARN ObjectStore: Version information not found in metastore. hive.metastore.schema.verification is not enabled so recording the schema version 1.2.0
21/02/07 18:59:10 WARN ObjectStore: Failed to get database default, returning NoSuchObjectException
21/02/07 18:59:10 WARN ObjectStore: Failed to get database global_temp, returning NoSuchObjectException
Spark context Web UI available at http://192.168.1.102:4040
Spark context available as 'sc' (master = local[*], app id = local-1612695546862).
Spark session available as 'spark'.
Welcome to
____ __
/ __/__ ___ _____/ /__
_\ \/ _ \/ _ `/ __/ '_/
/___/ .__/\_,_/_/ /_/\_\ version 2.1.1
/_/
Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_121)
Type in expressions to have them evaluated.
Type :help for more information.
scala> spark.sql("show tables").show
+--------+---------+-----------+
|database|tableName|isTemporary|
+--------+---------+-----------+
| default| emp| false|
+--------+---------+-----------+
scala> spark.sql("select * from emp").show
19/02/09 19:40:28 WARN LazyStruct: Extra bytes detected at the end of the row! Ignoring similar problems.
+-----+-------+---------+----+----------+------+------+------+
|empno| ename| job| mgr| hiredate| sal| comm|deptno|
+-----+-------+---------+----+----------+------+------+------+
| 7369| SMITH| CLERK|7902|1980-12-17| 800.0| null| 20|
| 7499| ALLEN| SALESMAN|7698| 1981-2-20|1600.0| 300.0| 30|
| 7521| WARD| SALESMAN|7698| 1981-2-22|1250.0| 500.0| 30|
| 7566| JONES| MANAGER|7839| 1981-4-2|2975.0| null| 20|
| 7654| MARTIN| SALESMAN|7698| 1981-9-28|1250.0|1400.0| 30|
| 7698| BLAKE| MANAGER|7839| 1981-5-1|2850.0| null| 30|
| 7782| CLARK| MANAGER|7839| 1981-6-9|2450.0| null| 10|
| 7788| SCOTT| ANALYST|7566| 1987-4-19|3000.0| null| 20|
| 7839| KING|PRESIDENT|null|1981-11-17|5000.0| null| 10|
| 7844| TURNER| SALESMAN|7698| 1981-9-8|1500.0| 0.0| 30|
| 7876| ADAMS| CLERK|7788| 1987-5-23|1100.0| null| 20|
| 7900| JAMES| CLERK|7698| 1981-12-3| 950.0| null| 30|
| 7902| FORD| ANALYST|7566| 1981-12-3|3000.0| null| 20|
| 7934| MILLER| CLERK|7782| 1982-1-23|1300.0| null| 10|
| 7944|zhiling| CLERK|7782| 1982-1-23|1300.0| null| 50|
+-----+-------+---------+----+----------+------+------+------+
3.2 在spark-sql cli中使用HiveSQL语句调用Hive数据仓库
Spark 专门给我们提供了书写 HiveQL 的工具: spark-sql cli
3.3 在hiveserver2 + beeline中使用HiveSQL语句调用Hive数据仓库
spark-sql 得到的结果不够友好, 所以可以使用hiveserver2 + beeline
- 启动 thrift服务器
sbin/start-thriftserver.sh \
--master yarn \
--hiveconf hive.server2.thrift.bind.host=hadoop201 \
-–hiveconf hive.server2.thrift.port=10000 \
- 启动beeline客户端
bin/beeline
# 然后输入
!connect jdbc:hive2://hadoop201:10000
# 然后按照提示输入用户名和密码
3.4 在IntellJ编辑器的Scala代码中使用HiveSQL语句调用Hive数据仓库
- 步骤1: 拷贝 hive-site.xml 到 resources 目录下
- 步骤2: 添加依赖
<dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-hive_2.11</artifactId> <version>2.1.1</version> </dependency>
3.4.1 读取Hive数据仓库
在开发工具中创建数据库默认是在本地仓库。通过参数修改数据库仓库的地址: config(“spark.sql.warehouse.dir”, “hdfs://hadoop201:9000/user/hive/warehouse”)
import org.apache.spark.sql.SparkSession
object HiveRead {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("HiveRead").enableHiveSupport().getOrCreate()
import spark.implicits._
spark.sql("show databases")
spark.sql("use gmall")
spark.sql("select count(*) from ads_uv_count").show
spark.close()
}
}
其中:enableHiveSupport()表示使用外置Hive
3.4.2 向Hive数据仓库插入数据
3.4.2.1 向Hive数据仓库插入数据方式一:spark.sql(“insert into user1 values(10, ‘lisi’)”).show
import org.apache.spark.sql.SparkSession
object HiveWrite {
def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "whx") // 设置HDFS有写入权限的用户
val spark: SparkSession = SparkSession
.builder()
.master("local[*]")
.appName("HiveWrite")
.enableHiveSupport()
.config("spark.sql.warehouse.dir", "hdfs://hadoop101:9000/user/hive/warehouse")
.getOrCreate()
import spark.implicits._
spark.sql("create database spark1016").show // 创建换一个数据库
spark.sql("create table user1(id int, name string)").show // 创建表
spark.sql("insert into user1 values(10, 'lisi')").show // 通过insert语句向表里插入数据(插入数据前表得存在)
spark.close()
}
}
3.4.2.2 向Hive数据仓库插入数据方式二:df.write.mode(“append”).saveAsTable(“user2”),按照列名分配插入值
直接把数据写入到hive中. 表可以存着也可以不存在。如果表不存在会自动创建
该方式在实操中用的比较多
import org.apache.spark.sql.SparkSession
object HiveWrite1_2 {
def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "whx")
val spark: SparkSession = SparkSession
.builder()
.master("local[*]")
.appName("HiveWrite")
.enableHiveSupport()
.config("spark.sql.warehouse.dir", "hdfs://hadoop101:9000/user/hive/warehouse")
.getOrCreate()
val df = spark.read.json("c:/users.json")
spark.sql("create database spark1016").show // 创建换一个数据库
spark.sql("use spark1016")
// 直接把数据写入到hive中. 表可以存着也可以不存在。如果表不存在会自动创建
df.write.mode("append").saveAsTable("user2") // mode("append")表示如果user2表已经存在,则追加数据
spark.close()
}
}
3.4.2.3 向Hive数据仓库插入数据方式三:df.write.insertInto(“user2”),按照位置顺序分配插入值
import org.apache.spark.sql.SparkSession
object HiveWrite1_3 {
def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "whx")
val spark: SparkSession = SparkSession
.builder()
.master("local[*]")
.appName("HiveWrite")
.enableHiveSupport()
.config("spark.sql.warehouse.dir", "hdfs://hadoop101:9000/user/hive/warehouse")
.getOrCreate()
val df = spark.read.json("c:/users.json")
spark.sql("create database spark1016").show // 创建换一个数据库
spark.sql("create table user1(id int, name string)").show // 创建表
spark.sql("use spark1016")
// 直接把数据写入到hive中. 表可以存着也可以不存在。表得提前存在
df.write.insertInto("user2") // 基本等于 mode("append").saveAsTable("user2")
spark.close()
}
}
4、Spark使用HiveSQL语句时的注意事项:HiveSQL聚合函数默认分区数为200
HiveSQL聚合函数默认分区数为200,如果数据量不大时,可以使用coalesce()函数限定分区数
import org.apache.spark.sql.{DataFrame, SparkSession}
object HiveWrite2 {
def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "whx")
val spark: SparkSession = SparkSession
.builder()
.master("local[*]")
.appName("HiveWrite2")
.enableHiveSupport()
.config("spark.sql.shuffle.partitions", 10)
.getOrCreate()
val df: DataFrame = spark.read.json("c:/users.json")
df.createOrReplaceTempView("a")
spark.sql("use spark1016")
val df1 = spark.sql("select * from a")
val df2 = spark.sql("select sum(age) sum_age from a group by name")
println(df1.rdd.getNumPartitions) // 1
println(df2.rdd.getNumPartitions) // 200
df2.coalesce(1).write.mode("overwrite").saveAsTable("a2")
spark.close()
}
}