SparkSQL实战2——先了解几个基础知识

前言: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()
    }
}

观看控制台打印结果验证程序可行性!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值