1. 环境准备
1.1 安装Hive
1.2 安装Spark
1.3 拷贝hive的conf下的hive-site.xml到spark的conf目录下
[hadoop@hadoop000 ~]$ cd app/spark
[hadoop@hadoop000 spark]$ cp ~/app/hive-1.1.0-cdh5.7.0/conf/hive-site.xml conf/
1.4 准备MySQL驱动(如果用MySQL存储Hive metadata则需要)
[hadoop@hadoop000 ~]$ ls -ltr ~/software/mysql-connector-java-5.1.46/mysql-connector-java-5.1.46.jar
-rw-r--r--. 1 hadoop hadoop 1004838 Feb 26 21:28 /home/hadoop/software/mysql-connector-java-5.1.46/mysql-connector-java-5.1.46.jar
[hadoop@hadoop000 ~]$
2. Spark SQL使用交互式命令行来访问hive
2.1 使用Spark-shell交互式命令行来连接hive
[hadoop@hadoop000 ~]$ spark-shell --master local[2] --jars ~/software/mysql-connector-java-5.1.46/mysql-connector-java-5.1.46.jar
使用spark sql的api调用hive的命令,把结果展示出来
scala> spark.sql("show tables").show(false)
scala> spark.sql("select * from hive.emp").show(false)
scala> spark.sql("select * from hive.dept").show(false)
scala> spark.sql("select a.empno,a.name,b.dname from hive.emp a join hive.dept b on a.depno = b.deptno").show(false)
Spark SQL对hive表做join查询执行效率比hiveQL高很多。
2.2 使用spark-sql交互式命令行来连接hive
[hadoop@hadoop000 ~]$ spark-sql --master local[2] --jars ~/software/mysql-connector-java-5.1.46/mysql-connector-java-5.1.46.jar --driver-class-path ~/software/mysql-connector-java-5.1.46/mysql-connector-java-5.1.46.jar
#这里的--jars也可以不带
使用spark sql的api调用hive命令,把结果展示出来。这里的命令跟HiveQL命令一模一样。
spark-sql> select * from hive.emp;
spark-sql> select * from hive.dept;
spark-sql> select a.empno,a.name,b.dname from hive.emp a join hive.dept b on a.depno = b.deptno;
Spark的Web UI右上角的显示会随着连接方式的改变而改变
2.3 Cache使用
将emp表cache起来
spark-sql> cache table hive.emp;
然后再查询
spark-sql> select * from hive.emp;
在Spark Core中,cache是一个lazy的操作;但在spark SQL中,它是一个eager的操作。Web UI上可以看到cache的job。
cache后,emp表的input size比没cache要大(job#8 VS job#6)。
3. Spark SQL通过JDBC/ODBC连接HiveServer2来访问Hive里面的数据
启动一个Spark Thrift Server。ThriftServer就对应Hive里面的HiveServer2。
[hadoop@hadoop000 ~]$ app/spark/sbin/start-thriftserver.sh --master local[2] --jars ~/software/mysql-connector-java-5.1.46/mysql-connector-java-5.1.46.jar
从启动日志文件里面可以看到,服务端口号10000
18/08/31 09:05:22 INFO ThriftCLIService: Starting ThriftBinaryCLIService on port 10000 with 5...500 worker threads
启动之后通过Spark Web UI http://192.168.1.8:4040/jobs/可以看到启动的状态(如果4040被占用,它会启动在4041端口)。
此时我们可以通过spark beeline客户端来连接它。
beeline -u jdbc:hive2://192.168.1.8:10000 -n hadoop
select * from hive.emp;
特别注意:如果机器上面既装了spark又装了hive,要区分开启动的是spark的beeline还是hive的beeline!
除此之外,也可以通过编程,使用JDBC/ODBC来连接Spark ThriftServer。
pom.xml添加hive依赖
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>1.1.0-cdh5.7.0</version>
</dependency>
SparkSQLClientAPP.scala
/**
* 通过JDBC连接Spark SQL
*/
package com.data.d1
import java.sql.DriverManager
object SparkSQLClientApp {
def main(args: Array[String]): Unit = {
Class.forName("org.apache.hive.jdbc.HiveDriver")
val conn = DriverManager.getConnection("jdbc:hive2://10.132.37.38:10000","hadoop","")
val stmt = conn.prepareStatement("select product_id,product_name from product_info limit 3")
val rs = stmt.executeQuery()
while (rs.next()) {
println("product_id:" + rs.getInt("product_id") + " product_name:" + rs.getString("product_name"))
}
rs.close()
stmt.close()
conn.close()
}
}
JDBC连接时,用户名写hadoop,不需要写密码。
thriftserver和spark-sql或者spark-shell的区别在哪?
我们的ThriftServer也是一个Application,ThriftServer启动后可以7*24小时一直运行。其他应用可以JDBC/ODBC的方式去访问它。这样减少了服务每次启动时带来的资源消耗和时间成本。
工作中我们经常也需要把自己的application封装成一个http服务,服务启动时一次性请求资源,客户端调用服务时一个http请求就可以把结果拿回来,不用去重复申请资源。
(HUE,Zeeplin都是以这样一种方式来执行的)
4. 执行计划(84:54)
总结:
- Spark SQL不仅仅是SQL,它还可以做很多事情。典型的,它可以处理文件系统或者是其他存储系统上的不同的文件。
- 如何使用Spark SQL处理其他文件系统上的文件呢?接下来的博客里面会补充。
- 对Spark SQL的一些误解一定要澄清:spark sql 并不需要hive,spark sql要想处理hive里面的数据,第一种方式是通过hive-site连过去,第二种方式也可以通过起一个hive metastore的服务来连接。hive里面有两个常用的服务,HiveServer2和MetaStore2。如果是把MetaStore服务起起来,就可以使用spark sql操作hive里的数据了。当然它们都是配置在hive-site里面的。第二种方式不需要使用hive-site,用代码来编程,直接把地址写成metastore的地址即可。
- 使用
- 如何在Web页面点一个按钮,来跑spark作业,这种需求不太现实。spark 是一个分布式离线计算框架,跟web 前台不直接发生关系,它一定是要定时执行的,而且一般不会立马产生结果能满足页面请求的需要。前端要访问,是直接去拿计算的结果,而不是把计算的步骤提交上去(job会阻塞)。通过页面按钮去触发提交一个spark任务是可以的,但是不要等待它的结果。