前言:Spark的用户有三种不同的API可以与分布式数据集合进行交互:RDD API、DataFrame API、Dataset API。传统的RDD API提供了类型安全和功能强大的lambda函数,但是没有对性能进行优化。Dataset API和DataFrame API提供了更简单的方法来使用领域特定的语言,并且提供了优于RDD的性能。Dataset API将RDD和DataFrame组合在一起。用户可以根据自己的需要选择使用RDD API、DataFrame API、Dataset API。但是,一般来说,为了更好的性能,DataFrame API和Dataset API应该优先于常规的RDD使用。
Dataset/DataFrame API具有性能优化、速度快、自动模式发现、多数据源支持、多编程语言支持和谓词下推等特性;此外,他们还可以与RDD和Dataset进行互操作。在Spark1.6版本中引入Dataset API,它可以在Scala和Java语言下调用。Spark2.0统一了DataFrame API和Dataset API,为用户提供了单一的抽象,因此,在Spark2.0中,DataFrame等同于Dataset[Row].
画外音:我在启动Spark集群的时候,有时候会出现如下的错误:
hadoop3: failed to launch: nice -n 0 /soft/spark/bin/spark-class org.apache.spark.deploy.worker.Worker --webui-port 8081 spark://hadoop0:7077
hadoop3: full log in /soft/spark/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-hadoop3.out
网上查过之后,找到了解决方法:就是在每一个root用户下/root/.bashrc目下的文件后边导入jdk 的路径即可,然后就停止之前启动的master 再启动sbin下./start-all.sh 查看进程即可。
vi /root/.bashrc export JAVA_HOME=/soft/jdk
1、起点:SparkContext
读取JSON文件:
import org.apache.spark.sql.SQLContext
import org.apache.spark.{SparkConf, SparkContext}
/**
* @author YuZhansheng
* @ desc
* @ create 2019-03-03 17:12
*/
object SQLContextApp {
def main(args: Array[String]): Unit = {
val path = args(0)
//1、创建相应的Context
val sparkConf = new SparkConf()//.setAppName("SQLContextApp").setMaster("local[2]")
val sc = new SparkContext(sparkConf)
val sqlContext = new SQLContext(sc)
//2、相关的处理:json "/soft/spark/examples/src/main/resources/people.json"
val people = sqlContext.read.format("json").load(path)
people.printSchema()
people.show()
//关闭资源
sc.stop()
}
}
使用Spark-submit提交:
bin/spark-submit --class com.xidian.spark.sql.SQLContextApp --name SQLContextApp --master local[2] /root/Project/Spark/target/spark-1.0.jar file:/soft/spark/examples/src/main/resources/people.json
解释一下各个参数的意义:
- bin/spark-submit:提交命令,不用多说。
- --class com.xidian.spark.sql.SQLContextApp:要运行的主类相对路径
- --name SQLContextApp:给这个任务起一个名字,一般都是类名
- --master local[2]:运行模式,是本地运行还是提交YARN
- /root/Project/Spark/target/spark-1.0.jar:jar包所在位置
- file:/soft/spark/examples/src/main/resources/people.json:参数名,本地文件前面加个file:!
测试的时候,没有加file:,运行命令,一直出现如下的错误:
19/03/03 18:08:29 WARN streaming.FileStreamSink: Error while looking for metadata directory.
Exception in thread "main" java.net.ConnectException: Call From hadoop0/192.168.25.128 to hadoop0:9000 failed on connection exception: java.net.ConnectException: 拒绝连接; For more details see: http://wiki.apache.org/hadoop/ConnectionRefused
2、从Hive过渡到SparkSQL
添加依赖:
<!--spark hive--> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-hive_2.11</artifactId> <version>${spark.version}</version> </dependency>
import org.apache.spark.sql.hive.HiveContext
import org.apache.spark.{SparkConf, SparkContext}
/**
* @author YuZhansheng
* @ desc HiveContext的使用
* @ create 2019-03-04 9:55
*/
object HiveContextApp {
def main(args: Array[String]): Unit = {
//1、创建相应的Context
val sparkConf = new SparkConf().setAppName("SQLContextApp").setMaster("local[2]")
val sc = new SparkContext(sparkConf)
val hiveContext = new HiveContext(sc)
//2、相关的处理:json
hiveContext.table("tbl").show
//关闭资源
sc.stop()
}
}
又遇到一个坑:Exception in thread "main" org.apache.spark.sql.catalyst.analysis.NoSuchTableException: Table or view 'tbl' not found in database 'default';解决方法:需要将hive-site.xml这个文件拷贝到resource下。
又是一个坑:Exception in thread "main" java.net.ConnectException: Call From hadoop0/192.168.25.128 to hadoop0:9000 failed on connection exception: java.net.ConnectException: 拒绝连接; For more details see: 解决办法:启动Hadoop的HDFS就可以了。
第三个坑:再启动hive的时候,出现错误:Caused by: MetaException(message:Hive Schema version 2.1.0 does not match metastore's schema version 1.2.0 Metastore is not upgraded or corrupt);解决办法:登录这个hive的MySQL源数据库;use hive_remote;然后:select * from VERSION;(在Linux下要区分表名大小写),最后更新一下schema就好了:update VERSION set SCHEMA_VERSION='2.2.0' where VER_ID=1;
3、新征程:SparkSession
Spark2.0开始,所有功能的入口点都是SparkSession类。要创建一个基本的SparkSession,只需使用SparkSession.builder():
还是实现读取Json文件的功能,程序如下:
import org.apache.spark.sql.SparkSession
/**
* @author YuZhansheng
* @ desc SparkSession的使用
* @ create 2019-03-04 10:57
*/
object SparkSessionApp {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().appName("SparkSessionApp").master("local[2]").getOrCreate()
val people = spark.read.json("file:/soft/spark/examples/src/main/resources/people.json")
people.show()
spark.stop()
}
}
4、spark-shell中的spark-sql的使用
先把hive/conf/hive-site.xml给复制到spark的conf目录。
然后启动bin/spark-shell后会报错:
Caused by: org.datanucleus.store.rdbms.connectionpool.DatastoreDriverNotFoundException: The specified datastore driver ("com.mysql.jdbc.Driver") was not found in the CLASSPATH. Please check your CLASSPATH specification, and the name of the driver.
没有MySQL的驱动包。解决办法:上传一份mysql的驱动包,在启动spark-shell命令中添加--jars参数指定该驱动包的路径即可。
再次启动:spark-shell --master local[2] --jars /soft/spark/mysql-connector-java-5.1.21.jar,没错了,可以使用了。
结果和通过hive查询的结果是一样的:
在spark-shell下每次查询都要使用 spark.sql("查询语言").show,有点麻烦,我们能不能跟hive一样使用,直接输入SQL语句就能查询呢?当然是可以的!这个时候,我们就需要另外一个脚本了,不再使用spark-shell了,而是使用spark-sql脚本。
spark-sql --master local[2] --jars /soft/spark/mysql-connector-java-5.1.21.jar
直接使用SQL语句就可以查询啦!
spark-sql> select * from tbl;
1 xiaoming
中间省略很多打印的日志。
5、查看spark-sql的执行计划
先创建一个表:create table t(key string,value string);
使用explain命令查看执行计划:explain extended select a.key*(2+3),b.value from t a join t b on a.key = b.key and a.key > 3;
6、thriftserver和beeline的使用
在Master集群机器上启动thriftserver服务的命令(在spark/sbin目录下):./start-thriftserver.sh --master local[2] --jars /soft/spark/mysql-connector-java-5.1.21.jar,默认端口是10000.
启动beeline(在spark/bin目录下)连接上thriftserver服务端:./beeline -u jdbc:hive2://hadoop0:10000 -n root
hadoop0就是Master节点。
注意:-n后面跟的是用户名,不知主机名。
[root@hadoop0 bin]# ./beeline -u jdbc:hive2://localhost:10000 -n root
Connecting to jdbc:hive2://localhost:10000
19/03/04 15:38:56 INFO jdbc.Utils: Supplied authorities: localhost:10000
19/03/04 15:38:56 INFO jdbc.Utils: Resolved authority: localhost:10000
19/03/04 15:38:56 INFO jdbc.HiveConnection: Will try to open client transport with JDBC Uri: jdbc:hive2://localhost:10000
Connected to: Spark SQL (version 2.2.0)
Driver: Hive JDBC (version 1.2.1.spark2)
Transaction isolation: TRANSACTION_REPEATABLE_READ
Beeline version 1.2.1.spark2 by Apache Hive
0: jdbc:hive2://localhost:10000>
0: jdbc:hive2://hadoop0:10000> show tables;
+-----------+------------+--------------+--+
| database | tableName | isTemporary |
+-----------+------------+--------------+--+
| default | t | false |
| default | tbl | false |
+-----------+------------+--------------+--+
2 rows selected (2.268 seconds)
0: jdbc:hive2://hadoop0:10000> select * from tbl;
+-----+-----------+--+
| id | name |
+-----+-----------+--+
| 1 | xiaoming |
+-----+-----------+--+
1 row selected (6.737 seconds)
thriftserver和普通的spark-shell/spark-sql有什么区别呢?
spark-shell/spark-sql都是一个Spark Application;thriftserver不管启动多少客户端(beeline/code)连接,永远都是一个Spark Application,解决了一个数据共享的问题,多个客户端可以共享数据。
7、jdbc编程访问SparkSQL数据
添加依赖:
<dependency> <groupId>org.spark-project.hive</groupId> <artifactId>hive-jdbc</artifactId> <version>1.2.1.spark2</version> </dependency>
import java.sql.DriverManager
/**
* @author YuZhansheng
* @desc 通过JDBC方式访问
* @create 2019-03-04 15:55
*/
object SparkSQLThriftServerApp {
def main(args: Array[String]): Unit = {
//加载驱动
Class.forName("org.apache.hive.jdbc.HiveDriver")
//获取连接
val conn = DriverManager.getConnection("jdbc:hive2://hadoop0:10000","root","")
//获取Statement
val pstmt = conn.prepareStatement("select * from tbl")
//执行查询
val rs = pstmt.executeQuery()
//遍历结果
while(rs.next()){
println(rs.getString("name") + rs.getInt("id"))
}
//关闭资源
rs.close()
pstmt.close()
conn.close()
}
}
观看控制台打印结果验证程序可行性!