day73 Spark - sql


I know, i know
地球另一端有你陪我




一、Spark 执行方式


1、spark-submit

package test

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

object Demo6Submit {
  def main(args: Array[String]): Unit = {

    val spark: SparkSession = SparkSession
      .builder()
      .appName("submit")
      .config("spark.sql.shuffle.partitions", 1)
      .getOrCreate()

    import org.apache.spark.sql.functions._
    import spark.implicits._

    /**
      * 读取hdfs中的数据
      *
      */

    val student: DataFrame = spark
      .read
      .format("csv")
      .option("sep", ",")
      .schema("id STRING,name STRING, age INT, gender STriNG ,clazz STRING")
      .load("/data/student/")


    //处理数据
    val clazzNum: DataFrame = student
      .groupBy($"clazz")
      .agg(count($"id") as "sum_num")


    /**
      * 保存数
      *
      */

    clazzNum
      .write
      .format("csv")
      .option("sep", ",")
      .save("/data/clazz_num")


    /**
      * 提交任务
      * spark-submit --master yarn-client --num-executors 1 --executor-cores 1 --executor-memory 1G --class sql.Demo6Submit Spark-1.0-SNAPSHOT.jar
      *
      *
      * spark-submit --master yarn-client --class sql.Demo6Submit Spark-1.0-SNAPSHOT.jar
      *
      *
      * 查看结果
      * hadoop dfs -cat /data/clazz_num/
      */
  }
}

2、spark shell

repl(read、execute、print、loop)

spark-shell --master yarn-client

不能使用yarn-cluster,因为 Driver 必须再本地启动


3、spark-sql

spark-sql --master yarn-client

由于 hive 早于 spark 诞生,所以很多时候需要数据上的兼容
因此可以通过修改配置整合使用 hive 中的表

1、在hive的hive-site.xml修改一行配置,增加了这一行配置之后,
      以后在使用hive之前都需要先启动元数据服务
      metastore 元数据

<property>
<name>hive.metastore.uris</name>
<value>thrift://master:9083</value>
</property>

2、启动 hive 元数据服务

nohup  hive --service metastore >> metastore.log 2>&1 &

3、将hive-site.xml 复制到spark conf目录下

 cp hive-site.xml /usr/local/soft/spark-2.4.5/conf/

4、 将 mysql 驱动包复制到saprk jars目录下
      hive 的 lib 目录里面应该有一个

cp mysql-connector-java-5.1.47.jar /usr/local/soft/spark-2.4.5/jars/

之后就可以在 spark-sql 中使用 hive 的数据了,但是依然不能使用 cluster 模式
spark-sql 中的shuffle 后分区数量依然是默认 200

// 这是在启动时设置 shuffle 后分区数量的方式
spark-sql --master yarn-client --conf spark.sql.shuffle.partitions=2

如果启动时忘记设置,进入后也可以补救

set spark.sql.shuffle.partitions=1;

此时,Spark-sql 中的数据和 hive 中的数据就已经互通了

