RDD常用算子编程-附有代码

一.RDD常用操作

transformation are lazy, noting actually happen until an action is called
action trigger the computation
action returns values to driver or writes data to external storage

二. Transformat

create a new dataset from an existing one
RDD是不可变,所以过程RDDA –》 transforma –》RDDB

  • map

from pyspark import SparkConf, SparkContext
conf = SparkConf().setMaster('local[2]').setAppName('spark1024')
sc = SparkContext(conf=conf)

data = [1,2,3,4]
rdd1 = sc.parallelize(data)
rdd2 = rdd1.map(lambda x: x*2)

结果:

        

         将func函数作用到数据集的每一个元素上,生成一个新的分布式的数据集返回

  • filter

data = [1, 2, 3, 4]
rdd1 = sc.parallelize(data)
rdd2 = rdd1.filter(lambda x: x >2)

结果:

        

  • flatMap

data = ['hello word', 'hello kitty', 'hello spark']
rdd1 = sc.parallelize(data)
rdd2 = rdd1.flatMap(lambda x: x.split(' '))

结果:

        

  • groupByKey

data = ['hello word', 'hello kitty', 'hello spark']
rdd1 = sc.parallelize(data)
rdd2 = rdd1.flatMap(lambda x: x.split(' ')).map(lambda s:(s, len(s)))
rdd3 = rdd2.groupByKey()
print(rdd3.collect())
return rdd3.map(lambda x:{x[0]:list(x[1])}).collect()

结果:

        

  • reduceByKey

data = ['hello word', 'hello kitty', 'hello spark']
rdd1 = sc.parallelize(data)
rdd2 = rdd1.flatMap(lambda x: x.split(' ')).map(lambda s: (s, len(s)))
rdd3 = rdd2.reduceByKey(lambda a, b: a + b)
rdd4 = rdd3.sortByKey(ascending=False)
print(rdd4.collect())
rdd5 = rdd3.map(lambda x:(x[1], x[0])).sortByKey().map(lambda x:(x[1], x[0]))
return rdd5.collect()

结果:

        

  • union

a = sc.parallelize([1,2,3])
b = sc.parallelize([4,5,6])
c = a.union(b)
return c.collect()

结果:

        

  • distinct

a = sc.parallelize([1,2,3,1])
c = a.distinct(a)
print(c.collect())

结果:

        [1, 2, 3]

  • join

a = sc.parallelize([('A','a1'), ('B','b1'),('F','f1')])
b = sc.parallelize([('A', 'a2'), ('B', 'b2'), ('B', 'b3'), ('B', 'b1'), ('E', 'e1')])
return a.join(b).collect()

结果:

        

三. Action

  • collect
  • count
  • take
  • reduce
  • saveAsTextFile
  • foreach
conf = SparkConf().setMaster('local[2]').setAppName('spark1024')
sc = SparkContext(conf=conf)
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
rdd = sc.parallelize(data)
print(rdd.count())
print(rdd.collect())
print(rdd.sum())
print(rdd.take(3))
print(rdd.max())
print(rdd.min())
print(rdd.reduce(lambda x, y:x+y))
rdd.foreach(lambda x: print(x))
rdd.saveAsTextFile('rdd')
sc.stop()

四. 案例

  • txt目录文件夹内容可以为以空格分开的单词, 可以有多个文件:

My father was a self-taught mandolin player. He was one of the best string instrument players in our town. He could not read music, but if he heard a tune a few times, he could play it. When he was younger, he was a member of a small country music band. They would play at local dances and on a few occasions would play for the local radio station. He often told us how he had auditioned and earned a position in a band that featured Patsy Cline as their lead singer. He told the family that after he was hired he never went back. Dad was a very religious man. He stated that there was a lot of drinking and cursing the day of his audition and he did not want to be around that type of environment.

  • 案例代码:

from pyspark import SparkConf, SparkContext
import os

if __name__ == '__main__':
    conf = SparkConf().setMaster('local[2]').setAppName('spark1024')
    sc = SparkContext(conf=conf)

    path = r'/home/spark/txt'
    files = os.listdir(path)
    files = [os.path.join(path, file)for file in files]

    rdd_total = sc.parallelize([])
    for file in files:
        rdd = sc.textFile(file).flatMap(lambda x: x.split(' ')).map(lambda x:(x, 1))
        rdd_total += rdd
    word_frequencys = rdd_total.reduceByKey(lambda x, y: x+y).map(lambda x:(x[1], x[0])).sortByKey(ascending=False).map(lambda x:(x[1], x[0]))

    print('取前3个高频单词', word_frequencys.take(3))
    print('单词总数:', rdd_total.count())
    for (word, frequency) in word_frequencys.collect():
        print(word, ':', frequency)
