学习spark任何技术之前请先正确理解spark,可以参考:正确理解Spark


本文详细介绍RDD python api的action操作。


先创建一个RDD:

conf = SparkConf().setAppName("appName").setMaster("local")
sc = SparkContext(conf=conf)

parallelize_rdd = sc.parallelize([1, 2, 4, 3, 3, 6, 12], 2)


一、collect、take

"""
结果:[[1, 2, 4], [3, 3, 6]]。收集RDD的所有元素
"""
print "parallelize_rdd = {0}".format(parallelize_rdd.glom().collect())
"""
结果:[1, 2]  获取RDD的第一个分区的前两个元素
"""
print "take(2) = {0}".format(parallelize_rdd.take(2))


二、top

"""
结果:[12, 6] 获取RDD的最大的两个元素
"""
print "top2 = {0}".format(parallelize_rdd.top(2))
"""
结果:[6, 4] 将RDD的元素转化成字符串,然后按照字符串的比较规则取最大的两个元素
"""
print "top(2, key=str) = {0}".format(parallelize_rdd.top(2, key=str))

接下来,详细讲解top的第二个参数:

"""
top的第二个参数是一个函数,一般是lambda表达式,可以看下面python内置的max的例子
当设置了这个key参数的时候,表示将数组中的元素应用这个key函数,按照返回的值来进行排序或者取最大值
"""
d1 = {'name': 'egon', 'price': 100}
d2 = {'name': 'rdw', 'price': 666}
d3 = {'name': 'zat', 'price': 1}
l1 = [d1, d2, d3]
"""
表示取数组 l1 中name最大的那个元素的值
"""
a = max(l1, key=lambda x: x['name'])
"""
结果是:{'price': 1, 'name': 'zat'}
"""
print(a)
"""
表示取数组 l1 中price最大的那个元素的值
"""
b = max(l1, key=lambda x: x['price'])
"""
结果是:{'price': 666, 'name': 'rdw'}
"""
print(b)


三、first、min、max、takeOrdered

"""
结果:first = 1
"""
print "first = {0}".format(parallelize_rdd.first())

"""
结果:min = 1. 这个参数和上面top的第二个参数是一个含义
"""
print "min = {0}".format(parallelize_rdd.min(key=lambda x: str(x)))

"""
结果:max = 12
"""
print "max = {0}".format(parallelize_rdd.max())

"""
结果:takeOrdered = [1, 12]  第二个参数和上面top的第二个参数是同一个含义
"""
print "takeOrdered = {0}".format(parallelize_rdd.takeOrdered(2, key=str))


四、foreach、foreachPartition

def get_init_number(source):
    print "get init number from {0}, may be take much time........".format(source)
    time.sleep(1)
    return 1

def foreach_fun(x):
    init_number = get_init_number("foreach")
    print x + init_number + "==========="
parallelize_rdd.foreach(foreach_fun)

def foreach_partition_fun(values):
    """
    和foreach api的功能是一样,只不过一个是将函数应用到每一条记录,这个是将函数应用到每一个partition
    如果有一个比较耗时的操作,只需要每一分区执行一次这个操作就行,则用这个函数
    这个耗时的操作可以是连接数据库等操作,不需要计算每一条时候去连接数据库,一个分区只需连接一次就行
    :param values:
    :return:
    """
    init_number = get_init_number("foreach")
    for item in values:
        print item + init_number + "==========="
parallelize_rdd.foreachPartition(foreach_partition_fun)


五、reduce、treeReduce

reduce_result = parallelize_rdd.reduce(lambda a, b: a + b)
print "reduce_result = {0}".format(reduce_result) # reduce_result = 31

tree_reduce_result = parallelize_rdd.treeReduce(lambda a, b: a + b, 2)
print "tree_reduce_result = {0}".format(tree_reduce_result) # tree_reduce_result = 31


六、fold

# 和reduce的功能类似,只不过是在计算每一个分区的时候需要加上初始值1,最后再将每一个分区计算出来的值相加再加上这个初始值
fold_result = parallelize_rdd.fold(0, lambda a, b: a + b)
print "fold_result = {0}".format(fold_result) # fold_result = 31


七、aggregate、treeAggregate

seqOp = (lambda x, y: (x[0] + y, x[1] + 1))
combOp = (lambda x, y: (x[0] + y[0], x[1] + y[1]))
aggregate_result = parallelize_rdd.aggregate((0, 0), seqOp, combOp)
print "aggregate_result = {0}".format(aggregate_result) #  aggregate_result = (31, 7)


对于reduce、treeReduce、fold、aggregate、treeAggregate的原理可以参考http://7639240.blog.51cto.com/7629240/1966172 和 spark core RDD api原理详解