RDD编程学习

:::tips
此处学习过程为 _JAVA _版本,但API基本相同(只存在部分差异,比如rdd切分操作partition在python中为parallelize),替换即可,不影响学习。
代码块中的代码均为 _pyspark _版本,可直接使用。
:::

RDD编程基础

什么是RDD:

概念:一个弹性分布式数据集

RDD的特征 :分区列表
· 计算函数:用于计算每个分区的函数
· 依赖关系:对其他RDD的依赖关系表
· 分区器:可选的,键值RDD的分区器
· 首选位置:可选的,计算每个拆分的首选位置列表(例如HDFS)

Wordcount中的RDD五大属性

image.png

RDD的创建:

数据来源

RDD中的数据可以来自两个地方:本地集合或外部数据源
image.png

RDD的构建方法(Java/python)

模拟创建来验证代码:
image.png
创建结果:
image.png
小结:
image.png

RDD的主要操作:

操作类型

image.png
image.png
tips
如:先让小明去喊小王,小明不动;再让小明喊小张,小明还不动;这个时候给小明发送:行动指令(action),小明开始行动

在这里称之为惰性机制。

基本算子/操作/方法/API(java/python)

map
faltMap
filter
foreach
saveAsTextFile
groupByKey
reduceByKey

image.png
输出:
image.png

转换操作(python实现):

1.0 传递文件函数textFile()加载数据
lines = sc.textFile("file:///home/master/test.txt")   ##换成自己的位置
lines.foreach(print)																	##打印每个元素

image.png
530F81420ACE883BE9E0135835648D48.jpg

lines=sc.textFile("hdfs://localhost:9000/zcw666/test6.txt")   
lines=sc.textFile("/zcw666/test6.txt")
lines=sc.textFile("test6.txt")                   ##只在路径内起作用!

image.png

2.0 .parallelize()创建RDD函数
array=[1,2,3,4,5,6]
rdd = sc.parallelize(array)
rdd.foreach(print)

image.png
*此处结果为乱序(哈希存放?应该是)
A86CE6ED8AAB5D479CE3B04732EC65A3.jpg
通过parallelize操作进行分区,分区为数组

3.0 filter筛选函数
lines=sc.textFile("file:///home/master/test.txt")
linesWithSpark = lines.filter(lambda line:"hello" in line)
linesWithSpark.foreach(print)

image.png
一个筛选函数,筛选符合条件的值并返回到一个新的数据集
C320D9D4FF6421A7DC99F0464C88D0C6.jpg

4.0几种Map映射函数
data=[1,2,3,4,5]
rdd1=sc.parallelize(data)
rdd2=rdd1.map(lambda x:x+10)
rdd2.foreach(print)

image.png
与python中的map映射函数类似,用于对rdd进行操作
C2C030459CB4035E1DE31659384EA48E.jpg

lines=sc.textFile("file:///home/master/test.txt")
words=lines.map(lambda line:line.split(""))
words=lines.map(lambda line:line.split(" "))
words.foreach(print)

image.png
6F1F1451256551B29193F8B7AD28CA9A.jpg

lines=sc.textFile("file:///home/master/test.txt")
words=lines.flatMap(lambda line:line.split(" "))
words.foreach(print)

image.png
B7B07B23425D8740AD93F99476E940B3.jpg
等同于先map再flat拍平

5.0聚合函数reduceByKey(func)
words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])
words1=words.reduceByKey(lambda a,b:a+b)
words1.foreach(print)

image.png
E8E40D054212A0B41177FFA32132A93A.jpg

6.0 返回分组函数groupByKey()
words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])            
words1=words.groupByKey()
words1.foreach(print)

image.png
34BBF416437C9EB2FC7DB8F5BE20C539.jpg

行动操作:

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

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

image.png

RDD的持久化(python):

持久化(缓存)可以用来避免惰性机制的迭代计算开销过大的问题,原本每一次进行action便会重新进行一次transformation,加了持久化后第一次计算后便会在一段时间内不再需要重新transformation。
具体使用方法为:使用persist()方法
一般而言使用cache()方法就会调用persist()

