大数据-计算引擎-离线数据分析框架:SparkSQL【替代SparkRDD处理“结构化数据”;使用DataFrame/DataSet编程;机制是将SparkSQL转成RDD程序;集成HiveSQL】

在这里插入图片描述

一、使用 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、三者的共性

  1. RDD、DataFrame、Dataset全都是 Spark 平台下的分布式弹性数据集,为处理超大型数据提供便利
  2. 三者都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action如foreach时,三者才会开始遍历运算。
  3. 三者都会根据 Spark 的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存溢出
  4. 三者都有partition的概念
  5. 三者有许多共同的函数,如map, filter,排序等
  6. 在对 DataFrame和Dataset进行操作许多操作都需要这个包进行支持 import spark.implicits._
  7. DataFrame和Dataset均可使用模式匹配获取各个字段的值和类型

2、三者的区别

2.1 RDD

  1. RDD一般和 spark mlib 同时使用
  2. RDD不支持sparksql操作

2.2 DataFrame

  1. 与RDD和Dataset不同,DataFrame每一行的类型固定为Row,每一列的值没法直接访问,只有通过解析才能获取各个字段的值,
  2. DataFrame与DataSet一般不与 spark mlib 同时使用
  3. DataFrame与DataSet均支持 SparkSQL 的操作,比如select,groupby之类,还能注册临时表/视窗,进行 sql 语句操作
  4. DataFrame与DataSet支持一些特别方便的保存方式,比如保存成csv,可以带上表头,这样每一列的字段名一目了然。

2.3 DataSet

  1. Dataset和DataFrame拥有完全相同的成员函数,区别只是每一行的数据类型不同。 DataFrame其实就是DataSet的一个特例
  2. 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

  1. 启动 thrift服务器
sbin/start-thriftserver.sh \
--master yarn \
--hiveconf hive.server2.thrift.bind.host=hadoop201 \
-–hiveconf hive.server2.thrift.port=10000 \
  1. 启动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()
    }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值