spark:学习杂记--29

从前两天开始跟着写spark官网上的例子,期间遇到很多函数和方法,这篇博客基本上都是从网上各位牛人那里东拼西凑copy过来的,在写例子的时候遇到不会的函数或方法就去google或百度然后贴在这里为读懂例子做准备···接下来会写一些spark的例子以及我个人对例子中语句的理解

1.map
map是对RDD中的每个元素都执行一个指定的函数来产生一个新的RDD。 任何原RDD中的元素在新RDD中都有且只有一个元素与之对应。

scala> val a = sc.parallelize(1 to 9, 3)
scala> val b = a.map(x => x*2)
scala> a.collect
res10: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> b.collect
res11: Array[Int] = Array(2, 4, 6, 8, 10, 12, 14, 16, 18)
上述例子中把原RDD中每个元素都乘以2来产生一个新的RDD。

2.mapPartitions
mapPartitions是map的一个变种。map的输入函数是应用于RDD中每个元素,而mapPartitions的输入函数是应用于每个分区,也就是把每个分区中的内容作为整体来处理的。 它的函数定义为:
def mapPartitions[U: ClassTag](f: Iterator[T] => Iterator[U], preservesPartitioning: Boolean = false): RDD[U]
f即为输入函数,它处理每个分区里面的内容。每个分区中的内容将以Iterator[T]传递给输入函数f,f的输出结果是Iterator[U]。最终的RDD由所有分区经过输入函数处理后的结果合并起来的。

scala> val a = sc.parallelize(1 to 9, 3)
scala> def myfunc[T](iter: Iterator[T]) : Iterator[(T, T)] = {
  var res = List[(T, T)]() 
  var pre = iter.next while (iter.hasNext) {
    val cur = iter.next; 
    res .::= (pre, cur) pre = cur;
  } 
  res.iterator
}
scala> a.mapPartitions(myfunc).collect
res0: Array[(Int, Int)] = Array((2,3), (1,2), (5,6), (4,5), (8,9), (7,8))
上述例子中的函数myfunc是把分区中一个元素和它的下一个元素组成一个Tuple。因为分区中最后一个元素没有下一个元素了,所以(3,4)和(6,7)不在结果中。 mapPartitions还有些变种,比如mapPartitionsWithContext,它能把处理过程中的一些状态信息传递给用户指定的输入函数。还有mapPartitionsWithIndex,它能把分区的index传递给用户指定的输入函数。

3.mapValues

mapValues顾名思义就是输入函数应用于RDD中Kev-Value的Value,原RDD中的Key保持不变,与新的Value一起组成新的RDD中的元素。因此,该函数只适用于元素为KV对的RDD。

scala> val a = sc.parallelize(List("dog", "tiger", "lion", "cat", "panther", " eagle"), 2)
scala> val b = a.map(x => (x.length, x))
scala> b.mapValues("x" + _ + "x").collect
res5: Array[(Int, String)] = Array((3,xdogx), (5,xtigerx), (4,xlionx),(3,xcatx), (7,xpantherx), (5,xeaglex))
4.mapWith
mapWith是map的另外一个变种,map只需要一个输入函数,而mapWith有两个输入函数。它的定义如下:
def mapWith[A: ClassTag, U: ](constructA: Int => A, preservesPartitioning: Boolean = false)(f: (T, A) => U): RDD[U]
    第一个函数constructA是把RDD的partition index(index从0开始)作为输入,输出为新类型A;
    第二个函数f是把二元组(T, A)作为输入(其中T为原RDD中的元素,A为第一个函数的输出),输出类型为U。
举例:把partition index 乘以10,然后加上2作为新的RDD的元素。

val x = sc.parallelize(List(1,2,3,4,5,6,7,8,9,10), 3) 
x.mapWith(a => a * 10)((a, b) => (b + 2)).collect 
res4: Array[Int] = Array(2, 2, 2, 12, 12, 12, 22, 22, 22, 22)
5.flatMap

与map类似,区别是原RDD中的元素经map处理后只能生成一个元素,而原RDD中的元素经flatmap处理后可生成多个元素来构建新RDD。 举例:对原RDD中的每个元素x产生y个元素(从1到y,y为元素x的值)

scala> val a = sc.parallelize(1 to 4, 2)
scala> val b = a.flatMap(x => 1 to x)
scala> b.collect
res12: Array[Int] = Array(1, 1, 2, 1, 2, 3, 1, 2, 3, 4)
6.flatMapWith

flatMapWith与mapWith很类似,都是接收两个函数,一个函数把partitionIndex作为输入,输出是一个新类型A;另外一个函数是以二元组(T,A)作为输入,输出为一个序列,这些序列里面的元素组成了新的RDD。它的定义如下:
def flatMapWith[A: ClassTag, U: ClassTag](constructA: Int => A, preservesPartitioning: Boolean = false)(f: (T, A) => Seq[U]): RDD[U]

