文章目录
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 启动