【spark】4.键值对操作

本文深入探讨了Spark中PairRDD的基本概念、创建方式、转化操作、聚合操作及并行度调优等关键内容,通过实例展示了如何利用PairRDD进行数据处理和分析。


键值对RDD是Spark中许多操作所需要的常见数据类型,被称为pairRDD,提供了并行操作各个键或者跨界点重新进行数据分组的操作接口。

创建PairRDD

1.使用map()函数将普通RDD转换为PairRDD。

lines=sc.parallelize(["pandas","i like pandas"])
pairs = line.map(lambda x:(x[0],x))

PairRDD转化操作

以键值对{(1,2),(3,4),(3,6)}为例

函数名目的示例结果
reduceByKey(func)合并具有相同键的值rdd.reduceByKey(lambda x,y: x+y){(1,2),(3,10)}
groupByKey()按照键对RDD进行分组rdd.groupByKey(){(1,[2]),(3,[4,6])}
comBinByKey()使用不同的返回类型合并具有相同键的值示例见下
mapValues(func)对pair的每一个值应用一个函数而不改变键值rdd.mapValues(lambda x:x+1){(1,3),(3,5),(3,7)}
flatMapValues(func)对pair的每一个值应用一个迭代器行数,然后对返回的每一个元素都生成对用原值键值对记录rdd.flatMapValues(lambda x: (3,5)){(1,3),(1,5),(3,3),(3,5),(3,3),(3,5)}
keys()返回一个包含所有键的RDDrdd.keys(){1,3,3}
values()返回一个包含所有值的RDDrdd.values(){2,4,6}
sortByKey()返回一个根据键值排序的RDDrdd.sortByKey(){(1,2),(3,4),(3,6)}

以键值对{(1,2),(3,4),(3,6)}和other={(3,9)}为例

函数名目的示例结果
subtractByKey删除pair中键与other rdd键相同的元素rdd.subtractByKey(other){(1,2)}
join对两个rdd进行内连接rdd.join(other){(3,(4,9)),(3,(6,9))}
rightOuterJoin右外连接rdd.rightOuterJoin(other){(3,(4,9)),(3,(6,9))}
leftOuterJoin左外连接rdd.leftOuterJoin(other){(1,(2,none))(3,(4,9)),(3,(6,9))}
cogroup将两个RDD中拥有相同键的数据分组到一起rdd.cogroup(other){(1,([2],[])),(3,([4,6],[9]))}

同时pairrdd也支持普通RDD所支持的函数,传送门,例如

#对值进行筛选
result = pair.filter(lambda x:len(x)>20)

聚合操作

pair RDD提供的针对键的转化操作,类似以基础RDD的fold(),combine(),reduce()等行动操作。

reducceByKey()

#计算键对应的平均值
rdd.mapValues(lambda x :(x,1)),reduceByKey(lambda x,y:(x[0]+y[0],x[1]+y[1]))

foldByKey()

类似于上一个,但需要初始值

combineByKey()

combinByKey()会遍历所有分区中的元素,包含3个过程:

  • 如果是一个新的元素,使用createCombiner()函数创建该键对应的累加器的初始值,这一过程在每一个分区都发生。
  • 如果是已经遇到的键,使用mergeValue()方法将该键对应的累加器的当前值于新的值进行合并
  • 因为每个分区都是独立进行处理的,同一个键可能有多个累加器,所以需要使用用户提供的mergeCombiner()方法将各个分区的结果进行合并。
sumCount = num.combineByKey((lambda x: (x,1),
							(lambda x,y: (x[0]+y,x[1]+1)),
							(lambda x,y: (x[0]+y[0],x[1]+y[1]))))

并行度调优

spark始终尝试根据集群大小来推断出一个有意义的默认值来确认分区数,但是有时需要我们主动调优。

data = [('a',3),('b',4),('a',1)]
sc.parallelize(data).reduceByKey(lambda x,y: x +y ) # 默认
sc.parallelize(data).reduceByKey(lambda x,y: x +y, 10) # 自定义并行度

数据分组

groupByKey() 对当个RDD进行分组结果为 [(k,[V])]
cogroup() 对多个rdd进行分组结果为[(K,([V1],[V2]))]

连接

见上表

数据排序

sortByKey() 使用参数ascending来选择正序还是倒序。

行动操作

以键值对{(1,2),(3,4),(3,6)}为例

函数名目的示例结果
countByKey()对键进行统计rdd.countByKey(){(1,1),(3,2)}
collectAsMap()将结果以映射表的形式返回,以便于查询rdd.collectAsMap()map{(1,2),(3,6)}
lookup(key)返回对应键的所有值rdd.lookup(1)[2]

