SPARK学习笔记总结

Hadoop可以完成项目的功能实现,spark是hadoop的功能优化实现,spark使用的内存基于内存进行计算,一个jar包中有很多任务,特点是:迭代式计算(后一个job依赖前一个job记过)和交互式数据挖掘(shell)。
spark被看成是一整套的大数据处理的通用处理引擎,是一套大数据的处理方案一个大的软件栈,在各个方面都可以基于此进行实现

spark中的角色:
集群中的角色:

master是集群中的管理节点,worker是在正式工作的节点。master是集群中的资源管理,worker是管理自己的资源的。

程序运行中的角色:

每一个spark项目由一个驱动器程序执行其中的main函数,驱动器程序的工作包括:
将程序分成若干任务,对执行器进行跟踪和调度,创建sparkContext(可以看成是和集群的一个连接,在shell中是一个sc对象,编程时候通过conf对象来生成);
执行器是运行在工作节点的进程,负责真正的作业工作并返回相应的结果,RDD是缓存在执行器进程中的。
driver和executor是对于当前这个程序而言的,程序执行完成那么这对角色也没有了,master和worker则是集群的机器角色。
驱动器程序和执行器程序之间通过集群资源调度管理器(内存和核心),常见的模式有Local只有本身自己一台机器,local-cluster伪分布相似的一台机器多个进程,standalone(master和workers存在于这种模式下的真正的集群模式),yarn,Mesos(专业的集群管理者)等

spark项目的提交方式:

spark-submit的总的格式是 :
spark-submit [options] <app jar | python file > [app options]

options的一些参数:

