神刀安全网

【原】Learning Spark (Python版) 学习笔记(一)

《Learning Spark》 这本书算是Spark入门的必读书了,中文版是 《Spark快速大数据分析》 ,不过豆瓣书评很有意思的是,英文原版评分7.4,评论都说入门而已深入不足,中文译版评分8.4,评论一片好评,有点意思。我倒觉得这本书可以作为官方文档的一个补充,刷完后基本上对Spark的一些基本概念、码简单的程序是没有问题的了。这本书有一个好处是它是用三门语言写的,Python/Java/Scala,所以适用性很广,我的观点是,先精通一门语言,再去学其他语言。由于我工作中比较常用的是Python,所以就用把Python相关的命令总结一下。下一阶段再深入学习Java和Scala。这一篇总结第一张-第三章的重点内容。

说到Spark,就不得不提到RDD,RDD,字面意思是弹性分布式数据集,其实就是分布式的元素集合。Python的基本内置的数据类型有整型、字符串、元祖、列表、字典,布尔类型等,而Spark的数据类型只有RDD这一种,在Spark里,对数据的所有操作,基本上就是围绕RDD来的,譬如创建、转换、求值等等。理解RDD后可以避免以后走很多弯路。关于 RDD的特点 ,可以搜到很多资料,其实我们只需要理解两点就可以了:

1. 不可变

2. 分布式

有人会觉得很奇怪,如果RDD不可变,那么在进行数据操作的时候,怎么改变它的值,怎么进行计算呢?其实 RDD支持两种操作

1. Tansformation (转化操作):返回值还是一个RDD

2. Action (行动操作):返回值不是一个RDD

第一种Transformation是返回一个新的RDD,如map(),filter()等。这种操作是lazy(惰性)的,即从一个RDD转换生成另一个RDD的操作不是马上执行,只是记录下来,只有等到有Action操作是才会真正启动计算,将生成的新RDD写到内存或hdfs里,不会对原有的RDD的值进行改变。而Action操作才会实际触发Spark计算,对RDD计算出一个结果,并把结果返回到内存或hdfs中,如count(),first()等。

通俗点理解的话,就是假设你写了一堆程序,里面对数据进行了多次转换,这个时候实际上没有计算,就只是放着这里。在最后出结果的时候会用到Action操作,这个时候Action会执行与之相关的转换操作,运算速度会非常快(一是Action不一定需要调用所有的transformation操作,二是只有在最后一步才会计算相关的transformation操作)。如果Transformation没有lazy性质的话,每转换一次就要计算一次,最后Action操作的时候还要计算一次,会非常耗内存,也会极大降低计算速度。

还有一种情况,如果我们想多次使用同一个RDD,每次都对RDD进行Action操作的话,会极大的消耗Spark的内存,这种情况下,我们可以使用RDD.persist()把这个RDD缓存下来,在内存不足时,可以存储到磁盘(disk)里。在Python中,储存的对象永远是通过Pickle库序列化过的,所以社不设置序列化级别不会产生影响。

RDD的性质和操作方式讲完了,现在来说说怎么 创建RDD ,有两种方式

1. 读取一个外部数据集

2. 在内存中对一个集合进行并行化 (parallelize)

第二种方式相对来说更简单,你可以直接在shell里快速创建RDD,举个例子:

 1 A = [1,2,3,4,5] 2 lines = sc.parallelize(A) 3 #另一种方式 4 lines = sc.parallelize([1,2,3,4,5]) 

但是这种方式并不是很好,因为你需要把你的整个数据集放在内存里,如果数据量比较大,会很占内存。所以,可以在测试的时候用这种方式,简单快速。

读取外部数据及时需要用到SparkContext.textFile()

1 lines = sc.textFile( " README.md " )

RDD的操作命令很多,包括map(),filter()等Transformation操作以及reduce(),fold(),aggregate()等Action操作,这里限于时间问题就先不一一写了,等有时间再补上。

最后来讲讲如何 Spark传递函数

两种方式:

1 .简单的函数:lambda表达式

适合比较短的函数,不支持多语句函数和无返回值的语句。

2 .def函数

会将整个对象传递过去,但是最好不要传递一个带字段引用的函数。如果你传递的对象是某个对象的成员,或者在某个函数中引用了一个整个字段,会报错。举个例子:

 1 class MyClass(object): 2     def __init__(self): 3         self.field = “Hello” 4  5     def doStuff(self, rdd): 6         #报错:因为在self.field中引用了整个self 7         return rdd.map(lambda s: self.field + x) 

解决方法:直接把你需要的字段拿出来放到一个局部变量里,然后传递这个局部变量就可以了。

 1 class MyClass(object): 2     def __init__(self): 3         self.field = “Hello” 4  5     def doStuff(self, rdd): 6         #将需要的字段提取到局部变量中即可 7         field = self.field 8         return rdd.map(lambda s: field + x) 

前面三章讲了Spark的基本概念和RDD的特性以及一些简单的命令,比较简单。后面三章主要讲了键值对操作、数据的读取和保存以及累加器、广播变量等,下周再更新,顺便把这次没写完的RDD常见操作命令补完。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 【原】Learning Spark (Python版) 学习笔记(一)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址