分布式计算平台Spark:离线综合案例
一、重点
-
SparkSQL使用
-
开发接口
- DSL:使用函数来对表进行处理,类似于RDD的编程,表的体现:DF、DS
- SQL语法函数:select、where、groupBy、orderBy、limit、agg
- RDD的函数:map/filter/flatMap
- SQL:使用SQL语句来实现对表的处理,类似于Hive的编程,表的体现:DF/DS注册成视图、Hive表
- step1:将数据集注册为视图
- step2:通过SQL语句进行处理
- DSL:使用函数来对表进行处理,类似于RDD的编程,表的体现:DF、DS
-
UDF函数
-
DSL
val funName = udf(函数体)
-
SQL
spark.udf.register(函数名,函数体)
-
-
SparkSQL中数据源
-
read
spark.read.format("类型").load =》 DataFrameReader
- parquet
- json
- textfile
- csv
- jdbc
-
write
ds/df.write.mode(SaveMode).format("类型").option.save
- csv
- jdbc
-
SaveMode:保存模式
- ErrorIfExists:如果存在就抛出异常,默认的模式
- Append:追加模式
- Overwrite:覆盖模式
- Ignore:忽略本次请求
-
-
SparkSQL使用方式
- 在IDEA中开发,打成jar包运行:类似于SparkCore开发
- 工作中比较常用的方式
- 通过spark-sql来运行SQL文件
- 一般用于调度系统,常用的方式
- 使用Spark-SQL的命令行来测试SQL语句的运行
- 一般用于测试开发阶段,用的比较少
- 使用SparkSQL的服务端ThriftServer,通过beeline连接
- 一般用于测试开发
- 使用JDBC连接ThriftServer
- 封装计算接口
- 在IDEA中开发,打成jar包运行:类似于SparkCore开发
-
-
问题
-
rdd的血脉信息保存在哪里
-
RDD分区源码有点看不懂,课堂如果时间充裕的话,老师可以再带我们看看源码吗
-
今天将的hiveserver2与ThriftServer端口都是10000,是否会有冲突问题,使用时将服务端分开在两台设备避免端口冲突问题
- HiveServer2:启动在第三台:10000 、 10001
- 创建或者修改元数据的操作:create、drop、alter
- ThriftServer:启动在第一台:10000
- 查询统计类的操作:select
- 补充一点:SparkSQL 与 Hive on Spark的区别
- SparkSQL =》 解析SQL =》 SparkCore
- SparkSQL负责解析
- HiveSQL =》 解析SQL =》 MapReduce/Tez/Spark
- Hive负责解析
- SparkSQL =》 解析SQL =》 SparkCore
- HiveServer2:启动在第三台:10000 、 10001
-
val Array(userId,itemId,rating,timestamp) = line.trim.split("\s+")这句代码有些不太明白 是定义了一个匿名常量,类型为Array,对Array内的数据赋值操作吗?
val Array(userId,itemId,rating,timestamp) = line.trim.split("\\s+") val Array(userId,itemId,_,_) = line.trim.split("\\s+")
-
二、课程目标
-
离线综合练习
- 熟悉SparkCore和SparkSQL的代码开发
- 熟悉实际业务需求中一些规范和细节
-
Streaming流式计算方式
-
实时数据流采集:Flume
-
实时数据存储:Kafka
-
实时数据计算:Streaming
-
实时结果保存:Redis
-
三、离线综合练习需求
1、广告业务需求
- 目标:基于广告的投放效果做分析
- 分析1:统计每个地区用户浏览广告的次数
- 分析2:统计广告投放效果的各个指标和转换率
2、数据内容
-
数据来源:来自于广告投放信息数据和用户访问数据
-
数据内容:整合为一个json数据
- ip:通过ip来解析得到用户所在的省份和城市
-
实现的设计
-
step1:ETL
- 补全地域字段:省份、城市
- 通过IP解析得到
- 将ETL的结果写入Hive表
- 分区表:写入对应的分区,基于T+1做数据的处理和分析
- 补全地域字段:省份、城市
-
step2:基于ETL的结果来实现分析:SQL、DSL
-
读Hive分区表的数据:昨天的数据
-
分析1:统计每个地区用户浏览广告的次数
-
分析2:统计广告投放效果的各个指标和转换率
-
-
四、环境准备
1、应用服务
-
先将三台机器拍个快照
-
将第一台机器恢复快照至:《7、Spark 离线综合实战》
-
启动所有相关服务
# Start HDFS hadoop-daemon.sh start namenode hadoop-daemon.sh start datanode # Start YARN yarn-daemon.sh start resourcemanager yarn-daemon.sh start nodemanager # Start MRHistoryServer mr-jobhistory-daemon.sh start historyserver # Start Spark HistoryServer /export/server/spark/sbin/start-history-server.sh # Start Hue hue-daemon.sh start # Start HiveMetaStore 和 HiveServer2 hive-daemon.sh metastore # Start Spark JDBC/ODBC ThriftServer /export/server/spark/sbin/start-thriftserver.sh \ --hiveconf hive.server2.thrift.port=10000 \ --hiveconf hive.server2.thrift.bind.host=node1.it.cn \ --master local[2] # Start Beeline /export/server/spark/bin/beeline -u jdbc:hive2://node1.it.cn:10000 -n root -p 123456
2、开发环境
-
新建一个模块,引入Maven依赖《参考附录一》
-
创建包结构
- config:放配置文件的解析工具类
- etl:放ETL的代码
- report:放数据分析的代码
- utils:工具类
- 日期工具类
- IP解析工具类
- ……
3、配置管理工具类
-
需求:将所有属性的配置放入配置文件
-
解析工具类:解析配置文件获取属性的值
4、SparkSession工具类
-
需求:针对于本地模式和集群模式、是否集成Hive,不同的情况,来创建SparkSession
package cn.it.spark.utils import cn.it.spark.config.ApplicationConfig import org.apache.spark.internal.Logging import org.apache.spark.sql.SparkSession /** * @ClassName SparkUtils * @Description TODO 提供创建SparkSession的方法 * @Date 2020/12/23 10:55 * @Create By Frank */ object SparkUtils extends Logging{ /** * 用于构建SparkSession对象返回 * @return */ def createSparkSession(clazz:Class[_]):SparkSession = { /** * val spark = SparkSession.builder() * .appName(this.getClass.getSimpleName.stripSuffix("$")) * .master("local[2]") * .getOrCreate() * * 问题1:以后这个代码可能放到Linux集群运行,所以不一定是本地模式 * 问题2:有时候需要集成Hive */ //step1:先构建一个建造者 val builder = SparkSession.builder() //设置程序的名称为调用的类的类名 .appName(clazz.getSimpleName.stripSuffix("$")) //step2:先判断是否是本地模式 if(ApplicationConfig.APP_LOCAL_MODE){ //设置本地master builder.master(ApplicationConfig.APP_SPARK_MASTER)、 //打印INfo级别的日志 logInfo("已开启本地模式") } //step3:判断是否需要集成Hive if(ApplicationConfig.APP_IS_HIVE){ //配置Hive的属性 builder //Metastore服务的地址 .config(ApplicationConfig.APP_HIVE_META_STORE_CONF,ApplicationConfig.APP_HIVE_META_STORE_URLS) //启用Hive的支持 .enableHiveSupport() //打印WARN级别的日志 logWarning("已集成Hive") } //step:返回 builder.getOrCreate() } def main(args: Array[String]): Unit = { val session = createSparkSession(this.getClass) print(session) } }
-
Logging:Spark中使用的日志记录的工具类,我们可以自己继承这个类来实现日志的记录
- 常用方法
- logInfo(日志内容)
- logWarning(日志内容)
- ……
- 常用方法
五、ETL解析实现
1、需求
- 补全地域字段:省份、城市
- 通过IP解析得到
- 将ETL的结果写入Hive表
- 分区表:写入对应的分区,基于T+1做数据的处理和分析
2、解析IP构建地域
-
测试
package bigdata.it.cn.spark.test.ip import cn.it.spark.config.ApplicationConfig import org.lionsoul.ip2region.{ DataBlock, DbConfig, DbSearcher} /** * @ClassName IpAnalaysisTest * @Description TODO 解析IP测试 * @Date 2020/12/23 11:36 * @Create By Frank */ object IpAnalaysisTest { def main(args: Array[String]): Unit = { //step1:先构建解析类的对象:第一个参数是一个配置对象,第二个参数是解析库文件的位置 val dbSearcher = new DbSearcher(new DbConfig(),ApplicationConfig.IPS_DATA_REGION_PATH) //step2:解析IP val dataBlock: DataBlock = dbSearcher.btreeSearch("223.167.137.230") //step3:输出结果 val Array(_,_,province,city,_) = dataBlock.getRegion.split("\\|") println(province+"\t"+city) } }
-
封装工具类
package cn.it.spark.utils import cn.it.spark.config.ApplicationConfig import cn.it.spark.etl.Region import org.lionsoul.ip2region.{ DataBlock, DbConfig, DbSearcher} /** * @ClassName IpUtils * @Description TODO 解析IP的工具类 * @Date 2020/12/23 11:48 * @Create By Frank */ object IpUtils { /** * 用于解析IP,返回Region(ip,省份,城市) * @param ip * @return */ def convertIpToRegion(ip:String,dbSearcher: DbSearcher)