7.5 访问 Hive
导读
整合
SparkSQL
和Hive
, 使用Hive
的MetaStore
元信息库使用
SparkSQL
查询Hive
表案例, 使用常见
HiveSQL
写入内容到
Hive
表
7.5.1 SparkSQL 整合 Hive
导读
开启
Hive
的MetaStore
独立进程整合
SparkSQL
和Hive
的MetaStore
和一个文件格式不同, Hive
是一个外部的数据存储和查询引擎, 所以如果 Spark
要访问 Hive
的话, 就需要先整合 Hive
(1)整合什么 ?
如果要讨论 SparkSQL
如何和 Hive
进行整合, 首要考虑的事应该是 Hive
有什么, 有什么就整合什么就可以
-
MetaStore
, 元数据存储SparkSQL
内置的有一个MetaStore
, 通过嵌入式数据库Derby
保存元信息, 但是对于生产环境来说, 还是应该使用Hive
的MetaStore
, 一是更成熟, 功能更强, 二是可以使用Hive
的元信息 -
查询引擎
SparkSQL
内置了HiveSQL
的支持, 所以无需整合
(2)为什么要开启 Hive
的 MetaStore?
Hive
的 MetaStore
是一个 Hive
的组件, 一个 Hive
提供的程序, 用以保存和访问表的元数据, 整个 Hive
的结构大致如下
由上图可知道, 其实 Hive
中主要的组件就三个, HiveServer2
负责接受外部系统的查询请求, 例如 JDBC
, HiveServer2
接收到查询请求后, 交给 Driver
处理, Driver
会首先去询问 MetaStore
表在哪存后, Driver
程序通过 MR
程序来访问 HDFS
从而获取结果返回给查询请求者
而 Hive
的 MetaStore
对 SparkSQL
的意义非常重大, 如果 SparkSQL
可以直接访问 Hive
的 MetaStore
, 则理论上可以做到和 Hive
一样的事情, 例如通过 Hive
表查询数据
而 Hive 的 MetaStore 的运行模式有三种
-
内嵌
Derby
数据库模式这种模式不必说了, 自然是在测试的时候使用, 生产环境不太可能使用嵌入式数据库, 一是不稳定, 二是这个
Derby
是单连接的, 不支持并发 -
Local
模式Local
和Remote
都是访问MySQL
数据库作为存储元数据的地方, 但是Local
模式的MetaStore
没有独立进程, 依附于HiveServer2
的进程 -
Remote
模式和
Loca
模式一样, 访问MySQL
数据库存放元数据, 但是Remote
的MetaStore
运行在独立的进程中
我们显然要选择 Remote
模式, 因为要让其独立运行, 这样才能让 SparkSQL
一直可以访问
(3)Hive
开启 MetaStore
Step 1
: 修改 hive-site.xml
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
</property>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://node01:3306/hive?createDatabaseIfNotExist=true</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>username</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>password</value>
</property>
<property>
<name>hive.metastore.local</name>
<value>false</value>
</property>
<property>
<name>hive.metastore.uris</name>
<value>thrift://node01:9083</value> //当前服务器
</property>
Step 2
: 启动 Hive MetaStore
nohup /export/servers/hive/bin/hive --service metastore 2>&1 >> /var/log.log &
(4)SparkSQL
整合 Hive
的 MetaStore
即使不去整合 MetaStore
, Spark
也有一个内置的 MateStore
, 使用 Derby
嵌入式数据库保存数据, 但是这种方式不适合生产环境, 因为这种模式同一时间只能有一个 SparkSession
使用, 所以生产环境更推荐使用 Hive
的 MetaStore
SparkSQL
整合 Hive
的 MetaStore
主要思路就是要通过配置能够访问它, 并且能够使用 HDFS
保存 WareHouse
, 这些配置信息一般存在于 Hadoop
和 HDFS
的配置文件中, 所以可以直接拷贝 Hadoop
和 Hive
的配置文件到 Spark
的配置目录
cd /export/servers/hadoop/etc/hadoop
cp hive-site.xml core-site.xml hdfs-site.xml /export/servers/spark/conf/
scp -r /export/servers/spark/conf node02:/export/servers/spark/conf
scp -r /export/servers/spark/conf node03:/export/servers/spark/conf
- Spark 需要 hive-site.xml 的原因是, 要读取 Hive 的配置信息, 主要是元数据仓库的位置等信息
- Spark 需要 core-site.xml 的原因是, 要读取安全有关的配置
- Spark 需要 hdfs-site.xml 的原因是, 有可能需要在 HDFS 中放置表文件, 所以需要 HDFS 的配置
如果不希望通过拷贝文件的方式整合 Hive, 也可以在 SparkSession 启动的时候, 通过指定 Hive 的 MetaStore 的位置来访问, 但是更推荐整合的方式
7.5.2 访问 Hive 表
导读
在
Hive
中创建表使用
SparkSQL
访问Hive
中已经存在的表使用
SparkSQL
创建Hive
表使用
SparkSQL
修改Hive
表中的数据
(1)在 Hive
中创建表
第一步, 需要先将文件上传到集群中, 使用如下命令上传到 HDFS
中
hdfs dfs -mkdir -p /dataset
hdfs dfs -put studenttabl10k /dataset/
第二步, 使用 Hive
或者 Beeline
执行如下 SQL
CREATE DATABASE IF NOT EXISTS spark_integrition;
USE spark_integrition;
CREATE EXTERNAL TABLE student
(
name STRING,
age INT,
gpa string
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
LOCATION '/dataset/hive';
LOAD DATA INPATH '/dataset/studenttab10k' OVERWRITE INTO TABLE student;
(2)通过 SparkSQL
查询 Hive
的表
查询 Hive
中的表可以直接通过 spark.sql(…)
来进行, 可以直接在其中访问 Hive
的 MetaStore
, 前提是一定要将 Hive
的配置文件拷贝到 Spark
的 conf
目录
scala> spark.sql("use spark_integrition")
scala> val resultDF = spark.sql("select * from student limit 10")
scala> resultDF.show()
(3)通过 SparkSQL
创建 Hive
表
通过 SparkSQL
可以直接创建 Hive
表, 并且使用 LOAD DATA
加载数据
val createTableStr =
"""
|CREATE EXTERNAL TABLE student
|(
| name STRING,
| age INT,
| gpa string
|)
|ROW FORMAT DELIMITED
| FIELDS TERMINATED BY '\t'
| LINES TERMINATED BY '\n'
|STORED AS TEXTFILE
|LOCATION '/dataset/hive'
""".stripMargin
spark.sql("CREATE DATABASE IF NOT EXISTS spark_integrition1")
spark.sql("USE spark_integrition1")
spark.sql(createTableStr)
spark.sql("LOAD DATA INPATH '/dataset/studenttab10k' OVERWRITE INTO TABLE student")
spark.sql("select * from student limit").show()
目前 SparkSQL
支持的文件格式有 sequencefile
, rcfile
, orc
, parquet
, textfile
, avro
, 并且也可以指定 serde
的名称
(4)使用 SparkSQL
处理数据并保存进 Hive 表
前面都在使用 SparkShell
的方式来访问 Hive
, 编写 SQL
, 通过 Spark
独立应用的形式也可以做到同样的事, 但是需要一些前置的步骤, 如下
Step 1: 导入 Maven
依赖
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
Step 2: 配置 SparkSession
如果希望使用 SparkSQL
访问 Hive
的话, 需要做两件事
-
开启
SparkSession
的Hive
支持经过这一步配置,
SparkSQL
才会把SQL
语句当作HiveSQL
来进行解析 -
设置
WareHouse
的位置虽然
hive-stie.xml
中已经配置了WareHouse
的位置, 但是在Spark 2.0.0
后已经废弃了hive-site.xml
中设置的hive.metastore.warehouse.dir
, 需要在SparkSession
中设置WareHouse
的位置 -
设置
MetaStore
的位置
val spark = SparkSession
.builder()
.appName("hive example")
.config("spark.sql.warehouse.dir", "hdfs://node01:8020/dataset/hive")
.config("hive.metastore.uris", "thrift://node01:9083")
.enableHiveSupport()
.getOrCreate()
- 设置 WareHouse 的位置
- 设置 MetaStore 的位置
- 开启 Hive 支持
配置好了以后, 就可以通过 DataFrame
处理数据, 后将数据结果推入 Hive
表中了, 在将结果保存到 Hive
表的时候, 可以指定保存模式
val schema = StructType(
List(
StructField("name", StringType),
StructField("age", IntegerType),
StructField("gpa", FloatType)
)
)
val studentDF = spark.read
.option("delimiter", "\t")
.schema(schema)
.csv("dataset/studenttab10k")
val resultDF = studentDF.where("age < 50")
resultDF.write.mode(SaveMode.Overwrite).saveAsTable("spark_integrition1.student")
通过 mode
指定保存模式, 通过 saveAsTable
保存数据到 Hive