pyspark中部分***ByKey的用法

準備工作

import pyspark
from pyspark import SparkContext
from pyspark import SparkConf
conf=SparkConf().setAppName("lg").setMaster('local[4]')
sc=SparkContext.getOrCreate(conf)

1. aggregateByKey

aggregateByKey中前一個函數是在各分區內計算的函數,後一個函數是聚合個分區結果的函數

其中zeroVal是對每個元素進行計算時的初始值,和分區無關。

rdd = sc.parallelize([('B',1),('B',2),('A',3),('A',4),('A',5)])   
zeroVal = 1
mergeVal = (lambda aggregated,el:aggregated+el)       #aggregated即zeroVal     
mergeComb = (lambda agg1,agg2:agg1+agg2)
result = rdd.aggregateByKey(zeroVal,mergeVal,mergeComb)
print(rdd.glom().collect())
print(result.collect())

[[('B', 1)], [('B', 2)], [('A', 3)], [('A', 4)], [('A', 5)]]
[('A', 15), ('B', 5)]

2. reduceByKey和GroupByKey

        都是按key對元素進行聚合計算,但原理有所不同。

def add(a,b):
    c = a + b
    return c
rdd = sc.parallelize([('a',1),('b',1),('a',1),('a',1),('b',1),('b',1),('a',1),('a',1),('a',1),('b',1),('b',1),('b',1)])
print(rdd.reduceByKey(add).collect())
print(rdd.groupByKey().mapValues(len).collect())

[('b', 6), ('a', 6)]
[('b', 6), ('a', 6)]

(1)groupByKey()是對RDD中的所有數據做shuffle,根據不同的Key映射到不同的partition中再進行aggregate。

 (2)aggregateByKey()是先對每個partition中的數據根據不同的Key進行aggregate,然後將結果進行shuffle,完成各個partition之間的aggregate。因此,和groupByKey()相比,運算量小了很多。

 (3)reduceByKey()也是先在單臺機器中計算,再將結果進行shuffle,I/O開銷比groupByKey要小。

 

3. sortByKey和sortBy

    sortByKey是按元素的鍵進行排序,可指定降序或者升序;sortBy則還可以指定按鍵或者按值進行排序。

rdd1 = sc.parallelize([(1,'one'),(6,'six'),(7,'seven'),(2,'two'),(3,'three'),(4,'four'),(5,'five'),(8,'eight'),(9,'night'),(10,'ten')])
rdd2 = rdd1.sortByKey(ascending=True, numPartitions=None) 
rdd3 = rdd1.sortBy(ascending=True, numPartitions=None, keyfunc = lambda x: x[1]) 
rdd4 = rdd1.sortBy(ascending=False, numPartitions=None, keyfunc = lambda x: x[0]) 
print(rdd2.collect())
print(rdd3.collect())
print(rdd4.collect())

[(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five'), (6, 'six'), (7, 'seven'), (8, 'eight'), (9, 'night'), (10, 'ten')]
[(8, 'eight'), (5, 'five'), (4, 'four'), (9, 'night'), (1, 'one'), (7, 'seven'), (6, 'six'), (10, 'ten'), (3, 'three'), (2, 'two')]
[(10, 'ten'), (9, 'night'), (8, 'eight'), (7, 'seven'), (6, 'six'), (5, 'five'), (4, 'four'), (3, 'three'), (2, 'two'), (1, 'one')]

4. countByKey

count返回rdd中元素的個數,返回一個int; countByKey返回rdd中每個元素鍵出現的次數,如果元素是字符串,則將首字母作爲鍵;如果元素是數值類型則報錯 countByValue返回rdd中不同元素出現的個數,返回的是一個字典。

counts = rdd1.count()
print("Number of elements in RDD -> %i" % counts)
print("Number of every elements in RDD -> %s" % rdd1.countByKey())
print("Number of every elements in RDD -> %s" % rdd1.countByValue())

Number of elements in RDD -> 10
Number of every elements in RDD -> defaultdict(<class 'int'>, {1: 1, 6: 1, 7: 1, 2: 1, 3: 1, 4: 1, 5: 1, 8: 1, 9: 1, 10: 1})
Number of every elements in RDD -> defaultdict(<class 'int'>, {(1, 'one'): 1, (6, 'six'): 1, (7, 'seven'): 1, (2, 'two'): 1, (3, 'three'): 1, (4, 'four'): 1, (5, 'five'): 1, (8, 'eight'): 1, (9, 'night'): 1, (10, 'ten'): 1})
rdd1 = sc.parallelize(['hive','hbase','hadoop','spark','flink','storm'])

Number of every elements in RDD1 -> defaultdict(<class 'int'>, {'h': 3, 's': 2, 'f': 1})

5. combineByKey

參數 createCombiner:實現輸入RDD[(K,V)]中V到結果RDD[(K,C)]中C的轉換, V和C可能是相同類型,也可能是不同類型 mergeValue:將V合併到C中 mergeCombiners:對mergeValue產生的C進一步合併,即是reduce操作。

SparkContext.defaultParallelism = 5
rdd = sc.parallelize([('B',1),('B',2),('A',3),('A',4),('A',5)])   
print(rdd.glom().collect()) 
def createCombiner(el):              #el對應每個分區第一個元素的value
    c = el**2
    return c

def mergeValue(aggregated, el):      #aggregated和el分別對應每個分區內已聚合的結果和待聚合的元素
    c = aggregated + el
    return c
def mergeValue2(aggregated, el):   
    c = aggregated                   #此處aggregated初始值是每個分區的第一個元素的value
    return c
def mergeValue3(aggregated, el): 
    c = el                            #此處el是每個分區的最後一個元素的value
    return c

def mergeCombiners(agg1, agg2):       #agg1和agg2對應兩個分區的結果
    c = agg1 + agg2
    return c
result1 = rdd.combineByKey(createCombiner, mergeValue, mergeCombiners)  
result2 = rdd.combineByKey(createCombiner, mergeValue2, mergeCombiners)  
result3 = rdd.combineByKey(createCombiner, mergeValue3, mergeCombiners)  
print(result1.collect())  
print(result2.collect()) 
print(result3.collect()) 

[[('B', 1)], [('B', 2)], [('A', 3)], [('A', 4)], [('A', 5)]]
[('B', 6), ('A', 18)]
[('B', 1), ('A', 9)]
[('B', 3), ('A', 5)]

6. sampleByKey

用於數據的抽樣,可按key指定樣本被抽樣的概率

rdd = sc.parallelize([('A',1),('B',2),('C',3),('A',4),('D',5),('A',6),('A',3),('B',2)])  
rdd2 = rdd.sampleByKey(withReplacement=False,
                        fractions={'A':0.3, 'B':0.5, 'C':0.2, 'D':1})
rdd2.collect()

[('A', 1), ('D', 5), ('A', 6)]

7. subtractByKey

按key是否相同對兩個rdd中的元素進行相減(類似差集)

rdd1 = sc.parallelize([('A',1),('B',2),('C',3),('A',4),('D',5),('A',6),('A',3),('B',2)])  
rdd2 = rdd = sc.parallelize([('A',1),('B',2),('B',8),('E',10)]) 
rdd3 = rdd1.subtractByKey(rdd2)
rdd4 = rdd2.subtractByKey(rdd1)
print(rdd3.collect())
print(rdd4.collectAsMap())

[('D', 5), ('C', 3)]
{'E': 10}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章