数据分区

对数据集在节点间的分区进行控制,在分布式程序中节点之间的通信代价很大。

### Spark 运行基本流程 Spark应用程序的执行遵循一系列特定阶段,从初始化到任务调度再到最终的结果收集。当创建`SparkContext`实例时,配置信息被传递给它来指定应用如何连接至集群管理器[^2]。 一旦上下文建立完成,用户定义的操作会被转换成DAG(Directed Acyclic Graph),即有向无环图形式的任务计划。对于批处理作业而言,在遇到诸如`collect()`这样的触发动作之前,所有的转换操作都是惰性的;只有当行动算子被执行时才会真正启动计算过程,并且会尽可能利用中间结果缓存机制减少重复运算开销。 ```scala val conf = new SparkConf().setMaster("yarn").setAppName("test") val spark = SparkSession.builder.config(conf).getOrCreate val df = spark.sql("select * from tb_a").collect() ``` 上述代码展示了通过YARN作为资源管理器提交一个简单的SQL查询请求的过程。这里值得注意的是`.collect()`方法的应用——这标志着由前面构建起来的一系列懒加载式的变换将在此刻变为实际行动以获取整个表的内容并返回给Driver端。 ### 数据抽象 在Spark中有多种用于表示数据集合的方式: - **RDD (Resilient Distributed Dataset)** 是最基础也是最早引入的一种不可变分布式对象列表结构,支持广泛而灵活的各种API来进行复杂的数据处理逻辑编码[^1]。 - 对于结构化或半结构化的表格型资料,则更推荐采用DataFrame API 或者Dataset API 。它们不仅提供了更加简洁易读语法糖衣包裹下的强大功能集,而且内部实现了优化过的物理执行引擎Catalyst从而提高了性能表现[^3]。 例如,如果有一个包含整数序列的List,那么它可以很容易地转化为具有两个分片(Partition) 的RDD实例 `p1(1,2)` 和 `p2(3,4)` 来实现并行度提升。 ### Scala 中 apply 方法的作用 `apply()` 函数通常用来简化类实例化或其他容器类型的访问方式。具体来说就是允许开发者像数组那样直接使用圆括号加参数的形式去调用某个对象的方法而不是显式写出其名称加上点符号再跟上目标成员名这种较为冗长的做法[^5]。 比如下面这段伪码就很好地诠释了这一点: ```scala // 假设我们有一个名为MyClass的类 object MyClass { def apply(x: Int): String = s"The value is $x" } println(MyClass(42)) // 输出 "The value is 42" ``` 在这个例子中,即使没有看到任何关于new关键字或者构造函数的具体调用,仍然能够成功获得预期的对象状态描述字符串输出[^5]。 ### 部署模式概述 Spark 支持几种不同的部署环境设置选项,包括但不限于本地单机版(Local Mode),独立集群模式(Standalone Cluster Manager), Apache Mesos 及 Hadoop YARN 资源管理系统等[^4]。 其中一种常见的生产环境中使用的方案便是借助YARN来管理和分配多租户共享的大规模硬件设施上的计算资源。此时可以通过命令行工具spark-submit配合相应参数指明master URL以及其他必要的属性来自动生成相应的Application Master进程并与之通信协调Worker Nodes之间的协作关系。 ```bash /opt/apps/spark-3.0.1-bin-hadoop3.2/bin/spark-submit \ --master yarn \ --class cn.doit.spark.day01.demo01.WordCount \ /opt/apps/WordCount.jar \ hdfs://linux01:8020/words \ hdfs://linux01:8020/wordcount ``` 此脚本片段说明了怎样在一个HDFS文件系统之上运行单词计数程序的例子,同时指定了输入路径和输出位置的信息。 ### 键值对 RDD 常见操作汇总 针对KV-RDD(Key Value Pair Resilient Distributed Datasets),存在许多专为其设计的独特转换与行为接口供使用者选择适用: - join(otherDataset): 将当前键值对与其他相同key的数据集按照key进行内联接; - cogroup(otherDataset): 类似join但是不会丢失任一侧独有的记录而是将其组合在一起形成Tuple2<Iterable,V>格式的结果项; - groupByKey(): 把所有拥有同一个key的不同value聚集到一起成为一个新的迭代器; - reduceByKey(func): 在groupByKey的基础上进一步聚合values部分得到单一数值; - mapValues(f): 单纯修改每一个entry中的value而不改变原有的keys分布情况; - sortByKey([ascending]): 根据key大小顺序重新排列元素的位置[^6]。 这些丰富的内置能力极大地增强了程序员们面对各种实际应用场景下解决问题的能力范围。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值