from pyspark import SparkConf, SparkContext
from pyspark import SparkContext
from operator import add
import os
'''
1.txt 文件中的内容为:
hello world hahah how are you
todo world world hello world hahah how
hello world hahah how
'''
if __name__ == "__main__":
os.environ['JAVA_HOME']='/home/taoke/apps/java/jdk1.8.0_231' # JAVA_HOME 目录
conf = SparkConf().setMaster('spark://localhost:7077').setAppName('word_count') # 连接spark,设置app名
sc = SparkContext(conf=conf) # 通过配置创建SparkContext
rdd = sc.textFile('1.txt') # 读取本地文件1.txt
.flatMap(lambda x: x.split(" ")) # 将读取到的每一行进行按空格分离
.map(lambda x: (x, 1)) # 对每个元素进行x=>(x,1)的处理
.reduceByKey(add) # 通过每个元素的第二个相加得到统计数量
.sortBy(lambda x:x[1]) # 通过第二个元素进行排序
.collect() # 获取计算结果
print(rdd)
sc.stop()
RDD API文档
https://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-distributed-datasets-rdds
https://spark.apache.org/docs/latest/api/python/pyspark.html#pyspark.RDD
迭代源RDD的每个数据,分别使每个数据通过func形成一个新的RDD。
>>> rdd = sc.parallelize([1,2,3,4,5])
>>> rdd1 = rdd.map(lambda x:x+1)
>>> rdd1.collect()
[2, 3, 4, 5, 6]
迭代源RDD的每个数据,分别使每个数据通过func进行过滤形成一个新的RDD。
>>> rdd = sc.parallelize([1,2,3,4,5])
>>> rdd1 = rdd.filter(lambda x:x>3)
>>> rdd1.collect()
[4, 5]
将数据拆分扁平化,举两个例子体会一下。
>>> rdd = sc.parallelize([(1,2),(2,3),(3,4),(4,5),(5,6)])
>>> rdd1=rdd.flatMap(lambda x:x)
>>> rdd1.collect()
[1, 2, 2, 3, 3, 4, 4, 5, 5, 6]
>>> rdd = sc.parallelize(["a b","c d 12 44","e aa f","g h","j kk l"])
>>> rdd1=rdd.flatMap(lambda x:x.split(" "))
>>> rdd1.collect()
['a', 'b', 'c', 'd', '12', '44', 'e', 'aa', 'f', 'g', 'h', 'j', 'kk', 'l']
mapPartitions是map的一个变种。map的输入函数是应用于RDD中每个元素,而mapPartitions的输入函数是应用于每个分区,也就是把每个分区中的内容作为整体来处理。
>>> from pyspark import SparkFiles
>>> path = os.path.join(tempdir, "test.txt")
>>> with open(path, "w") as testFile:
... _ = testFile.write("100")
>>> sc.addFile(path)
>>> def func(iterator):
... with open(SparkFiles.get("test.txt")) as testFile:
... fileVal = int(testFile.readline())
... return [x * fileVal for x in iterator]
>>> sc.parallelize([1, 2, 3, 4]).mapPartitions(func).collect()
[100, 200, 300, 400]
迭代Partitions的索引号
>>> rdd = sc.parallelize([1, 2, 3, 4], 4)
>>> def f(splitIndex, iterator): yield splitIndex
>>> rdd.mapPartitionsWithIndex(f).sum()
6
对RDD数据进行取样
withReplacement:Boolean , True表示进行替换采样,False表示进行非替换采样
fraction:Double, 在0~1之间的一个浮点值,表示要采样的记录在全体记录中的比例
seed:随机数种子
>>> rdd = sc.parallelize(range(100), 4)
>>> rdd1 = rdd.sample(False, 0.1, 81)
>>> rdd1.collect()
[4, 26, 39, 41, 42, 52, 63, 76, 80, 86, 97]
union(otherDataset)是数据合并,返回一个新的数据集,由原数据集和otherDataset联合而成。
>>> rdd = sc.parallelize([1,2,3,4,5])
>>> rdd1 = sc.parallelize([4,5,6,7,8])
>>> rdd2 = rdd.union(rdd1)
>>> rdd2.collect()
[1, 2, 3, 4, 5, 4, 5, 6, 7, 8]
两个rdd数据的交集,并返回一个新的rdd
>>> rdd1 = sc.parallelize([1, 10, 2, 3, 4, 5])
>>> rdd2 = sc.parallelize([1, 6, 2, 3, 7, 8])
>>> rdd1.intersection(rdd2).collect()
[1, 2, 3]
对rdd数据进行去重操作,与sql中的distinct功能类似。
>>> rdd = sc.parallelize([1,1,2,3,3,3,4,5])
>>> rdd1=rdd.distinct()
>>> rdd1.collect()
[1, 2, 3, 4, 5]
按key分组
>>> rdd = sc.parallelize([("a",1),("b",1),("c",1),("a",1),("b",1)])
>>> rdd1=rdd.groupByKey()
>>> rdd1.collect()
[('a', <pyspark.resultiterable.ResultIterable object at 0x7f875b63b690>), ('b', <pyspark.resultiterable.ResultIterable object at 0x7f875b63b3d0>), ('c', <pyspark.resultiterable.ResultIterable object at 0x7f875b63b750>)]
>>> rdd2 = rdd1.mapValues(list)
>>> rdd2.collect()
[('a', [1, 1]), ('b', [1, 1]), ('c', [1])]
说明:rdd通过groupByKey变为(k,pyspark.resultiterable.ResultIterable)形式的rdd1,rdd1通过mapValues(list)将值映射为list的形式。
对rdd数据进行聚合操作
>>> from operator import add
>>> rdd = sc.parallelize([("a", 1), ("b", 1), ("a", 1)])
>>> sorted(rdd.reduceByKey(add).collect())
[('a', 2), ('b', 1)]
第一个参数是, 每个key的初始值
第二个是个函数, Seq Function, 经测试这个函数就是用来先对每个分区内的数据按照key分别进行定义进行函数定义的操作
第三个是个函数, Combiner Function, 对经过 Seq Function 处理过的数据按照key分别进行进行函数定义的操作
通过key排序
>>> rdd = sc.parallelize([(3, 1), (2, 1), (4, 1), (3, 2)])
>>> rdd1 = rdd.sortByKey()
>>> rdd1.collect()
[(2, 1), (3, 1), (3, 2), (4, 1)]
join(otherDataset, [numTasks])是连接操作,将输入数据集(K,V)和另外一个数据集(K,W)进行Join, 得到(K, (V,W));该操作是对于相同K的V和W集合进行笛卡尔积 操作,也即V和W的所有组合;
>>> x = sc.parallelize([("a", 1), ("b", 4)])
>>> y = sc.parallelize([("a", 2), ("a", 3)])
>>> sorted(x.join(y).collect())
[('a', (1, 2)), ('a', (1, 3))]
cogroup(otherDataset, [numTasks])是将输入数据集(K, V)和另外一个数据集(K, W)进行cogroup,得到一个格式为(K, Seq[V], Seq[W])的数据集。
>>> rdd1 = sc.parallelize([("aa",1),("bb",2),("cc",6)])
>>> rdd2 = sc.parallelize([("aa",3),("dd",4),("aa",5)])
>>> rdd1.cogroup(rdd2).collect()
[('aa', (<pyspark.resultiterable.ResultIterable object at 0x7f875b62cb10>, <pyspark.resultiterable.ResultIterable object at 0x7f875c2151d0>)), ('cc', (<pyspark.resultiterable.ResultIterable object at 0x7f875b62ca90>, <pyspark.resultiterable.ResultIterable object at 0x7f875b62cc10>)), ('bb', (<pyspark.resultiterable.ResultIterable object at 0x7f875b62c9d0>, <pyspark.resultiterable.ResultIterable object at 0x7f875b62ce10>)), ('dd', (<pyspark.resultiterable.ResultIterable object at 0x7f875b62cdd0>, <pyspark.resultiterable.ResultIterable object at 0x7f875b62cbd0>))]
>>> l = list(rdd1.cogroup(rdd2).collect())
>>> for k,v in l:
... print(k, [list(i) for i in v])
aa [[1], [3, 5]]
cc [[6], []]
bb [[2], []]
dd [[], [4]]
对每个rdd的每个元素进行分别取值合并,生成新的rdd
>>> rdd = sc.parallelize([1,2,3])
>>> rdd1 = sc.parallelize([4,5])
>>> rdd2 = rdd.cartesian(rdd1)
>>> rdd2.collect()
[(1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)]
通过外部进程生成rdd
>>> sc.parallelize(['1', '2', '', '3']).pipe('ls').collect()
['hive', 'spark']
>>> sc.parallelize(['1', '2', '', '3']).pipe('cat').collect()
['1', '2', '', '3']
重设RDD 的Partition数
>>> sc.parallelize([1, 2, 3, 4, 5], 3).coalesce(1).glom().collect()
[[1, 2, 3, 4, 5]]
>>> sc.parallelize([1, 2, 3, 4, 5], 3).coalesce(2).glom().collect()
[[1], [2, 3, 4, 5]]
>>> sc.parallelize([1, 2, 3, 4, 5], 3).coalesce(3).glom().collect()
[[1], [2, 3], [4, 5]]
返回一个恰好有numPartitions个分区的RDD,可以增加或者减少此RDD的并行度。内部,这将使用shuffle重新分布数据,如果你减少分区数,考虑使用coalesce,这样可以避免执行shuffle
>>> rdd = sc.parallelize([1,2,3,4,5,6,7], 4)
>>> sorted(rdd.glom().collect())
[[1], [2, 3], [4, 5], [6, 7]]
>>> len(rdd.repartition(2).glom().collect())
2
>>> len(rdd.repartition(10).glom().collect())
10
repartitionAndSortWithinPartitions算是一个高效的算子,是因为它要比使用repartition And sortByKey 效率高,这是由于它的排序是在shuffle过程中进行,一边shuffle,一边排序;
>>> rdd = sc.parallelize([(0, 5), (3, 8), (2, 6), (0, 8), (3, 8), (1, 3)])
>>> rdd2 = rdd.repartitionAndSortWithinPartitions(2, lambda x: x % 2, True)
>>> rdd2.glom().collect()
[[(0, 5), (0, 8), (2, 6)], [(1, 3), (3, 8), (3, 8)]]