scala> val a = sc.parallelize(List(1,2,3,4,5,6,7,8,9), 3)
scala> a.flatMapWith(x => x, true)((x, y) => List(y, x)).collect
res58: Array[Int] = Array(0, 1, 0, 2, 0, 3, 1, 4, 1, 5, 1, 6, 2, 7, 2,
8, 2, 9)
7.flatMapValues
flatMapValues类似于mapValues,不同的在于flatMapValues应用于元素为KV对的RDD中Value。每个一元素的Value被输入函数映射为一系列的值,然后这些值再与原RDD中的Key组成一系列新的KV对。
scala> val a = sc.parallelize(List((1,2),(3,4),(3,6)))
scala> val b = a.flatMapValues(x=>x.to(5))
scala> b.collect
res3: Array[(Int, Int)] = Array((1,2), (1,3), (1,4), (1,5), (3,4), (3,5))
上述例子中原RDD中每个元素的值被转换为一个序列(从其当前值到5),比如第一个KV对(1,2), 其值2被转换为2,3,4,5。然后其再与原KV对中Key组成一系列新的KV对(1,2),(1,3),(1,4),(1,5)。

8.reduce

reduce将RDD中元素两两传递给输入函数,同时产生一个新的值,新产生的值与RDD中下一个元素再被传递给输入函数直到最后只有一个值为止。

scala> val c = sc.parallelize(1 to 10)
scala> c.reduce((x, y) => x + y)
res4: Int = 55
上述例子对RDD中的元素求和。
9.reduceByKey
顾名思义,reduceByKey就是对元素为KV对的RDD中Key相同的元素的Value进行reduce,因此,Key相同的多个元素的值被reduce为一个值,然后与原RDD中的Key组成一个新的KV对。

scala> val a = sc.parallelize(List((1,2),(3,4),(3,6)))
scala> a.reduceByKey((x,y) => x + y).collect
res7: Array[(Int, Int)] = Array((1,2), (3,10))
上述例子中,对Key相同的元素的值求和,因此Key为3的两个元素被转为了(3,10)
10.Iterator中hasNext(), next()
在Iterator类中,我们经常用到两个方法: hasNext(), next(),
具体含义: next(),  是返回当前元素, 并指向下一个元素。
                  hasNext(), 则是判断当前元素是否存在,并指向下一个元素(即所谓的索引)
如: 枚举工号
Map  map = new HashMap();       
        map = new HashMap();
        map.put("1155669", "Tom");
        map.put("1155689", "Jane");
        map.put("1165669", "Kevin");
        map.put("1155660", "Gavin");
        
        Set keySet = map.keySet();
        Iterator  iterator = keySet.iterator();
        
        while (iterator.hasNext()) {
            String  key = (String) iterator.next();
            System.out.println(key);
        }
/

1、WARN TaskSchedulerImpl: Initial job has not accepted any resources; check your cluster uito ensure that workers are registered and have sufficient memory
当前的集群的可用资源不能满足应用程序所请求的资源。
资源分2类: cores 和 ram
Core代表对执行可用的executor slots
Ram代表每个Worker上被需要的空闲内存来运行你的Application。
解决方法:
应用不要请求多余空闲可用资源的
关闭掉已经执行结束的Application

2、Application isn’t using all of the Cores: How to set the Cores used by a Spark App
设置每个App所能获得的core
解决方法:
spark-env.sh里设置spark.deploy.defaultCores

spark.cores.max

3、Spark Executor OOM: How to set Memory Parameters on Spark
OOM是内存里堆的东西太多了


1、增加job的并行度,即增加job的partition数量,把大数据集切分成更小的数据,可以减少一次性load到内存中的数据量。InputFomart, getSplit来确定。

2、spark.storage.memoryFraction
管理executor中RDD和运行任务时的内存比例,如果shuffle比较小,只需要一点点shuffle memory,那么就调大这个比例。默认是0.6。不能比老年代还要大。大了就是浪费。

3、spark.executor.memory如果还是不行,那么就要加Executor的内存了,改完executor内存后,这个需要重启。

4、Shark Server/ Long Running Application Metadata Cleanup
Spark程序的元数据是会往内存中无限存储的。spark.cleaner.ttl来防止OOM,主要出现在Spark Steaming和Shark Server里。
export SPARK_JAVA_OPTS +="-Dspark.kryoserializer.buffer.mb=10 -Dspark.cleaner.ttl=43200"

5、Class Not Found: Classpath Issues
问题1、缺少jar,不在classpath里。
问题2、jar包冲突,同一个jar不同版本。

解决1:
将所有依赖jar都打入到一个fatJar包里,然后手动设置依赖到指定每台机器的DIR。
val conf = new SparkConf().setAppName(appName).setJars(Seq(System.getProperty("user.dir") + "/target/scala-2.10/sparktest.jar"))

解决2:
把所需要的依赖jar包都放到default classpath里,分发到各个worker node上。

///

