29_spark七—hive

spark内存计算框架

1、sparksql 操作hivesql

  • 添加依赖
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-hive_2.11</artifactId>
            <version>2.3.3</version>
        </dependency>
  • 代码开发
package com.kaikeba.sql
import org.apache.spark.sql.SparkSession


//todo:利用sparksql操作hivesql
object HiveSupport {
  def main(args: Array[String]): Unit = {
    //1、构建SparkSession对象
    val spark: SparkSession = SparkSession.builder()
      .appName("HiveSupport")
      .master("local[2]")
      .enableHiveSupport() //开启对hive的支持
      .getOrCreate()
    //2、直接使用sparkSession去操作hivesql语句

      //2.1 创建一张hive表
       spark.sql("create table people(id string,name string,age int) row format delimited fields terminated by ','")

      //2.2 加载数据到hive表中
       spark.sql("load data local inpath './data/kaikeba.txt' into table people ")

      //2.3 查询
      spark.sql("select * from people").show()

    spark.stop()
  }
}

2、JDBC数据源(★★★★★)

  • spark sql可以通过 JDBC 从关系型数据库中读取数据的方式创建DataFrame,通过对DataFrame一系列的计算后,还可以将数据再写回关系型数据库中

2.1 通过sparksql加载mysql表中的数据

  • 添加mysql连接驱动jar包
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.38</version>
</dependency>
  • 代码开发
package com.kaikeba.sql

import java.util.Properties

import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, SparkSession}

//todo:利用sparksql加载mysql表中的数据
object DataFromMysql {

  def main(args: Array[String]): Unit = {
    //1、创建SparkConf对象
    val sparkConf: SparkConf = new SparkConf().setAppName("DataFromMysql").setMaster("local[2]")

    //2、创建SparkSession对象
    val spark: SparkSession = SparkSession.builder().config(sparkConf).getOrCreate()

    //3、读取mysql表的数据
        //3.1 指定mysql连接地址
        val url="jdbc:mysql://node03:3306/spark"
        //3.2 指定要加载的表名
        val tableName="user"
        // 3.3 配置连接数据库的相关属性
        val properties = new Properties()

      //用户名
      properties.setProperty("user","root")
      //密码
      properties.setProperty("password","123456")

     val mysqlDF: DataFrame = spark.read.jdbc(url,tableName,properties)

      //打印schema信息
      mysqlDF.printSchema()

      //展示数据
      mysqlDF.show()

    //把dataFrame注册成表
    mysqlDF.createTempView("user")

    spark.sql("select * from user where age >30").show()

    spark.stop()
  }
}


2.2 通过sparksql保存结果数据到mysql表中

  • 代码开发(本地运行)
package com.kaikeba.sql

import java.util.Properties

import org.apache.spark.sql.{DataFrame, SparkSession}