list=['hadoop','hello','hive']
rdd= sc.parallelize(list)
rdd.cache()
print(rdd.count())
print(','.join(rdd.collect()))

image.png

RDD的分区操作java

image.png

map:表示针对分区中的每一个数据进行操作
mapPartions: 表示针对每个分区进行操作
foreach 同理

重分区函数

image.png
image.png

聚合函数

image.png
image.png

注意这里只进行了Action,没有进行transform

image.png
image.png
image.png
image.png

关联函数

image.png
image.png
image.png

排序函数

image.png
image.png

sortBy //可以根据其他字段进行排序的RDD
sortByKey //返回一个根据key排序的RDD
---------------------------------------------------------------------------------------------------------
*top //按照RDD中的数据采用降序的方式排序,如果是键值对按照Key降序排序
*只有在结果数字很小的时候能够使用top(返回的是数组)

//需求:求结果的TOP3
image.png

RDD的分区操作python

分区的原因:

不分区进行数据处理容易造成数据混洗,网络传输开销大,分区可大大减少数据混洗的情况。
FA42701BA2627D5558BC1DACB96AD7B8.jpg
0FC73D2195D319036D4597F265739AB7.jpg

分区的原则:

1.尽量等于集群中的CPU核心(core)数目
对于任意的spark部署模式都可以通过设置:spark.default.parallelism 这个参数值,来配置默认的分区数目。

设置分区的个数:

1.创建RDD的时候手动设定分区个数:
sc.textFile(path,partitionNum)

list=[1,2,3,4,5,6]
rdd=sc.parallelize(list,2)  //设置两个分区

如果不设置分区数量
:::tips
对于textFile()会默认为min(defailtParallelism,2)defailtParallelism这个值对应spark.default.parallelism
:::
:::tips
对于parallelize()会默认spark.default.parallelism 这个参数值
:::

2.重新设置分区个数repartition:

使用repartition方法

data=sc.parallelize([1,2,3,4,5],2)
len(data.glom().collect())   //显示data这个rdd分区数量

rdd=data.repartition(1)       //重新设置这个分区数量
len(rdd.glom().collect())     //再次显示rdd数量

image.png

自定义分区方法(拓展):

spark自带HashParatitioner(哈希分区)与RangeParatitioner(区域分区),能够满足大多数的场景。同时也支持自定义分区。(自学)

RDD基础示例

文件内容:

hello world
hello spark
hello hadoop
hahahhahahahah
wojiuzhidaonihuifanyizhejuhuade
Anallve.cityz-19

lines=sc.textFile("file:///home/master/test.txt")
str=lines.flatMap(lambda line :line.split(' '))
dir=str.map(lambda a:(a,1))
wordcount=dir.reduceByKey(lambda a,b:a+b)
wordcount.foreach(print)

结果:
image.png

RDD键值对

键值对RDD的创建

键值对的创建主要有两种方式:
1.文件中加载生成RDD
2.通过并行集合(列表)创建RDD

从文件中加载

首先使用file()方法从文件中加载数据,然后使用map()函数转换得到相应的键值对RDD

lines=sc.textFile("file:///home/master/test.txt")
pairRDD=lines.flatMap(lambda line :line.split(" ")).map(lambda a:(a,1)).foreach(print)

image.png

通过并行集合创建RDD
list=['a','b','n','m','j','c']
rdd=sc.parallelize(list)
pairRDD=rdd.map(lambda word:(word,1)).foreach(print)

image.png

常用的键值对转换操作

1.0 聚合函数reduceByKey(func)

(同上文聚合函数5.0)

words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])
words1=words.reduceByKey(lambda a,b:a+b)
words1.foreach(print)

image.png

2.0 分组函数groupByKey()

(同上文分组函数6.0)

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

image.png

reduceByKey可以聚合操作,但groupByKey不可以,需要加上map()函数才可以达到根reduceByKey一样的效果。两者本就殊途同归

words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])            
words1=words.groupByKey()
words2=words1.map(lambda x:(x[0],sum(x[1])))
words2.foreach(print)