–class: 你的应用的启动类 (如 org.apache.spark.examples.SparkPi)
–master: 集群的master URL (如 spark://192.168.9.102:7077)
–deploy-mode: 是否发布你的驱动到worker节点(cluster) 或者作为一个本地客户端 (client) (default: client)*
–name 应用的显示名,会在网页中显示
–jars需要上传并放在CLASSPATH中的第三方应用jar,少量的jar可以这么做
–files 需要放到应用工作目录中的文件的列表,分发到各个节点的数据文件
–conf: 任意的Spark配置属性, 格式key=value. 如果值包含空格,可以加引号“key=value”. 缺省的Spark配置 application-jar: 打包好的应用jar,包含依赖. 这个URL在集群中全局可见。 比如hdfs:// 共享存储系统, 如果是 file:// path, 那么所有的节点的path都包含同样的jar.
application-arguments: 传给main()方法的参数
例如:

bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://hadoop102:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.1.1.jar  100
master参数的例子:
  • local 本地单线程的跑

  • local[K] 本地k个线程跑

  • spark://HOST:PORT 独立集群standalone中的master

  • mesos://HOST:PORT连接到指定的Mesos集群

  • yarn-client 作为客户端连接到YARN cluster,集群位置由HADOOP_CONF_DIR指定

  • yarn-cluster:以cluster形式连接到YARN cluster,集群位置由HADOOP_CONF_DIR指定,两者差别在driver的运行 位置在哪里。client在提交的机器上,cluster在集群中的一台上。后面的yarn上的可以分开写,master写yarn,deploy-mode写client或者cluster

在运行spark-shell中不指定master的是local[* ],是以本地的模式在运行的。同常测试集群和生产集群两种,端口4040是对当前运行(注意只是当前,历史的查看需要重新配置)application的job状况查看,8080查看集群中的情况,7077是集群提交的端口。

一般spark程序的工作过程:

通过外部数据产生RDD,通过filter这样的转化操作产生新的RDD,通过行动操作触发spark优化后的并行计算,通过persist()实现持久化保存中间的需要进行重用的结果。
RDD操作:行动操作(不产生新的RDD)和转化操作(返回产生的新RDD),filter这个操作虽然产生了新的RDD但是在对旧的RDD来说,在后面的程序中依然可以使用,
创建RDD:通过sc.parallelize产生;通过从外部数据读取(sc.textFile等)
RDD的惰性求值:产生的新的RDD,只有在进行行动操作的时候才会被真正的计算。
由于转化操作的存在,使得RDD之间存在着类似派生的关系,spark使用的系谱图来记录这些RDD之间的关系。常用来进行恢复数据等操作使用

一些重要的RDD操作
普通RDD操作:
  1. 单个RDD的操作:
take(10)  获取指定数目的元素rdd;
filter(x=>x>10) 针对各个元素过滤掉返回值是false的元素;
map(x=>(x,1)) 针对各个元素进行操作;
flatMap(x=>x.split(" ")) 针对各个元素,单个元素可能返回值不止一个,接受所有的返回值作为一个RDD中的元素;
count() 对元素进行计数;
first() 返回第一个元素;
collect() 整个的元素返回驱动器, 消耗巨大;
sample() 对rdd进行取样,结果非确定的;
distinct() 使集合中元素唯一;
reduce((x,y)=>x+y) 对所有的元素进行归约,比如对RDD中所有元素求和;
fold(sum)((x,y)=>x+y),所有元素的归约,但是是存在初始值的;
aggregate((0, 0))( (acc, value) => (acc. _1 + value, acc._2 + 1), (acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2)) val avg = result._1 / result._2.toDouble 分别是初始值(0,0),(acc,value)本地节点运行是遇到value如何操作,(acc1,acc2)在多个累加器之间合并操作;
foreach(x=>x+1) 可以在不返回驱动器的情况下操作每一个元素;
  1. 集合操作:
union(other) 取两个RDD的并集
substract(other) 差集,在前者而不在后者的元素
intersection(other)取两个RDD的交集
cartesian(other) 两个RDD 的笛卡尔积
  1. RDD的持久化

多次重复计算同一个RDD的消耗可以通过持久化的操作减少多次重复计算,持久化有不同的级别,
用法:rdd.persist(StorageLevel.DISK_ONLY),持久化是在将数据存在执行器进程的缓存中的,也可以使用unpersist()解除持久化操作

pairRDD操作:

pairRDD支持所有的普通的RDD的操作,只是在书写时候可以使用
val r3=r2.map(x=>x._1+x._2) val r4=r2.filter{case (x,y) => x>1}
两种。
键值对的RDD可以从普通的RDD转化过来,val pairRdd=r1.map(x=>(x,1))

单个pairRDD 的操作:

reduceByKey((x,y)=>x+y) 对相同key的元素操作
groupBykey() 按照key进行分组
combineByKey() 合并具有相同的key
mapValues() 对所有的values进行相同的操作
flatMapValues()
keys() 获取所有的keys
values() 获取所有的values
sortByKey() 根据key进行排序
lookup(key) 返回给定的键对相应的所有的值
collectAsMap() 结果以映射表的形式返回
countBykey() 对每个键分别计数

针对两个pairRDD的转化操作

subtractBykey() 在key上的差集操作
join() 根据key进行内连接
rightOuterJoin
leftOuterJoin
cogroup 将相同的key进行分组

聚合操作:
reduceByKey((x,y)=>x+y)
combine求key对应的均值val result = input.combineByKey(
 (v) => (v, 1),//新key作v的转化
 (acc: (Int, Int), v) => (acc._1 + v, acc._2 + 1),//已经存在的key对于其v的处理
 (acc1: (Int, Int), acc2: (Int, Int)) => (acc1._1 + acc2._1, acc1._2 + acc2._2) ).map{ case (key, value) => (key, value._1 / value._2.toFloat) }//多个分区之间的合并

数据分区

为了减少数据通信的代价,对于多次访问多次扫描基于Key的多次操作的RDD可以考虑进行分区,首先所有的pairRDD都可以针对Key进行分组,spark所有的共同一组的key(通过某种函数获得相同的结果的key是一组的)的数据出现在同一个分区中。数据分区时候需要充分的考虑后续使用的时候重复计算的部分,比如相对较大的表和较小的表在进行连接时候是通过计算key的哈希值来进行匹配的,此时就可以将大一点的表进行分区,创建新的RDD并持久化,这样在后续的哈希计算过程中,就不需要重新计算了,获取新的joined的RDD时候大大减少了计算量。

注意在实现过程中的持久化的位置,不然每次划分之后都重新计算没分区的意义就不存在了。
partitionBy()这个方法需要使用的版本尽量不要特别旧。
使用RDD.partitioner属性来获取分区的信息,返回的结果是一个scala.Option对象,这个对象中的isDefined()检查是否有值,get()方法获取其中的值。
从分区中获益的操作:
一些常见的操作用到分区的信息:
sortByKey 使用范围分区
groupByKey 使用哈希分区
join 使用哈希分区
cogroup 
groupWith
leftOuterJoin
groupByKey
reduceByKey
combineByKey
lookup
二元操作中至少一个RDD是不用做数据混洗的,通常选择那个数据操作量耗时严重的作为不发生数据混洗的那个。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值