mapreduce不适用迭代的计算:数据挖掘,机器学习
hadoop早期版本架构
mapreduce缺点
spark 和 yarn 结合
所以yarn非常重要
spark standalone模式
这种模式只要配置master和worker的节点各自在哪里即可
1.配置文件的路径 /opt/install/spark-standalone/conf
2.mv spark-env.sh.template spark-env.sh
3.vim spark-env.sh
SPARK_MASTER_HOST=sunyjhost
PARK_MASTER_PORT=7077
4. mv slaves.template slaves
5. vim slaves
sunyjhost
sunyjhost2
sunyjhost3
6. 分发配置
scp -r spark-standalone/ sunyjhost:/opt/install/
7.启动集群
./sbin/start-all.sh
8.提供了一个ui界面可以访问spark启动的页面
master:sunyjhost:8080
worker:sunyjhost:8081,sunyjhost2:8081,sunyjhost3:8081
webui
standalone模式下提交spark任务
[sunyj@sunyjhost spark-standalone]$ ./bin/spark-submit \
> --master spark://sunyjhost:7077 \
> --class org.apache.spark.examples.SparkPi \
> ./examples/jars/spark-examples_2.11-2.1.1.jar 1000
deploy-mode 可以为 cluster or client 代表driver运行的位置 cluster:driver运行在集群的节点上
[sunyj@sunyjhost spark-standalone]$ ./bin/spark-submit \
> --master spark://sunyjhost:7077 \
> --deploy-mode cluster \
> --class org.apache.spark.examples.SparkPi \
> ./examples/jars/spark-examples_2.11-2.1.1.jar 1000
driverui:只有程序run的时候才能看到driverui
spark配置历史服务器
1.在hadoop上创建一个目录,用于保存spark运行日志信息
hdfs dfs -mkdir -p /spark/historylog
2. 配置spark-defaults.conf ,使spark history server从此目录下读取信息
mv spark-defaults.conf.template spark-defaults.conf
vim spark-defaults.conf
spark.eventLog.enabled true --开启日志
spark.eventLog.dir hdfs://mycluster/spark/historylog --日志存储位置hdfs中
3.配置spark-env.sh
vim spark-env.sh
export SPARK_HISTORY_OPTS="-Dspark.history.retainedApplications=2 -Dspark.history.fs.logDirectory=hdfs://mycluster/spark/historylog -Dspark.history.ui.port=18080"
export HADOOP_CONF_DIR=/opt/install/hadoop-2.7.2/etc/hadoop
4.分发配置
5.启动历史服务器
./sbin/start-history-server.sh
配置项: spark.history.retainedApplications spark.history.fs.logDirectory:配置了该属性后,在start-history-server.sh时就无需再显式的指定路径,Spark History Server页面只展示该指定路径下的信息 spark.history.ui.port:历史服务器端口
如果不暴露HADOOP_CONF_DIR的配置地址,会报如下错误
删除日志 但是我没有验证
spark HA
配置spark-env.sh即可 然后分发配置 ./sbin/start-master.sh 需要单独启动master集群模式
// 集群模式需要将master地址的配置注释掉
#SPARK_MASTER_HOST=sunyjhost
#PARK_MASTER_PORT=7077
export SPARK_HISTORY_OPTS="-Dspark.history.retainedApplications=2 -Dspark.history.fs.logDirectory=hdfs://mycluster/spark/historylog -Dspark.history.ui.port=18080"
export HADOOP_CONF_DIR=/opt/install/hadoop-2.7.2/etc/hadoop
配置zk集群模式 锁的节点 以及zk集群的地址
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=sunyjhost:2181,sunyjhost2:2181,sunyjhost4:2181 -Dspark.deploy.zookeeper.dir=/spark"
spark on yarn
不需要额外的spark集群
配置: yarn-site.xml
<property>
<name>yarn.nodemanager.pmem-check-enabled</name>
<value>false</value>
</property>
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
在原来的yarn上增加了如上的配置,因为我的虚拟机内存少 所以将内存检查关闭,防止内存超出限制,将进程杀死, hadoop集群的配置就做这么点修改即可,然后分发配置
spark-env.sh
YARN_CONF_DIR=/opt/install/hadoop-2.7.2/etc/hadoop
因为我们要讲spark程序提交到yarn集群,所以要配置hadoop的环境
spark_yarn 历史配置
spark-defaults.conf
spark.eventLog.enabled true
spark.eventLog.dir hdfs://mycluster/spark/historylog-yarn
spark-env.sh
HADOOP_CONF_DIR=/opt/install/hadoop-2.7.2/etc/hadoop
export SPARK_HISTORY_OPTS="-Dspark.history.retainedApplications=2 -Dspark.history.fs.logDirectory=hdfs://mycluster/spark/historylog-yarn -Dspark.history.ui.port=18080"
为了从yarn上关联spark的历史服务器,需要增加如下配置 spark-defaults.conf
spark.yarn.historyServer.address=sunyjhost:18080
spark.history.ui.port=18080
提交任务
./bin/spark-submit --master yarn --class org.apache.spark.examples.SparkPi ./examples/jars/spark-examples_2.11-2.1.1.jar 1
配置yarn历史
yarn-site.xml
<property>
<name>yarn.log.server.url</name>
<value>http://sunyjhost2:19888/jobhistory/logs</value>
</property>
RDD
RDD 弹性分布式数据集,对这个数据集提供一些列算子(方法),对数据集进行处理。
算子:转换算子和行动算子
RDD创建的方式
从集合中创建: parallelize,makeRDD makeRDD底层调用的还是parallelize
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("sparkcoretest").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
//创建一个集合 。数据保存在内存中
val list: List[Int] = List(1, 2, 3, 4)
//根据集合创建RDD方式1 parallelize
val rdd: RDD[Int] = sc.parallelize(list)
val result: Array[Int] = rdd.collect()
result.foreach(println)
sc.stop()
}
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("sparkcoretest").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
//创建一个集合 。数据保存在内存中
val list: List[Int] = List(1, 2, 3, 4)
//根据集合创建RDD方式2 makeRDD
val rdd: RDD[Int] = sc.makeRDD(list)
val result: Array[Int] = rdd.collect()
result.foreach(println)
sc.stop()
}
从外部文件创建RDD
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("sparkcoretest").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
// 读取每一行,将每一行内容“放到”RDD 读取本地文件系统
val lineRDD:RDD[String] = sc.textFile("F:\\2020study\\spark-study\\in\\word.txt")
lineRDD.collect().foreach(println)
sc.stop()
}
执行结果
读取hdfs文件创建RDD
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("sparkcoretest").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
sc.hadoopConfiguration.set("fs.defaultFS", "hdfs://mycluster")
sc.hadoopConfiguration.set("dfs.nameservices", "mycluster")
sc.hadoopConfiguration.set("dfs.ha.namenodes.mycluster", "nn1,nn2")
sc.hadoopConfiguration.set("dfs.namenode.rpc-address.mycluster.nn1", "sunyjhost:8020")
sc.hadoopConfiguration.set("dfs.namenode.rpc-address.mycluster.nn2", "sunyjhost2:8020")
sc.hadoopConfiguration.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider")
// 读取每一行,将每一行内容“放到”RDD
val lineRDD:RDD[String] = sc.textFile("hdfs://mycluster/wcinput")
lineRDD.collect().foreach(println)
sc.stop()
}
RDD数据集 分区
在spark中切片数和分区数是一样的概念
切片:切片大小 偏移量 所在节点等信息
transformation 转换算子
RDD整体分为value型,双value型,key-value型
value类型
map算子:
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
// 对rdd进行映射 元数据乘2
//val rdd2: RDD[Int] = rdd.map((a: Int) => a * 2)
//简化写法
val rdd2: RDD[Int] = rdd.map((a) => a * 2)
val rdd3: RDD[Int] = rdd.map(a => a * 2)
val rdd4: RDD[Int] = rdd.map(_ * 2)
}
mapPartitions算子
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
println(rdd.partitions.length)
val newRdd: RDD[Int] = rdd.mapPartitions((datas: Iterator[Int]) => datas.map(_ * 2))
println(newRdd.partitions.length)
}
mapPartitionsWithIndex 算子 带分区号
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8), 3)
// index 分区编号
val newRDD: RDD[(Int, Int)] = rdd.mapPartitionsWithIndex((index, datas) => {
datas.map(data => (index, data))
})
//简化写法
val newRDD2: RDD[(Int, Int)] = rdd.mapPartitionsWithIndex((index, datas) => {
datas.map(data => (index, data))
})
//简化写法
val newRDD3: RDD[(Int, Int)] = rdd.mapPartitionsWithIndex((index, datas) => {
datas.map((index, _))
})
newRDD.collect().foreach(println)
}
输出结果:
flatmap 算子
rdd 压平
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
// 集合中含有集合
val rdd: RDD[List[Int]] = sc.makeRDD(List(List(1, 2), List(3, 4), List(5, 6), List(7)), 2)
val newRdd: RDD[Int] = rdd.flatMap(datas => datas)
}
glom 算子
将分区中的数据转化为数组
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
// glom 将rdd中的每个分区的元素 转化为数组
val arrayRdd: RDD[Array[Int]] = rdd.glom()
//取出数组中的最大值
val maxRdd: RDD[Int] = arrayRdd.map(_.max)
println(maxRdd.collect().sum)
}
group by
将rdd中的元素按照一定的规则进行分组,
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4 , 5, 6,7,8,9), 2)
// 将 rdd中的元素按照一定的规则进行分组 分3组,对3进行取模%3
//返回的rdd是一个元祖 第一个元素是组的key 第二个元素是在这个组的所有元素的集合
// group by 接受一个函数作为参数,这个函数的返回结果作为分组的条件
val groupRdd: RDD[(Int, Iterable[Int])] = rdd.groupBy(_ % 3)
}
filter 算子
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4 , 5, 6, 7, 8, 9), 2)
// 不简化
val filterRDD1: RDD[Int] = rdd.filter(elem => elem % 2 != 0)
val filterRDD: RDD[Int] = rdd.filter(_ % 2 != 0)
filterRDD.collect().foreach(println)
}
sample 算子 和takeSample 采样
distinct 去重算子
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4 ,3, 6, 2, 5, 2, 0), 4)
rdd.mapPartitionsWithIndex{
(index,datas)=>{
println(index + ":::" +datas.mkString(" "))
datas
}
}.collect()
println("去重后,重新指定分区")
val distinctRDD: RDD[Int] = rdd.distinct(2)
distinctRDD.mapPartitionsWithIndex{
(index,datas)=>{
println(index + ":::" +datas.mkString(" "))
datas
}
}.collect()
}
coalesce算子和repartition算子 重新分区
repartition底层调用的是 coalesce
sortby 排序算子
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4 ,3, 6, 2, 5, 2, 0), 4)
val sortbyRDD: RDD[Int] = rdd.sortBy(num => num)
sortbyRDD.collect().foreach(println)
val sortbyRDD2: RDD[Int] = rdd.sortBy(num => num,false)
sortbyRDD2.collect().foreach(println)
}
双value类型
合集
差集
交集
拉链
拉链的前提
key-value类型
partitionBy
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val rdd: RDD[(Int, String)] = sc.makeRDD(List((1, "aaa"), (2, "bbb"), (3, "ccc"), (4, "ddd")), 3)
val partionRDD: RDD[(Int, String)] = rdd.partitionBy(new HashPartitioner(2))
partionRDD.mapPartitionsWithIndex{
(index,datas)=>{
println(index + ":::" +datas.mkString(" "))
datas
}
}.collect()
}
也可以自定义分区逻辑 上面使用的是hashPartitioner
class MyPartitioner(partitions:Int) extends Partitioner{
override def numPartitions: Int = partitions
override def getPartition(key: Any): Int = {
// 分区业务逻辑
if (key.isInstanceOf[String]){
val k: String = key.asInstanceOf[String]
if (k.startsWith("135")){
0
}else if(k.startsWith("136")){
1
}else{
2
}
} else {
9
}
}
}
reduceByKey
groupByKey
aggregateByKey
foldByKey
combineByKey
四种聚合运算底层调用的是相同的算子
sortByKey
mapValues
只对value进行映射
join 算子
如果key 只是某一个RDD有 则不会关联上
注意调用顺序
cogroup 算子
WORDCOUT
方案1
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val strList: List[String] = List("Hello Scala", "Hello Spark", "Hello World")
val rdd: RDD[String] = sc.makeRDD(strList)
val flatMapRdd: RDD[String] = rdd.flatMap(_.split(" "))
val mapRdd: RDD[(String, Int)] = flatMapRdd.map((_, 1))
//将相同的单词放到一组,所以按照元祖的第一个元素进行分组
val groupByRDD: RDD[(String, Iterable[(String, Int)])] = mapRdd.groupBy(_._1)
val finalRdd: RDD[(String, Int)] = groupByRDD.map {
case (word, datas) => {
(word, datas.size)
}
}
finalRdd.collect().foreach(println)
}
方案2
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
val strList: List[String] = List("Hello Scala", "Hello Spark", "Hello World")
val rdd: RDD[String] = sc.makeRDD(strList)
val flatMapRdd: RDD[String] = rdd.flatMap(_.split(" "))
val groupbyRDD: RDD[(String, Iterable[String])] = flatMapRdd.groupBy(word => word)
val finalRdd: RDD[(String, Int)] = groupbyRDD.map {
case (word, datas) => {
(word, datas.size)
}
}
finalRdd.collect().foreach(println)
}
WORDCOUNT 复杂
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("map").set("spark.testing.memory", "2147480000")
val sc: SparkContext = new SparkContext(conf)
// RDD中的元素是元组
val rdd: RDD[(String, Int)] = sc.makeRDD(List(("Hello Scala", 2), ("Hello Spark", 3), ("Hello World", 2)))
// 方式1
val mapRDD: RDD[String] = rdd.map(tup => {
(tup._1 + " ") * tup._2
})
// 方式2 模式匹配
rdd.map{
case (words,count) =>{
(words + " ") * count
}
}
// 方案2 模式匹配的話就得使用{} 不能使用()
// ("Hello Scala", 2) 轉化成(Hello,2) (Scala,2)
val flatRDD: RDD[(String, Int)] = rdd.flatMap {
case (words, count) => {
words.split(" ").map((_, count))
}
}
val groupbyADD: RDD[(String, Iterable[(String, Int)])] = flatRDD.groupBy(_._1)
val finalRDD: RDD[(String, Int)] = groupbyADD.map {
case (word, datas) => {
(word, datas.map(_._2).sum)
}
}
}
求学生的平均成绩
方案1
方案2
方案3
topN
模式匹配用的6
隐式转换用的6
行动算子
行动算子触发job执行