弹性分布式数据集(Resilient Distribute Dataset)
- RDD其实就是分布式元素的集合。
- 在Spark中,对数据的所有操作不外乎创建RDD,转化已有的RDD以及调用RDD操作进行求值。
- Spark会自动讲RDD中的数据分发到集群上,并讲操作并行化执行。
初始化sparkcontext:
from pyspark import SparkContext , SparkConf
#创建一个conf对象来配置应用,此处设置为本地,名字为My App
conf = SparkConf().setMaster("loacal").setAppName("My App")
#基于配置的应用conf来创建一个SparkContext对象
sc = SparkContext(conf = conf)
RDD基础:
Spark中RDD就是一个不可变的分布式对象集合。每个RDD都被分为多个分区,这些分区被运行在集群中的不同节点上。
例如:
创建RDD:
lines = sc.textFile("README.md")
创建出来后,RDD支持两种类型的操作:转化操作(transformation)和行动操作(action)。转化操作会由一个RDD生成一个新的RDD。
调用转化操作:
pythonlines = lines.filter(lamda line : "Python" in line)
行动操作:
lines.first()
转化操作和行动操作的区别在于Spark计算RDD的方式不同。
python进行union转化操作:
lines = sc.textFile("README.md")
PythonRDD = lines.filter(lambda x : "Python" in x)
ScalaRDD = lines.filter(lambda x : "Scala" in x)
languageRDD = PythonRDD.union(ScalaRDD)
RDD 的转化操作都是惰性求值的,也就是说在被调用行动操作之前,spark不会进行计算。所以我们不应该把RDD看作是存放着特定数据的数据集,而最好把每个RDD看作我们通过转化操作侯建出来的。因此当我们调用sc.textFile()时,数据并没有被读取进来,而是在必要时才会读取。
传递函数:
PythonRDD = lines.filter(lambda x : "Python" in x)
#可以等价与:
def containsPython(s):
return "Python" in s
P_RDD = lines.filter(containsPython)
需要注意的一点是,当你传递的对象是某个对象的成员时,或者某个对象的一个字段的引用(如self.filed),spark会讲整个对象发到工作节点上。
传递带字段的函数(错误行为):
class AA():
def __init__(self,query):
self.query = query
def getinfo():
return rdd.filter(lambda x : self.query in x)
不传递带字段的函数(正确行为):
class AA():
...
def getinfo():
query = self.query
return rdd.filter(lambda x : query in x)
常见的转化操作(产生新的RDD)和行动操作
常见的转化操作
- map() 。map()接受一个函数,把这个函数用于RDD中的每一个元素,将函数返回结果作为结果RDD中对应的元素值。
- filter(). filter()接受一个函数,并将RDD中满足这个函数(通常来说就是这个函数返回True)的元素放入新的RDD中。
例:用转化操作map()对RDD中的所有元素求平方,返回一个新的RDD
nums = sc.parallelize([1,2,3,4]) #建立rdd
squared_rdd = nums.map(lambda x : x*x) #转化rdd
squared_rdd = squared_rdd.collect() #把rdd转化为列表
squared_rdd
[1, 4, 9, 16]
flatMap()与map()类似,只是这个转化可以由1个元素返回多个元素。比如把英文句子切分成单词。
例:用转化操作flatMap()将行数据切分为单词:
lines = sc.parallelize(["hello world","hi"])
words = lines.flatMap(lambda line : line.split(" "))
words.first()
'hello'
对数据为{1,2,3,3}的RDD进行进行基本的RDD转化操作:num = sc.parallelize([1,2,3,3])
函数名 | 目的 | 示例 | 结果 |
---|---|---|---|
map() | 将RDD中每个元素都输入函数中得到返回的元素构成新的RDD | rdd_map = num.map(lambda x : x+1) | [2, 3, 4, 4] |
flatMap() | 将RDD中每个元素都输入函数中得到返回的多个元素构成新的RDD | rdd_flatMap = num.flatMap(lambda x : range(x,4)) | [1, 2, 3, 2, 3, 3, 3] |
filter | 把原元素输入传入的函数中返回返回值为True的原元素组成的新rdd | filter_rdd = num.filter(lambda x : x != 2) | [1, 3, 3] |
distinct() | 去重 | distinct_rdd = num.distinct() | [1, 2, 3] |
sample() | 采样 | sample_rdd = num.sample(False,0.5) | [1, 2] |
对数据分别为{1,2,3}和{3,4,5}的RDD进行针对两个RDD的转化操作num1 = sc.parallelize([1,2,3])
,num2 = sc.parallelize([3,4,5])
函数名 | 目的 | 示例 | 结果 |
---|---|---|---|
union() | 生成一个包含两个RDD中所有元素的RDD | union_rdd = num1.union(num2) | [1, 2, 3, 3, 4, 5] |
intersection() | 求两个RDD共同元素的RDD | intersection_rdd = num1.intersection(num2) | [3] |
subtract() | 移除一个RDD中存在与另一个RDD中的元素(不改变原来的RDD,而是生产一个新的RDD) | subtract_rdd = num1.subtract(num2) | [1, 2] |
cartesian() | 与另一个RDD的笛卡尔积 | cartesian_rdd = num1.cartesian(num2) | [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 3), (3, 4), (3, 5)] |
常见的行动操作(不产生新的RDD,返回数值或数值集合)
例如对元素进行累加:
num1 = sc.parallelize([1,2,3])
sum = num1.reduce(lambda x,y:x+y)
print(sum)
6
对一个数据为{1,2,3,3}的RDD进行基本的RDD行动操作:num = sc.parallelize([1,2,3,3])
函数名 | 目的 | 示例 | 结果 |
---|---|---|---|
collect() | 返回RDD中所有的元素 | num.collect() | [1, 2, 3, 3] |
count() | RDD中元素的个数 | num.count() | |
countByValue() | 各元素在RDD中出现的次数,在python中返回的是一个字典 | dic = num.countByValue() | defaultdict(<class ‘int’>, {1: 1, 2: 1, 3: 2}) |
take(n) | 返回RDD中n个元素,python中返回列表 | num.take(2) | [1, 2] |
top(n) | 返回RDD中最前面的n个元素 | num.top(2) | [3, 3] |
takeOrdered(n)(ordering) | 在RDD中按照提供的顺序返回最前面的n个元素 | num.takeOrdered(2) | [1, 2] |
takeSample() | 从RDD中返回任意一些元素 | num.takeSample(False,1) | 随机值如[1] |
reduce(func) | 并行整合RDD中所有数据 | num.reduce(lambda x,y : x*y) | 18 |
fold(zero)(func) | 和reduce一样,但是需要提供初始值 | num.fold(0, lambda x,y : x+y) | 9 |
aggregate((zeroValue),(seqOp,comOp)) | 和reduce相似,但是通常返回不同的类型 | sumcount = num.aggregate((0,0,), (lambda acc,value:(acc[0]+value , acc[1]+1)),(lambda acc1,acc2 : (acc1[0]+acc2[0],acc1[1]+acc2[1]))) | (9, 4) |
foreach(func) |
持久化操作
Spark RDD是惰性求值的,如果会多次使用同一个RDD,为避免重复计算,.可以将其持久化.