Broadcast(广播)是相对较为常用方法功能,通常使用方式,包括共享配置文件,map数据集,树形数据结构等,为能够更好更快速为TASK任务使用相关变量。
    <span style="font-size:18px;">val broadcastValue = sc.broadcast(存储值)  
    broadcastValue .value</span>  
Broadcast是典型的建造者模式方法,相对内部设计相对较为简单,同时初始化并非直接创建Broadcast对象,作用有两个方面:

1. 依据配置属性(spark.broadcast.factory)创建BroadcastFactory对象 - 反射创建。

2. 将sparkConf对象注入Broadcast中,同时定义压缩编码
用广播较为简单,如果sparkContext为长期有效执行多个job,则考虑注销广播,同时尽量广播要小
相关配置属性说明:

spark.broadcast.factory 定义使用http或Torrent方式,默认是Torrent,无需修改

spark.broadcast.blockSize 数据库块大小,blockifyObject依据此属性切分数据块,默认4M

spark.broadcast.compress 是否压缩,默认是使用,sparkcontext初始化该属性,无需修改
Broadcast 变量

Spark 所支持的两种共享变量 (shared variables) 的一种,主要用于共享分布式计算过程中各个 task 都会用到的只读变量,broadcast 变量只会在每台计算机器上保存一份,而不会每个task都传递一份,节省空间,效率也高。Spark 的HadoopRDD 的  实现  中,就采用 broadcast 进行 Hadoop JobConf 的传输。 官方文档的说法  是当task的大小大于20k时,就可以考虑用 broadcast 进行优化。

在我们的实现中,权重矩阵是一个 100 * 1000000 的Float矩阵,Spark 默认进行压缩后大约是400M左右,由于梯度计算时每个样本都需要跟整个权重矩阵进行计算,因此权重矩阵的传输我们通过 broadcast 实现。而由于权重矩阵在每次迭代后都会更新,因此在每次迭代后都会重新 broadcast 一次。每次 worker 读取 broadcast 的时间短则几秒,长则二三十秒,相比序列化传参的方式,要快得多。但是这种实现也不完美,因为每次迭代所传输的 broadcast 变量都会保存在 worker 的内存中,直至内存不够用,spark 才会把旧的 broadcast 变量释放掉,不能提前release掉。
///
ExceptionHandling
异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件)。

各种编程语言在处理异常方面具有非常显著的不同点(错误检测与异常处理区别在于:错误检测是在正常的程序流中,处理不可预见问题的代码,例如一个调用操作未能成功结束)。某些编程语言有这样的函数:当输入存在非法数据时不能被安全地调用,或者返回值不能与异常进行有效的区别。例如,C语言中的atoi函数(ASCII串到整数的转换)在输入非法时可以返回0。在这种情况下编程者需要另外进行错误检测(可能通过某些辅助全局变量如C的errno),或进行输入检验(如通过正则表达式),或者共同使用这两种方法。

通过异常处理,我们可以对用户在程序中的非法输入进行控制和提示,以防程序崩溃。

从进程的视角,硬件中断相当于可恢复异常,虽然中断一般与程序流本身无关。

从子程序编程者的视角,异常是很有用的一种机制,用于通知外界该子程序不能正常执行。如输入的数据无效(例如除数是0),或所需资源不可用(例如文件丢失)。如果系统没有异常机制,则编程者需要用返回值来标示发生了哪些错误。

获取或设置一个值,用于在由引发的异常所导致的堆栈展开期间调用自动对象的析构函数。 ExceptionHandling 公开编译器的 /EH(异常处理模型) 选项的功能。
throw 语句用于发出程序执行期间出现反常情况(异常)的信号。
调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。
///
java Test value1 value2
后面就是两个参数,在main里面args[]就是两个长度的数组value1存在args[0]中,value2存在args[1]中。
//
HBase是一个分布式的、面向列的开源数据库
///
HBaseConfiguration是用来配置HBase的对象。
意思是把HBase的配置文件添加到配置信息中,这个类继承自org.apache.hadoop.conf.Configuration,
///
Cassandra是一套开源分布式NoSQL数据库系统。它最初由Facebook开发,用于储存收件箱等简单格式数据,集GoogleBigTable的数据模型与Amazon Dynamo的完全分布式的架构于一身Facebook于2008将 Cassandra 开源,此后,由于Cassandra良好的可扩放性,被Digg、Twitter等知名Web 2.0网站所采纳,成为了一种流行的分布式结构化数据存储方案。
Cassandra是一个混合型的非关系的数据库,类似于Google的BigTable。其主要功能比Dynamo (分布式的Key-Value存储系统)更丰富,但支持度却不如文档存储MongoDB(介于关系数据库和非关系数据库之间的开源产品,是非关系数据库当中功能最丰富,最像关系数据库的。支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型)。Cassandra最初由Facebook开发,后转变成了开源项目。它是一个网络社交云计算方面理想的数据库。以Amazon专有的完全分布式的Dynamo为基础,结合了Google BigTable基于列族(Column Family)的数据模型。P2P去中心化的存储。很多方面都可以称之为Dynamo 2.0。[1]
///

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值