create table student
(
id  string,
name string,
age int,
gender string,
clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS textfile
location '/Spark/data/student/';

create table score
(
student_id  string,
cource_id string,
sco int
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS textfile
location '/Spark/data/score/';

统计班级人数

select clazz,count(1) from student group by clazz;

二、散碎

1、外部链接到 hive 库

通过 jdbc 链接

package sql

import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, Row, SaveMode, SparkSession}

object Demo7Hive {

  def main(args: Array[String]): Unit = {

    val spark: SparkSession = SparkSession
      .builder()
      .appName("Demo7Hive")
      .config("spark.sql.shuffle.partitions", 1)
      .enableHiveSupport()
      .getOrCreate()


    import org.apache.spark.sql.functions._
    import spark.implicits._

    // 通过表名获得一个DF
    val stu: DataFrame = spark.table("student")


    // SQL
    spark
      .sql(
        """
          |select clazz,count(1) from student group by clazz
        """.stripMargin)


    // DSL
    val test: DataFrame = stu
      .groupBy("clazz")
      .agg(count($"id"))

    test
      .write
      .format("csv")
      .mode(SaveMode.Overwrite)
      .save("/Spark/data/output")


    // 将DF 转换成RDD;
    val rdd: RDD[Row] = stu.rdd

    rdd.map(row =>{
      val age = row.getAs[Int]("age")
      age
    })

    rdd.map{
      case Row(id: String, name: String, age: Int, gender: String, clazz: String)=>{
        (id, name, age, gender, clazz)
      }
    }
  }
}

2、Spark 中的 Map Join(小表广播)

通过 broadcast,需要用到 hive 中的注解
可以避免 shuffle

package sql

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

object Demo9MapJoin {

  def main(args: Array[String]): Unit = {

    val spark = SparkSession
      .builder()
      .appName("Demo9MapJoin")
      .master("local")
      .config("spark.sql.shuffle.partitions", 1)
      .getOrCreate()

    import spark.implicits._
    import org.apache.spark.sql.functions._

    val stu: DataFrame = spark
      .read
      .format("json")
      .load("Spark/data/students.json")

    val sco = spark
      .read
      .format("csv")
      .schema("student_id  STRING, cou_id STRING,sco INT")
      .load("Spark/data/score.txt")

    sco
      .join(stu.hint("broadcast"),$"student_id" === $"id")
      .show()
  }
}

3、PageRank

PageRank是Google专有的算法,用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度。

是Google创始人拉里·佩奇和谢尔盖·布林于1997年创造的。

PageRank实现了将链接价值概念作为排名因素。
在这里插入图片描述
转换为这样的链接

	A-B,D
	B-C
	C-A,B
	D-B,C

第一次为每个网站设置一个初始值为 1
接着将该初始值均分给每一个链接网页
反复执行,最终每个网页的值会收敛,得到一个几乎确定的值

package sql

import org.apache.spark.{SparkConf, SparkContext}

object PageRank {

  def main(args: Array[String]): Unit = {

    val conf = new SparkConf()
      .setMaster("local")
      .setAppName("PageRank")

    val sc: SparkContext = new SparkContext(conf)

    val data = sc
      .textFile("Spark/data/pagerank.txt")

    // 此处构建网页的方向信息
    // 需要是一个map格式,因为后面需要join
    val pageLink = data.map(line => {
      val page = line.split("-")(0)

      val linked = line.split("-")(1).split(",").toList

      (page, linked)
    })

    pageLink.cache()

    // 计算网页数量
    val size: Long = pageLink.count()

    // 阻尼系数,减少黑洞网页的分散值
    val q = 0.85

    // 分配初始值
    // 1.0 是因为之后需要用到浮点数
    var pageLinkVal = pageLink.map(kv => {
      (kv._1, kv._2, 1.0)
    })

    var flag = true

    while (flag) {

      /**
        * 将每一个网页pr值平分给他的出链列表
        *
        * List((B,0.5), (D,0.5))
        * List((C,1.0))
        * List((A,0.5), (B,0.5))
        * List((B,0.5), (C,0.5))
        *
        */

      // 将网页的权值进行分散
      val avgPage = pageLinkVal.map {

        case (page, linked, pr) => {

          val avg = pr / linked.length

          linked.map(p => (p, avg))
        }
      }

      /**
        * 把数据展开
        * (B,0.5)
        * (D,0.5)
        * (C,1.0)
        * (A,0.5)
        * (B,0.5)
        * (B,0.5)
        * (C,0.5)
        *
        */
      val flatAvgPage = avgPage.flatMap(x => x)


      /**
        * 计算每一个网页新的pr值
        * (B,1.5)
        * (A,0.5)
        * (C,1.5)
        * (D,0.5)
        *
        */
      val newPage = flatAvgPage.reduceByKey(_ + _)

      /**
        * 关联出链列表
        *
        */

      val joinPage = newPage.join(pageLink)

      //整理数据,
      val newPagevalue = joinPage.map {

        case (page, (value, linked)) =>
          (page, linked, (1 - q) / size + q * value)
      }

      val newkv = newPagevalue.map(kv =>
        (kv._1, kv._3)
      )

      val oldkv = pageLinkVal.map(kv =>
        (kv._1, kv._3)
      )

      val diff = newkv
        .join(oldkv)
        .map {
          case (page, (v1, v2)) =>
            Math.abs(v1 - v2)
        }
        .sum() / size

      if (diff < 0.0001) {
        flag = false
      }

      pageLinkVal = newPagevalue

    }
    pageLinkVal.foreach(println)
  }
}

零碎

spark-sql 本地模式下,使用的是当前服务器的资源,元数据存在打开的当前目录

多个 task 空跑,不会生成多余的空文件

spark - shell 和 spark-sql 都不能使用 yarn-cluster 启动

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值