RDD:弹性分布式数据集(ResilientDistributed Dataset),是Spark对数据的核心抽象。RDD其实是分布式的元素集合。当Spark对数据操作和转换时,会自动将RDD中的数据分发到集群,并将操作并行化执行。 Spark中的RDD是一个不可变的分布式对象集合。每个RDD都倍分为多个分区,这些分区运行在集群中的不同节点。RDD可以包含Python、Java、Scala中任意类型的对象,甚至可以包含用户自定义对象,本文主要通过Java实现相关示例。 Spark程序或shell会话工作流程 1. 从外部数据创建出输入RDD; 2. 使用诸如filter()等这样的转化操作对RDD进行转化,以定义新的RDD; 3. 告诉Spark对需要被重用的中间结果RDD执行persist()操作; 4. 使用诸如first()等这样的行动操作来触发一次并行计算,Spark会对计算进行优化后再执行。 一. 创建RDD Spark提供了两种创建RDD方式: 1. 读取外部数据集,如文件,hive数据库等; 2. 在驱动器程序中对一个集合进行并行化,如list,set等。 方法1是常用方法,其从外部存储中读取数据来创建RDD,如读取文件 方法1创建RDD 方法2其实使用较少,毕竟它需要把整个数据集先放在一台机器的内存中。实现也简单,就是把程序中一个已有集合传给SparkContext的parallelize()方法。二.RDD操作 方法2创建RDD 二. RDD操作 1. RDD支持两种操作: (1) 转化操作,RDD的转化操作是返回一个新的RDD的操作,比如map()和filter。 (2) 行动操作,RDD的行动操作则是向驱动器程序返回结果或把结果入外部系统的操作,会触发实际的计算,比如count()和first()。 惰性求值:RDD的转化操作是惰性求值的,即在被调用行动操作之前Spark不会开始计算,相反,Spark会在内部记录下索要求执行的操作的相关信息。例如,当我们调用jsc.textFile()时,数据并没有读取进来,而是在必要时才会读取。Spark使用惰性求值,就可以把一些操作合并到一起来减少计算数据的步骤。 2. RDD的基本转化操作 函数名 目的 示例 结果 map() 将函数应用于RDD的每一元素, 将返回值构成新的RDD rdd.map(x=>x+1) {2,3,4,4} flatMap() 将函数应用于RDD的每一元素, 将返回的迭代器的所有内容构成新的RDD. 通常用于切分单词 rdd.flatMap(x=>x.to(3)) {1,2,3,2,3,3,3} filter() 返回一个由通过传给filter()的函数 的元素组成的RDD rdd.filter(x=>x!=1) {2,3,3} distinct() 去重 rdd.distinct() {1,2,3) sample(withReplacement, fraction,[seed]) 对RDD采用,以及是否替换 rdd.sample(false,0.5) 非确定的 对一个数据为{1,2,3,3}的RDD进行基本的RDD转化操作 函数名 目的 示例 结果 union() 生成一个包含两个RDD 中所有元素的RDD rdd.union(other) {1, 2, 3, 3, 4, 5} intersection() 求两个RDD 共同的元素的RDD rdd.intersection(other) {3} subtract() 移除一个RDD 中的内容(例如移除训练数据) rdd.subtract(other) {1, 2} cartesian() 与另一个RDD 的笛卡儿积 rdd.cartesian(other) {(1, 3), (1, 4), ...(3, 5)} 对数据分别为{1, 2,3}和{3, 4, 5}的RDD进行针对两个RDD的转化操作 3. RDD的基本执行操作 函数名 目的 示例 结果 collect() 返回RDD 中的所有元素 rdd.collect() {1, 2, 3, 3} count() RDD 中的元素个数 rdd.count() 4 countByValue() 各元素在RDD 中出现的次数 rdd.countByValue() {(1, 1),(2, 1),(3, 2)} take(num) 从RDD 中返回num 个元素 rdd.take(2) {1, 2} top(num) 从RDD 中返回最前面的num个元素 rdd.top(2) {3, 3} takeOrdered(num) (ordering) 从RDD 中按照提供的顺序返回最前面的num 个元素 rdd.takeOrdered(2)(myOrdering) {3, 3} takeSample(withReplacement, num, [seed]) 从RDD 中返回任意一些元素 rdd.takeSample(false, 1) 非确定的 reduce(func) 并行整合RDD 中所有数据(例如sum) rdd.reduce((x, y) => x + y) 9 fold(zero)(func) 和reduce() 一样, 但是需要提供初始值 注意:不重复元素加初始值,重复元素只加一个 rdd.fold(0)((x, y) => x + y) 9 aggregate(zeroValue) (seqOp, combOp) 和reduce() 相似, 但是通常返回不同类型的函数 注意:不重复元素加初始值,重复元素只加一个 rdd.aggregate((0, 0))((x, y) => (x._1 + y, x._2 + 1),(x, y) => (x._1 + y._1, x._2 + y._2)) (9,4) foreach(func) 对RDD 中的每个元素使用给定的函数 rdd.foreach(func) 无 对一个数据为{1, 2,3, 3}的RDD进行基本的RDD行动操作 4. 标准Java函数接口 在Java中,函数需要作为实现了Spark的org.apache,spark.api.java.function包中的任一函数接口的对象传递。 函数名 实现的方法 用途 Function<T, R> R call(T) 接收一个输入值并返回一个输出值,用于类似map() 和filter() 等操作中 Function2<T1, T2, R> R call(T1, T2) 接收两个输入值并返回一个输出值,用于类似aggregate()和fold() 等操作中 FlatMapFunction<T, R> Iterable<R> call(T) 接收一个输入值并返回任意个输出,用于类似flatMap()这样的操作中 标准Java函数接口 5. Java中针对专门类型的函数接口 函数名 等价函数 用途 DoubleFlatMapFunction<T> Function<T, Iterable<Double>> 用于flatMapToDouble,以生成DoubleRDD DoubleFunction<T> Function<T, Double> 用于mapToDouble,以生成DoubleRDD PairFlatMapFunction<T, K, V> Function<T, Iterable<Tuple2<K, V>>> 用于flatMapToPair,以生成PairRDD<K, V> PairFunction<T, K, V> Function<T, Tuple2<K, V>> 用于mapToPair, 以生成PairRDD<K, V> Java中针对专门类型的函数接口 三. 示例 本节将通过示例的方式验证第二节中相关的转化操作和行动操作。 转化和行动计算结果 代码地址: 参考文献: 王道远 《Spark 快速大数据分析》
这段代码主要是用来读取MySQL中的数据,并对数据中的taglist进行处理,将每一行的taglist转换为列表,然后统计列表中每个tag的出现次数,最后将结果排序并输出前五个tag及其对应的出现次数。 具体每行代码的含义如下: 1. `spark = SparkSession.builder.getOrCreate()`:创建一个SparkSession实例,如果已经存在则获取已存在的实例。 2. `data = spark.read.format("jdbc").options(**options).load()`:从MySQL中读取数据,并将数据存储为DataFrame格式。 3. `def convert_to_list(line):`:定义一个转换函数,用来将每行的taglist转换为列表。 4. `tmp_list = line[0].replace("#", "").split(",")`:将每行的taglist去掉#号,并按逗号分割,得到一个tag的列表。 5. `datas = []`:定义一个空列表,用来存储tag及其出现次数。 6. `for i in tmp_list:`:遍历每个tag。 7. `if len(i) > 0 and "牛" not in i:`:如果tag长度大于0且不包含“牛”。 8. `datas.append((i, 1))`:将tag及其出现次数1添加到列表datas中。 9. `return datas`:返回列表datas。 10. `rdd = data.rdd.flatMap(lambda line: convert_to_list(line)).reduceByKey(lambda x, y: x + y)`:将DataFrame转换为RDD,并对RDD中的tag进行统计,得到每个tag及其对应的出现次数。 11. `schemaString = "tag count"`:定义一个字符串,用来表示DataFrame的列名。 12. `fields = [StructField(field_name, StringType(), True) for field_name in schemaString.split()]`:根据列名字符串,定义一个包含两个字段(tag和count)的结构体。 13. `schema = StructType(fields)`:根据结构体定义,创建DataFrame的schema。 14. `schema_data = spark.createDataFrame(rdd, schema).orderBy("count", ascending=False)`:基于RDD和schema,创建DataFrame,并按照count字段进行降序排序。 15. `result_pdf = schema_data.limit(5).toPandas()`:将DataFrame转换为Pandas数据帧,并取前五行数据。 16. `plt.rcParams['font.family'] = ['sans-serif']`:设置matplotlib支持中文。 17. `plt.rcParams['font.sans-serif'] = ['SimHei']`:设置matplotlib使用SimHei字体。 18. `plt.pie(result_pdf["count"], labels=result_pdf["tag"], shadow=True, autopct='%1.1f%%')`:绘制饼图,以tag为标签,以count为数据,并显示百分比。 19. `plt.legend()`:添加图例。 20. `plt.show()`:显示图形。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值