大数据-SparkSQL(五)
sparksql中自定义函数
自定义UDF函数
代码开发
package com.kaikeba.sql
import org.apache.spark.sql.api.java.UDF1
import org.apache.spark.sql.types.StringType
import org.apache.spark.sql.{DataFrame, SparkSession}
//TODO:自定义sparksql的UDF函数 一对一的关系
object SparkSQLFunction {
def main(args: Array[String]): Unit = {
//1、创建SparkSession
val sparkSession: SparkSession = SparkSession.builder().appName("SparkSQLFunction").master("local[2]").getOrCreate()
//2、构建数据源生成DataFrame
val dataFrame: DataFrame = sparkSession.read.text("E:\\data\\test_udf_data.txt")
//3、注册成表
dataFrame.createTempView("t_udf")
//4、实现自定义的UDF函数
//小写转大写
sparkSession.udf.register("low2Up",new UDF1[String,String]() {
override def call(t1: String): String = {
t1.toUpperCase
}
},StringType)
//大写转小写
sparkSession.udf.register("up2low",(x:String)=>x.toLowerCase)
//4、把数据文件中的单词统一转换成大小写
sparkSession.sql("select value from t_udf").show()
sparkSession.sql("select low2Up(value) from t_udf").show()
sparkSession.sql("select up2low(value) from t_udf").show()
sparkSession.stop()
}
}
sparksql整合hive
步骤
- 1、需要把hive安装目录下的配置文件hive-site.xml拷贝到每一个spark安装目录下对应的conf文件夹中
- 2、需要一个连接mysql驱动的jar包拷贝到spark安装目录下对应的jars文件夹中
- 3、可以使用spark-sql脚本 后期执行sql相关的任务
启动脚本
spark-sql \
--master spark://node01:7077 \
--executor-memory 1g \
--total-executor-cores 4 \
--conf spark.sql.warehouse.dir=hdfs://node01:8020/user/hive/warehouse
应用场景
#!/bin/sh
#定义sparksql提交脚本的头信息
SUBMITINFO="spark-sql --master spark://node01:7077 --executor-memory 1g --total-executor-cores 4 --conf spark.sql.warehouse.dir=hdfs://node01:8020/user/hive/warehouse"
#定义一个sql语句
SQL="select * from default.hive_source;"
#执行sql语句 类似于 hive -e sql语句
echo "$SUBMITINFO"
echo "$SQL"
$SUBMITINFO -e "$SQL"
sparksql处理点击流日志数据案例
需求描述
通过sparksql对用户访问产生点击流日志数据进行分析处理,计算出对应的指标。
代码开发
(1)校验日志数据进行字段解析提取的工具类
AccessLogUtils
package com.kaikeba.sql.applog
import scala.util.matching.Regex
case class AccessLog(
ipAddress: String, // IP地址
clientId: String, // 客户端唯一标识符
userId: String, // 用户唯一标识符
serverTime: String, // 服务器时间
method: String, // 请求类型/方式
endpoint: String, // 请求的资源
protocol: String, // 请求的协议名称
responseCode: Int, // 请求返回值:比如:200、401
contentSize: Long, // 返回的结果数据大小
url:String, //访问的url地址
clientBrowser:String //客户端游览器信息
)
/**
* 校验日志数据进行字段解析提取的工具类
*/
object AccessLogUtils {
val regex: Regex =
"""^(\S+) (\S+) (\S+) \[([\w:/]+\s[+\-]\d{4})\] "(\S+) (\S+) (\S+)" (\d{3}) (\d+) (\S+) (.*)""".r
/**
* 验证一下输入的数据是否符合给定的日志正则,如果符合返回true;否则返回false
*
* @param line
* @return
*/
def isValidateLogLine(line: String): Boolean = {
val options = regex.findFirstMatchIn(line)
if (options.isEmpty) {
false
} else {
true
}
}
/**
* 解析输入的日志数据
*
* @param line
* @return
*/
def parseLogLine(line: String): AccessLog = {
// 从line中获取匹配的数据
val options = regex.findFirstMatchIn(line)
// 获取matcher
val matcher = options.get
// 构建返回值
AccessLog(
matcher.group(1), // 获取匹配字符串中第一个小括号中的值
matcher.group(2),
matcher.group(3),
matcher.group(4),
matcher.group(5),
matcher.group(6),
matcher.group(7),
matcher.group(8).toInt,
matcher.group(9).toLong,
matcher.group(10),
matcher.group(11)
)
}
}
(2)指标统计
LogAnalysis
package com.kaikeba.sql.applog
import java.util.Properties
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{DataFrame, SparkSession}
/**
* 日志分析案例
*/
object LogAnalysis {
//定义url连接
val url="jdbc:mysql://node03:3306/spark"
//定义属性
val properties=new Properties()
properties.setProperty("user","root")
properties.setProperty("password","123456")
def main(args: Array[String]): Unit = {
//1、构建sparkConf对象
val sparkConf: SparkConf = new SparkConf().setAppName("LogAnalysis").setMaster("local[2]")
//2、构建sparkSession对象
val spark: SparkSession = SparkSession.builder().config(sparkConf).getOrCreate()
//3、获取sparkContext对象
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("warn")
//4、读取数据文件
val logRDD: RDD[String] = sc.textFile("./logs/access.log")
//5、过滤脏数据,然后解析
val rightRDD: RDD[String] = logRDD.filter(line => AccessLogUtils.isValidateLogLine(line))
val accessLogRDD: RDD[AccessLog] = rightRDD.map(line => AccessLogUtils.parseLogLine(line))
//6、将RDD转换成DataFrame
import spark.implicits._
val accessLogDF: DataFrame = accessLogRDD.toDF
//7、将DataFrame注册成一张表
accessLogDF.createTempView("access")
//todo:8、指标分析
//todo:8.1 求contentSize的平均值,最大值以及最小值
val result1 = spark.sql(
"""
|select
|date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),1) as time,
|AVG(contentSize) as avg_contentSize,
|MAX(contentSize) as max_contentSize,
|MIN(contentSize) as min_contentSize
|from access
""".stripMargin)
//展示结果数据
result1.show()
//保存结果数据到mysql表中
//result1.write.jdbc(url,"t_contentSizeInfo",properties)
//todo:8.2 求 pv 和 uv
val result2 = spark.sql(
"""
|select
|date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),1) as time,
|count(*) as pv,
|count(distinct ipAddress) as uv
|from access
""".stripMargin)
//展示结果数据
result2.show()
//保存结果数据到mysql表中
// result2.write.jdbc(url,"t_uv_pv",properties)
//todo:8.3 求各个响应码出现的次数
val result3 = spark.sql(
"""
|select
|date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),1) as time,
|responseCode as code,
|count(*) as count
|from access
|group by responseCode
""".stripMargin)
//展示结果数据
result3.show()
//保存结果数据到mysql表中
//result3.write.jdbc(url,"t_responseCode",properties)
//todo:8.4 求访问url次数最多的前N位
val result4 = spark.sql(
"""
|select
|*,date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),1) as time
|from (
|select
|url as url,
|count(*) as count
|from access
|group by url) t
|order by t.count desc limit 5
""".stripMargin)
//展示结果数据
result4.show()
//保存结果数据到mysql表中
//result4.write.jdbc(url,"t_url",properties)
//todo:8.5 求各个请求方式出现的次数
val result5 = spark.sql(
"""
|select
|date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),1) as time,
|method as method,
|count(*) as count
|from access
|group by method
""".stripMargin)
//展示结果数据
result5.show()
//保存结果数据到mysql表中
//result5.write.jdbc(url,"t_method",properties)
spark.stop()
}
}
此博文仅供学习参考,如有错误欢迎指正。
上一篇《大数据-SparkSQL(四)》
下一篇《大数据-Spark调优(一)》