【原】Learning Spark (Python版) 学习笔记(一)
idvv5744
9年前
<p><a href="/misc/goto?guid=4959671324623618572" rel="nofollow,noindex">《Learning Spark》</a> 这本书算是Spark入门的必读书了,中文版是 <a href="/misc/goto?guid=4959671324704748698" rel="nofollow,noindex">《Spark快速大数据分析》</a> ,不过豆瓣书评很有意思的是,英文原版评分7.4,评论都说入门而已深入不足,中文译版评分8.4,评论一片好评,有点意思。我倒觉得这本书可以作为官方文档的一个补充,刷完后基本上对Spark的一些基本概念、码简单的程序是没有问题的了。这本书有一个好处是它是用三门语言写的,Python/Java/Scala,所以适用性很广,我的观点是,先精通一门语言,再去学其他语言。由于我工作中比较常用的是Python,所以就用把Python相关的命令总结一下。下一阶段再深入学习Java和Scala。这一篇总结第一张-第三章的重点内容。</p> <p>说到Spark,就不得不提到RDD,RDD,字面意思是弹性分布式数据集,其实就是分布式的元素集合。Python的基本内置的数据类型有整型、字符串、元祖、列表、字典,布尔类型等,而Spark的数据类型只有RDD这一种,在Spark里,对数据的所有操作,基本上就是围绕RDD来的,譬如创建、转换、求值等等。理解RDD后可以避免以后走很多弯路。关于 <strong>RDD的特点</strong> ,可以搜到很多资料,其实我们只需要理解两点就可以了:</p> <p>1. 不可变</p> <p>2. 分布式</p> <p>有人会觉得很奇怪,如果RDD不可变,那么在进行数据操作的时候,怎么改变它的值,怎么进行计算呢?其实 <strong>RDD支持两种操作</strong> :</p> <p>1. Tansformation (转化操作):返回值还是一个RDD</p> <p>2. Action (行动操作):返回值不是一个RDD</p> <p>第一种Transformation是返回一个新的RDD,如map(),filter()等。这种操作是lazy(惰性)的,即从一个RDD转换生成另一个RDD的操作不是马上执行,只是记录下来,只有等到有Action操作是才会真正启动计算,将生成的新RDD写到内存或hdfs里,不会对原有的RDD的值进行改变。而Action操作才会实际触发Spark计算,对RDD计算出一个结果,并把结果返回到内存或hdfs中,如count(),first()等。</p> <p>通俗点理解的话,就是假设你写了一堆程序,里面对数据进行了多次转换,这个时候实际上没有计算,就只是放着这里。在最后出结果的时候会用到Action操作,这个时候Action会执行与之相关的转换操作,运算速度会非常快(一是Action不一定需要调用所有的transformation操作,二是只有在最后一步才会计算相关的transformation操作)。如果Transformation没有lazy性质的话,每转换一次就要计算一次,最后Action操作的时候还要计算一次,会非常耗内存,也会极大降低计算速度。</p> <p>还有一种情况,如果我们想多次使用同一个RDD,每次都对RDD进行Action操作的话,会极大的消耗Spark的内存,这种情况下,我们可以使用RDD.persist()把这个RDD缓存下来,在内存不足时,可以存储到磁盘(disk)里。在Python中,储存的对象永远是通过Pickle库序列化过的,所以社不设置序列化级别不会产生影响。</p> <p>RDD的性质和操作方式讲完了,现在来说说怎么 <strong>创建RDD</strong> ,有两种方式</p> <p>1. 读取一个外部数据集</p> <p>2. 在内存中对一个集合进行并行化 (parallelize)</p> <p>第二种方式相对来说更简单,你可以直接在shell里快速创建RDD,举个例子:</p> <pre> A = [1,2,3,4,5] lines = sc.parallelize(A) #另一种方式 lines = sc.parallelize([1,2,3,4,5]) </pre> <p>但是这种方式并不是很好,因为你需要把你的整个数据集放在内存里,如果数据量比较大,会很占内存。所以,可以在测试的时候用这种方式,简单快速。</p> <p> </p> <p>读取外部数据及时需要用到SparkContext.textFile()</p> <p>1 lines = sc.textFile( " README.md " )</p> <p>RDD的操作命令很多,包括map(),filter()等Transformation操作以及reduce(),fold(),aggregate()等Action操作,这里限于时间问题就先不一一写了,等有时间再补上。</p> <p>最后来讲讲如何 <strong> 向 Spark传递函数 </strong> :</p> <p>两种方式:</p> <p>1 .简单的函数:lambda表达式 。</p> <p>适合比较短的函数,不支持多语句函数和无返回值的语句。</p> <p>2 .def函数</p> <p>会将整个对象传递过去,但是最好不要传递一个带字段引用的函数。如果你传递的对象是某个对象的成员,或者在某个函数中引用了一个整个字段,会报错。举个例子:</p> <pre> class MyClass(object): def __init__(self): self.field = “Hello” def doStuff(self, rdd): #报错:因为在self.field中引用了整个self return rdd.map(lambda s: self.field + x) </pre> <p>解决方法:直接把你需要的字段拿出来放到一个局部变量里,然后传递这个局部变量就可以了。</p> <pre> class MyClass(object): def __init__(self): self.field = “Hello” def doStuff(self, rdd): #将需要的字段提取到局部变量中即可 field = self.field return rdd.map(lambda s: field + x) </pre> <p>前面三章讲了Spark的基本概念和RDD的特性以及一些简单的命令,比较简单。后面三章主要讲了键值对操作、数据的读取和保存以及累加器、广播变量等,下周再更新,顺便把这次没写完的RDD常见操作命令补完。</p> <p>来自: <a href="/misc/goto?guid=4959671324789881753" rel="nofollow">http://www.cnblogs.com/charlotte77/p/5412709.html</a></p>