常见的算子
rdd.map(f: (T) -> U)
def map_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd = sc.parallelize([1, 2, 3, 4, 5], 5)
map_rdd = rdd.map(lambda x: x ** 2)
print(map_rdd.collect()) # [1, 4, 9, 16, 25]
rdd.flatMap(f: (T) -> U)
对rdd执行map操作,然后进行扁平化
def flatMap_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd = sc.parallelize(['spark hadoop python', 'flatMap java scala', 'c c++ mr'])
# flatMap_rdd = rdd.map(lambda word: word.split(" "))
flatMap_rdd = rdd.flatMap(lambda word : word.split(" "))
print(flatMap_rdd.collect()) # ['spark', 'hadoop', 'python', 'flatMap', 'java', 'scala', 'c', 'c++', 'mr']
rdd.reduceByKey(func: (V, V) -> V)
针对KV型,自动按照key分组,然后根据你提供的聚合逻辑,完成组内数据的聚合
def reduceByKey_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd = sc.parallelize(['spark hadoop python', 'flatMap java scala', 'c c++ mr', 'c python java scala'])
reduceByKey_rdd = rdd.flatMap(lambda lis: lis.split(" ")).map(lambda world: (world, 1)).reduceByKey(
lambda a, b: a + b)
print(
reduceByKey_rdd.collect()) # [('hadoop', 1), ('python', 2), ('spark', 1), ('scala', 2), ('java', 2), ('c', 2), ('c++', 1), ('mr', 1), ('flatMap', 1)]
rdd.mapValues(func: (V) -> U)
针对KV类型的RDD,对其内部的KV的Value执行map操作
def mapValues_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd = sc.parallelize(['spark hadoop python', 'flatMap java scala', 'c c++ mr', 'c python java scala'])
mapValues_rdd = rdd.flatMap(lambda lis: lis.split(" ")).map(lambda world: (world, 1)).reduceByKey(
lambda a, b: a + b).mapValues(lambda x: x ** 2)
print(mapValues_rdd.collect()) # [('hadoop', 1), ('python', 4), ('spark', 1), ('scala', 4), ('java', 4), ('c', 4), ('c++', 1), ('mr', 1), ('flatMap', 1)]
rdd.groupBy(func: (T) -> K)
将rdd的数据进行分组
def groupBy_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd = sc.parallelize([('a', 1), ('b', 1), ('a', 2), ('b', 2), ('b', 3), ('a', 3)])
groupBy_rdd = rdd.groupBy(lambda x : x[0])
print(groupBy_rdd.collect()) # [('a', <pyspark.resultiterable.ResultIterable object at 0x00000213BEF3C288>), ('b', <pyspark.resultiterable.ResultIterable object at 0x00000213BEF3C208>)]
result = groupBy_rdd.map(lambda x : (x[0], list(x[1])))
print(result.collect()) # [('a', [('a', 1), ('a', 2), ('a', 3)]), ('b', [('b', 1), ('b', 2), ('b', 3)])]
rdd.filter(func : (T) -> bool)
过滤想要的数据
def filter_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7, 8, 9])
filter_rdd = rdd.filter(lambda x: x % 2 == 0)
print(filter_rdd.collect()) # [2, 4, 6, 8]
rdd.distinct(参数1)
参数1:去重分区数,一般不传
def distinct_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd = sc.parallelize([1, 2, 3, 1, 2, 3])
distinct_rdd = rdd.distinct()
print(distinct_rdd.collect()) # [1, 2, 3]
rdd.union(other_rdd)
将两个rdd合并成一个rdd返回,只合并,并不去重, rdd的类型不同也是可以合并的
def union_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd = sc.parallelize([1, 2, 3, 4])
rdd2 = sc.parallelize([(1, 2), (3, 4)])
union_rdd = rdd.union(rdd2)
print(union_rdd.collect()) # [1, 2, 3, 4, (1, 2), (3, 4)]
rdd.join(other_rdd)
join算子只能用于二元元组, 对于join算子来说,关联条件按照二元元组的key来进行关联
def join_operator():
conf = SparkConf().setMaster('local[*]').setAppName('map_operator')
sc = SparkContext(conf=conf)
rdd1 = sc.parallelize([('a', 1), ('b', 2), ('c', 3)])
rdd2 = sc.parallelize([('b', 2), ('c', 3), ('d', 4)])
join_rdd = rdd1.join(rdd2)
print(join_rdd.collect()) # [('b', (2, 2)), ('c', (3, 3))]
leftOuterJoin_rdd = rdd1.leftOuterJoin(rdd2)
print(leftOuterJoin_rdd.collect()) # [('b', (2, 2)), ('c', (3, 3)), ('a', (1, None))]
rightOuterJoin_rdd = rdd1.rightOuterJoin(rdd2)
print(rightOuterJoin_rdd.collect()) # [('b', (2, 2)), ('c', (3, 3)), ('d', (None, 4))]
rdd.intersection(other_rdd)
功能:求2个rdd的交集,返回一个新的rdd
def intersection_operator():
sc = spark()
rdd1 = sc.parallelize([('a', 1), ('b', 2)])
rdd2 = sc.parallelize([('b', 2), ('c', 3)])
intersection_rdd = rdd1.intersection(rdd2)
print(intersection_rdd.collect()) # [('b', 2)]
rdd.glom()
将rdd的数据,加上嵌套,这个嵌套是按照分区来进行的
def glom_operator():
sc = spark()
rdd = sc.parallelize([1, 2, 3, 4, 5, 6], 2)
glom_rdd = rdd.glom()
# 解嵌套
flatMap_rdd = glom_rdd.flatMap(lambda x : x)
print(glom_rdd.collect()) # [[1, 2, 3], [4, 5, 6]]
print(flatMap_rdd.collect()) # [1, 2, 3, 4, 5, 6]
rdd.groupByKey()
针对KV类型的数据,自动按照key进行分组
注意groupBy() 和 groupByKey()返回的结果是不一样的
def groupByKey_operator():
sc = spark()
rdd = sc.parallelize([('a', 1), ('b', 2), ('c', 3), ('a', 'a'), ('b', 'b'), ('c', 'c')])
groupByKey_rdd = rdd.groupByKey().map(lambda x : (x[0], list(x[1])))
groupBy_rdd = rdd.groupBy(lambda x : x[0]).map(lambda x : (x[0], list(x[1])))
print(groupByKey_rdd.collect()) # [('a', [1, 'a']), ('b', [2, 'b']), ('c', [3, 'c'])]
print(groupBy_rdd.collect()) # [('a', [('a', 1), ('a', 'a')]), ('b', [('b', 2), ('b', 'b')]), ('c', [('c', 3), ('c', 'c')])]
rdd.sortBy(func: (T) -> U, ascending=False, numPartitions=1)
参数3:分区数, 这里的排序只能保证分区内有序,如果是生产环境下,可能会导致局部有序,如果要全局有序分区数要设置为1
def sortBy_operator():
sc = spark()
rdd = sc.parallelize([-1, 3, 5, 2, 6, 9])
sortBy_rdd = rdd.sortBy(lambda x: x, ascending=True, numPartitions=2)
# 参数1:表示按照什么来进行排序
# 参数2:True升序,False降序
# 参数3:分区数, 这里的排序只能保证分区内有序,如果是生产环境下,可能会导致局部有序,如果要全局有序分区数要设置为1
print(sortBy_rdd.collect()) # [-1, 2, 3, 5, 6, 9]
rdd.sortByKey(ascending = True, numPartition = None, keyfunc=<function RDD.<lambda>>)
针对KV类型,按照K进行排序
参数3:在排序前对key进行处理,语法是(K) -> U,一个参数传入,返回一个值,并不会改变结果集上的值,而是改变排序时的值
def sortByKey_operator():
sc = spark()
rdd = sc.parallelize([('1', 'a'), ('3', 'c'), ('002', 'b'), ('09', 'z')])
sortByKey_rdd = rdd.sortByKey(True, 1, lambda x : int(x))
print(sortByKey_rdd.collect()) # [('1', 'a'), ('002', 'b'), ('3', 'c'), ('09', 'z')]
def spark()
def spark():
conf = SparkConf().setMaster('local[*]').setAppName('rdd_test')
# conf.set("spark.submit.pyFiles", "**.py")
sc = SparkContext(conf=conf)
return sc
rdd.countByKey()
行动算子, 统计key出现的次数
def countByKey_operator():
sc = spark()
rdd = sc.textFile("./data/words.txt")
map_rdd = rdd.flatMap(lambda world: world.split(" ")).map(lambda world : (world , 1))
countByKey_rdd = map_rdd.countByKey()
print(type(countByKey_rdd)) # <class 'collections.defaultdict'>
print(countByKey_rdd) # defaultdict(<class 'int'>, {'hello': 3, 'spark': 1, 'hadoop': 1, 'flink': 1})
rdd.collect()
行动算子,将rdd各个分区中的数据,统一收集到Driver中,形成一个List()对象
这个算子,是将各个分区中的数据都拉取到Driver中,Rdd是一个分布式对象,其数据量非常的大,所以在使用这个算子之前要知道数据集的大小。
rdd.reduce(func :(T, T) -> U)
行动算子, 对RDD数据集按照你传入的逻辑进行聚合
def reudce_operator():
from operator import add
sc = spark()
rdd = sc.parallelize([x+1 for x in range(10)])
result = rdd.reduce(add)
print(result) # 55
rdd.flod()
和reduce一样,接受传入逻辑进行聚合,聚合是带有初始值的,这个初始值会作用在:分区内聚合和分区间聚合
def flod_operator():
from operator import add
sc = spark()
rdd = sc.parallelize(range(10), 3)
print(rdd.glom().collect()) # [[0, 1, 2], [3, 4, 5], [6, 7, 8, 9]]
flod_rdd = rdd.fold(10, add)
"""在分区内聚合:第一个分区:10 + 0 + 1 + 2 = 13
第二个分区:10 + 3 + 4 + 5 = 22
第三个分区:10 + 6 + 7 + 8 + 9 = 40
分区间聚合: 10 + 13 + 22 + 40 = 85
"""
print(flod_rdd) # 85
rdd.first()
取出rdd的第一个元素
rdd.take(n)
取出rdd前n个算子,返回值是list
rdd.top(n)
对rdd的结果集,进行降序排序,取前n个
rdd.count()
计算rdd有多少条数据,返回值是一个数字
rdd.takeSample(参数1:True or False, 参数2:采样数,参数3:随机数种子)
随机抽样rdd的数据
参数1:True表示运行允许取同一个数据;False表示不允许取同一个数据,和数据内容无关,是否重复表示的是同一个位置的数据
参数2:抽取几个
参数3:随机数种子,这个参数传入一个数字即可,随机,一般不传,spark会自动分配
def takeSample_operator():
sc = spark()
rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 3, 1, 2])
takeSample_rdd = rdd.takeSample(True, 20)
print(takeSample_rdd) # [2, 2, 2, 6, 3, 3, 6, 1, 6, 1, 1, 1, 4, 5, 1, 4, 3, 3, 4, 3]
takeSample_rdd2 = rdd.takeSample(False, 20)
print(takeSample_rdd2) # [4, 5, 2, 6, 2, 3, 1, 1, 3]
rdd.takeOrdered(参数1, 参数2)
对rdd进行排序取前N个数据
参数1:要几个数据
参数2:对排序的数据进行更改,但是不会影响数据本身,只是在排序的时候换个了样子
def takeOrdered_operator():
sc = spark()
rdd = sc.parallelize([-1, 3, 5, 2, 1, 0, -2])
result = rdd.takeOrdered(4, lambda x: x ** 2)
print(result) # [0, -1, 1, 2]
rdd.foreach(func:(T) -> None)
对rdd的每一个元素,执行你提供的逻辑的操作(和map一个意思),但是这个方法没有返回值,每个分区会自己执行func函数,并不会把结果返回给Dirver端
def foreach_operator():
sc = spark()
rdd = sc.parallelize([1, 2, 3, 4, 5])
rdd.foreach(lambda x : print(x, end = " ")) # 1 3 2 5 4
rdd.saveAsTextFile()
支持写入到本地文件系统,也支持写入到hdfs等文件系统,写出是每个分区执行,并不汇总到Driver端
rdd.mapPartitions(func:(iter) : list)
def mapPartition_operator():
sc = spark()
rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7], 3)
def process(iter):
resule = list()
for i in iter:
resule.append(i * 10)
return resule
mapPartitions_rdd = rdd.mapPartitions(lambda iter : process(iter))
print(mapPartitions_rdd.collect()) # [10, 20, 30, 40, 50, 60, 70]
rdd.foreachPartition()
和普通的foreach一致,一次处理的是一整个分区数据,同时它也没有返回值
rdd.partitionBy(参数1, 参数2)
针对KV类型的rdd进行自定义分区操作
参数1:重新分区后有几个分区
参数2:自定义分区规则,函数传入
def partitionBy_operator():
sc = spark()
rdd = sc.parallelize([(1, 'a'), (2, 'b'), (3, 'c')], 2)
# 默认分区
print(rdd.glom().collect()) # [[(1, 'a')], [(2, 'b'), (3, 'c')]]
# 自定义分区
partitionBy_rdd = rdd.partitionBy(2, lambda x: x % 2 + 1)
print(partitionBy_rdd.glom().collect()) # [[(1, 'a'), (3, 'c')], [(2, 'b')]]
rdd.repartition(N)
对rdd的分区执行重新分区(仅数量)
一般情况下,我们写spark代码除了要求全局排序设置1个分区外,多数的时候,所有API中关于分区相关的代码我们都不会理会,因为,如果修改了分区,①会影响到并行计算②分区如果增加,极大可能会导致shuffle
rdd.coalesce(分区数, shuffle = True, False)
如果要增加分区,需要将shuffle设置为True