2RDD编程

1rdd创建

rdd主要通过从各种文件系统中加载数据和通过并行集合(数组)得来。
sc.textFile用于从文件中读取,sc.parallelize用于python对象生成rdd

1.1通过文件系统加载产生

Spark的SparkContext通过textFile()读取数据生成内存中的RDD,支持本地文件系统、分布式文件系统HDFS及Amazon S3(云端存储服务)等等;

lines=sc.textFile("file:///home/glzt/software/spark/data.txt")
lines.collect()
lines.count()

1.2通过分布式文件系统加载

# 三条语句等价
lines=sc.textFile("hdfs://localhost:9000/home/glzt/software/spark/data.txt")
lines=sc.textFile("/home/glzt/software/spark/data.txt")
lines=sc.textFile("data.txt")

1.3通过并行集合(数组)得来

narry=[1,2,3,4,5]
rdd=sc.parallelize(array)
rdd.collect()
rdd.foreach(lambda x: print(x+1))

对于RDD而言,每一次转换操作都会产生不同的RDD,供一个操作使用;
转换得到的RDD是惰性求值的,也就是说,整个转换过程只是记录了转换的轨迹,并不会发生真正的计算,只有遇到行动操作时,才会发生真正的计算,从源头开始进行“从头到尾”的计算操作。

2转换操作

2.1常用的RDD转换操作API

filter(func) 筛选出满足函数func的元素,并返回一个新的数据集;
map(func)将每个元素传递到函数func中,并将结果返回为一个新的数据集;
flatMap(func)与map()类似,但每个输入元素都可以映射到0个或多个输出结果;
groupByKey()应用于(key, value)键值对的数据集时,返回一个新的(key, iterable)形式的数据集;
reduceByKey(func)应用于(key,value)键值对的数据集时,返回一个新的(key,value)形式的数据集,其中每个值是将每个key传递到函数func中进行聚合后的结果;

lines = sc.textFile("file:///home/glzt/software/spark/data.txt")
lines=lines.map(eval)
# 返回大于55的元素
tem=lines.filter(lambda x: x['predict_data']['predict_value'][0]>55)
tem.foreach(print)
# 返回一个由预测值加100组成的数组
tem.map(lambda x: x['predict_data']['predict_value'][0]+100).collect()
# 用map则将是一个数组是一个元素,返回的是一个包含一系列数组的数组,用flatMap返回的则是一个包含的一系列数据的数组
lines.flatMap(lambda x: x.split(" "))

words = sc.parallelize([('a', 1), ('b', 2), ('a',2),('c',5),('a', 6)])
words1 = words.groupByKey()
words1.foreach(print)

words = sc.parallelize([('a', 1), ('b', 2), ('a',2),('c',5),('a', 6)])
# 先对words使用groupByKey,然后对结果的value进行reduce操作
words1 = words.reduceByKey(lambda x,y: a+b)
words1.foreach(print)

3行动操作

count()返回数据集中的元素个数;
collect()以数组的形式返回数据集中的所有元素;
first()返回数据集中的第一个元素;
take(n)以数组的形式返回数据集中的前n个元素;
reduce(func)通过函数func(输入两个参数并返回一个值)聚合数据集中的元素;
foreach(func)将数据集中的每个元素传递到函数func中运行。

rdd = sc.parallelize([1,2,3,4,5])
rdd.count()
rdd.first()
rdd.take(3)
rdd.reduce(lambda a,b: a+b)
rdd.collect()
rdd.foreach(print)

4持久化

1.可以通过持久化(缓存)机制避免重复计算的开销;
可以使用persist()方法对一个RDD标记为持久化;
之所以说标记为持久化,是因为出现persist()语句的地方,并不会马上计算生成RDD并把他持久化,而是要等到遇到第一个行动操作触发真正计算以后,才会把计算结果持久化;
持久化后的RDD将会被保留在计算节点的内存中被后面的行动操作重复使用。

4.1如何持久化

persist()对一个rdd标记为持久化,并不会马上开始计算生成RDD并把它持久化;动作类型操作才会真正把它持久化。
rdd.persist(MEMORY_ONLY)存储在内存中,内存不足,替换内容;rdd.persist(MEMORY_ONLY)效果同rdd.cache()
rdd.persist(MEMORY_AND_DISK)存储在内存中,内存不足,存放磁盘;
rdd.unpersist()手动把持久化的rdd从缓存中删除;

4.2分区

分区能增加并行度;
减少通信开销;

4.2.1分区原则

分区个数尽量等于集群中CPU核心数目;
local模式默认分区个数为本地的CPU个数,若设置了local[N]则为N个;
apache mesos模式分区数目默认为8;
分区设置方法

# sc.textFile(文件加载的路径, 分区个数),也可以通过repartition重设分区个数
rdd = sc.textFile(path, partitionNum)
# 重设分区为10
rdd = rdd.repartition(10)
# 显示rdd的分区数量
print(len(rdd.glom().collect()))

4.3自定义分区

spark分区有哈希分区、自定义分区及区域分区三种;

from pyspark import SparkConf, SparkContext

def MyPartitioner(key):
    # 以余数作为划区依据
    return key%10

def main():
    # 生成环境对象
    conf = SparkConf().setMaster("local").setAppName("Myapp")
    sc = SparkContext(conf=conf)
    # 创建一个5个分区的rdd
    data = sc.parallelize(range(10), 5)
    # 因为partitionBy只接收键值对的数据,所以先用map转换成键值对,然后传给partitionBy重置分区,分区接受重置分区的个数及分区的自定义函数,然后取出键值对中的键,最后传入一个文件夹给saveAsTextFile,将会在这个文件夹中保存分区的文件。
    data.map(lambda x: (x,1)).partitionBy(10, MyPartitioner).map(lambda x: x[0]).saveAsTextFile("file:///home/glzt/script/spark")

5综合实例

统计一个文本文件中每个单词出现的次数

from pyspark import SparkConf, SparkContext

conf = SparkConf().setMaster("local").setAppName("Myapp")
sc = SparkContext(conf=conf)
lines = sc.textFile("file:///home/glzt/script/spark/word.txt")
# 先用flatMap将每行按空格拆分为单个单词,并组合为一个列表,最后初始化为键值对,最后用reduceByKey对结果按键分组并相加其值,得到其出现的次数
wordCount=lines.flatMap(lambda line: line.split(" ")).map(lambda word: (word, 1)).reduceByKey(lambda a,b: a+b)
print(wordCount.collect())

你可能感兴趣的:(2RDD编程)