image.png

3.0 keys,valus 返回函数

返回关键字key

words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])            
words2.keys().foreach(print)

image.png
返回关键字value

words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])            
words2.values().foreach(print)

image.png

4.0 sortByKey 排序

函数会根据key排序

words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])
words.sortByKey().foreach(print)

image.png

5.0 sortBy排序

函数可以根据其他字段排序

words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])
words.reduceByKey(lambda a,b:a+b).sortByKey(false).collect()
注意这里必须采用collcet()收集才能正常排序,单独使用sortByKey容易出错!上面4.0同理,可以看出来并不是升序的

image.png

6.0mapValues(func)

对键值对的value进行map函数操作

words= sc.parallelize([("a",1),("b",1),('a',1),("c",2),('b',3)])
words1=words.mapValues(lambda x:x**2)
words1.foreach(print)

image.png

7.0 join

join表示连接,对给定的两个键值(K,V1)和(K,V2)对进行连接得到(k,(V1,V2))类型的数据集。

words= sc.parallelize([("a","10.30"),("b",1),('d',1),("c",2),('b',3)])
words1= sc.parallelize([("a","birthday"),("b",1),('d',1),("c",2),('b',3)])
word=words.join(words1)
word.foreach(print)

image.png
8.0 combineByKey
combineByKey(createCombiner,mergeValue,mergeCombiners,partitioner,mapSideCombine)
:::warning

  1. createCombiner:在第一次遇到key时创建组合器函数,将RDD数据集中的V类型转化为C类型值(V=>C);
  2. mergeValue:合并值函数,再次遇到相同的Key时,将createCombiner传出的C值类型与这次传人的V值进行合并成一个C值类型
  3. mergeCombiners:合并组合器函数,将C类型值两两合并成一个C值类型;
  4. partitioner:使用已有的或者自定义的分区函数,默认为HashPartitioner
  5. mapSideCombine:是否在map端进行Combine操作,默认为Ture
    :::
from pyspark import SparkConf,SparkContext
conf = SparkConf().setMaster("local").setAppName("Combine")
sc=SparkContext(conf=conf)


data=sc.parallelize([('company1',57),('company1',30),('company2',55),('company1',15),\
('company3',30),('company2',11),('company2',18),('company3',62),],3)
res=data.combineByKey(\
    lambda income:(income,1),\
    lambda acc,income:(acc[0]+income,acc[1]+1),\
    lambda acc1,acc2:(acc1[0]+acc2[0],acc1[1]+acc1[1])).\
    map(lambda x:(x[0],x[1][0],x[1][1],x[1][0]/x[1][1]))
res.repartition(1).saveAsTextFile('file:///home/master/combineresult')

image.png
image.png

数据读写:

1.文件数据的读写

1.1本地文件的读写(textFile)
textfile=sc.textFile("file:///home/master/test.txt")
textfile.first()

image.png

1.2本地文件的写()
textfile=sc.textFile("file:///home/master/test.txt")
textfile.saveAsTextFile("file:///home/master/test1")

image.png
image.png

注:写入的是RDD类型的文件

这里的rdd默认以需要的内核数打开(我这里为2),实际情况可能需要发生改变,可以尝试使用:

pyspark --master local[1]

textfile=sc.textFile("file:///home/master/test.txt")
textfile.saveAsTextFile("file:///home/master/test2")

来限制内核数量
image.png
image.png
image.png

2.HDFS的读写操作(textFile)
>>> textfile=sc.textFile("hdfs://zcw666/test.txt")
>>> textfile=sc.textFile("/zcw666/test.txt")
>>> textfile=sc.textFile("test.txt")
>>> textfile.saveAsTextFile("test11")
>>> textfile=sc.textFile("/zcw666/test1.txt")
>>> textfile.saveAsTextFile("/zcw666/new_test1")

image.png

后续补充学习

RDD.count() → int       元素数量计算
lines.filter(lambda line :(len(line.strip())>0)  去掉空行的语句
##filter:过滤器
if __namea__=='__main__':
	main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值