//todo:通过sparksql把结果数据写入到mysql表中
object Data2Mysql {
  def main(args: Array[String]): Unit = {
    //1、创建SparkSession
    val spark: SparkSession = SparkSession
                                .builder()
                                .appName("Data2Mysql")
                                .master("local[2]")
                                .getOrCreate()
    //2、读取mysql表中数据
    //2.1 定义url连接
    val url="jdbc:mysql://node03:3306/spark"
    //2.2 定义表名
    val table="user"
    //2.3 定义属性
    val properties=new Properties()
    properties.setProperty("user","root")
    properties.setProperty("password","123456")

    val mysqlDF: DataFrame = spark.read.jdbc(url,table,properties)

    //把dataFrame注册成一张表
      mysqlDF.createTempView("user")

    //通过sparkSession调用sql方法
       //需要统计经度和维度出现的人口总数大于1000的记录 保存到mysql表中
      val result: DataFrame = spark.sql("select * from user where age > 30")

    //保存结果数据到mysql表中
     //mode:指定数据的插入模式
        //overwrite: 表示覆盖,如果表不存在,事先帮我们创建
        //append   :表示追加, 如果表不存在,事先帮我们创建
        //ignore   :表示忽略,如果表事先存在,就不进行任何操作
        //error    :如果表事先存在就报错(默认选项)
    result.write.mode("append").jdbc(url,"kaikeba",properties)
    // result.write.mode(args(0)).jdbc(url,args(1),properties)

    //关闭
     spark.stop()
  }
}

  • 打成jar包集群提交

    • 代码开发

      package com.kaikeba.sql
      
      import java.util.Properties
      
      import org.apache.spark.sql.{DataFrame, SparkSession}
      
      //todo:通过sparksql把结果数据写入到mysql表中
      object Data2Mysql {
        def main(args: Array[String]): Unit = {
          //1、创建SparkSession
          val spark: SparkSession = SparkSession
                                      .builder()
                                      .appName("Data2Mysql") 
                                      .getOrCreate()
            
          //2、读取mysql表中数据
              //2.1 定义url连接
              val url="jdbc:mysql://node03:3306/spark"
              //2.2 定义表名
              val table="user"
              //2.3 定义属性
              val properties=new Properties()
              properties.setProperty("user","root")
              properties.setProperty("password","123456")
      
          val mysqlDF: DataFrame = spark.read.jdbc(url,table,properties)
      
          //把dataFrame注册成一张表
            mysqlDF.createTempView("user")
      
          //通过sparkSession调用sql方法
             //需要统计经度和维度出现的人口总数大于1000的记录 保存到mysql表中
          val result: DataFrame = spark.sql("select * from user where age >30")
      
          //保存结果数据到mysql表中
          //mode:指定数据的插入模式
              //overwrite: 表示覆盖,如果表不存在,事先帮我们创建
              //append   :表示追加, 如果表不存在,事先帮我们创建
              //ignore   :表示忽略,如果表事先存在,就不进行任何操作
              //error    :如果表事先存在就报错(默认选项)
        
           result.write.mode(args(0)).jdbc(url,args(1),properties)
      
          //关闭
           spark.stop()
        }
      }
      
    • 提交任务脚本

      spark-submit \
      --master spark://node01:7077 \
      --class com.kaikeba.sql.Data2Mysql \
      --executor-memory 1g \
      --total-executor-cores 4 \
      --driver-class-path /home/hadoop/mysql-connector-java-5.1.38.jar \
      --jars /home/hadoop/mysql-connector-java-5.1.38.jar \
      spark_class02-1.0-SNAPSHOT.jar \
      append  kaikeba
      

3. sparksql保存数据操作

  • 代码开发
package com.kaikeba.sql

import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, SparkSession}

//todo:sparksql可以把结果数据保存到不同的外部存储介质中
object SaveResult {

  def main(args: Array[String]): Unit = {
    //1、创建SparkConf对象
    val sparkConf: SparkConf = new SparkConf().setAppName("SaveResult").setMaster("local[2]")

    //2、创建SparkSession对象
    val spark: SparkSession = SparkSession.builder().config(sparkConf).getOrCreate()

    //3、加载数据源
    val jsonDF: DataFrame = spark.read.json("E:\\data\\score.json")

    //4、把DataFrame注册成表
    jsonDF.createTempView("t_score")

    //todo:5、统计分析
    val result: DataFrame = spark.sql("select * from t_score where score > 80")

    //保存结果数据到不同的外部存储介质中
    //todo: 5.1 保存结果数据到文本文件  ----  保存数据成文本文件目前只支持单个字段,不支持多个字段
    result.select("name").write.text("./data/result/123.txt")

    //todo: 5.2 保存结果数据到json文件
    result.write.json("./data/json")

    //todo: 5.3 保存结果数据到parquet文件
    result.write.parquet("./data/parquet")

    //todo: 5.4 save方法保存结果数据,默认的数据格式就是parquet
    result.write.save("./data/save")

    //todo: 5.5 保存结果数据到csv文件
    result.write.csv("./data/csv")

    //todo: 5.6 保存结果数据到表中
    result.write.saveAsTable("t1")

    //todo: 5.7  按照单个字段进行分区 分目录进行存储
    result.write.partitionBy("classNum").json("./data/partitions")

    //todo: 5.8  按照多个字段进行分区 分目录进行存储
    result.write.partitionBy("classNum","name").json("./data/numPartitions")


    spark.stop()
  }

}


4. 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()
    
      }
    }
    
    
    

5. 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"

6. 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()
        }
      }
      
      
发布了70 篇原创文章 · 获赞 25 · 访问量 6373

猜你喜欢

转载自blog.csdn.net/TU_JCN/article/details/103761050
今日推荐