reduce和reduceByKey的区别

reduce和reduceByKey是spark中使用地非常频繁的,在字数统计中,可以看到reduceByKey的经典使用。那么reduce和reduceBykey的区别在哪呢?reduce处理数据时有着一对一的特性,而reduceByKey则有着多对一的特性。比如reduce中会把数据集合中每一个元素都处理一次,并且每一个元素都对应着一个输出。而reduceByKey则不同,它会把所有key相同的值处理并且进行归并,其中归并的方法可以自己定义。

例子

在单词统计中,我们采用的就是reduceByKey,对于每一个单词我们设置成一个键值对(key,value),我们把单词作为key,即key=word,而value=1,因为遍历过程中,每个单词的出现一次,则标注1。那么reduceByKey则会把key相同的进行归并,然后根据我们定义的归并方法即对value进行累加处理,最后得到每个单词出现的次数。而reduce则没有相同Key归并的操作,而是将所有值统一归并,一并处理。

spark的reduce

我们采用scala来求得一个数据集中所有数值的平均值。该数据集包含5000个数值,数据集以及下列的代码均可从github下载,数据集名称为"avg"。为求得这个数据集中的平均值,我们先用map对文本数据进行处理,将其转换成long类型。

数据集内容:

reduce求平均值scala实现

import org.apache.spark.{SparkConf, SparkContext}

object SparkReduce {

  def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local").setAppName("SparkReduce") val sc = new SparkContext(conf) //将String转成Long类型
val numData = sc.textFile("./avg").map(num => num.toLong) //reduce处理每个值
println(numData.reduce((x,y)=>{
println("x:"+x)
println("y:"+y)
x+y
})/numData.count()) } }

reduce求平均值Java实现

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.Function2; public class SparkReduceJava { public static void main(String[] main){ SparkConf conf = new SparkConf().setAppName("SparkReduceJava").setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); reduceJava(sc); reduceJava8(sc);
} public static void reduceJava(JavaSparkContext sc){
JavaRDD<Long>textData = sc.textFile("./avg").map(new Function<String, Long>() {
@Override
public Long call(String s) throws Exception {
return Long.parseLong(s);
};
}); System.out.println(
textData.reduce(new Function2<Long, Long, Long>() {
@Override
public Long call(Long aLong, Long aLong2) throws Exception {
System.out.println("x:"+aLong);
System.out.println("y:"+aLong2);
return aLong+aLong2;
}
})/textData.count()
);
} public static void reduceJava8(JavaSparkContext sc){
JavaRDD<Long>textData = sc.textFile("./avg").map(s->Long.parseLong(s));
System.out.println(textData.reduce((x,y)->x+y)/textData.count());
} }

reduce求平均值python实现

from pyspark import SparkConf,SparkContext

conf = SparkConf().setMaster("local").setAppName("SparkReduce")

sc = SparkContext(conf=conf)

numData = sc.textFile("./avg").map(lambda s:int(s))

print(numData.reduce(lambda x,y:x+y)/numData.count())

运行结果

观察运行结果,我们不难发现,x存放的是累加后的值,y是当前值,x初始为0。事实上,x正是存放上次处理的结果,而y则是本次的数值。不断做x+y就并且放回累加后的结果作为下一次x的值。这样就可以得 到数值总和。最后将总和除以总数就能够得到平均值。

scala或java运行结果

平均值只保留了整数

x:222783
y:48364
x:271147
y:204950
x:476097
y:261777
x:737874
y:166827
x:904701
y:154005
x:1058706
y:150029
x:1208735
y:140158
x:1348893
y:404846
x:1753739
y:542750
...
...
平均值是:334521

python运行结果

python默认保留了小数

334521.2714

spark的reduceByKey

spark的reduceByKey对要处理的值进行了差别对待,只有key相同的才能进行reduceByKey,则也就要求了进行reduceByKey时,输入的数据必须满足有键有值。由于上述的avg我们是用随机数生成的,那么我们可以用reduceByKey完成一个其他功能,即统计随机数中末尾是0-9各个数值出现的个数。

scala实现

import org.apache.spark.{SparkConf, SparkContext}

object SparkReduceByKey {

  def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local").setAppName("SparkReduce") val sc = new SparkContext(conf) //将String转成Long类型
val numData = sc.textFile("./avg").map(num => (num.toLong%10,1)) numData.reduceByKey((x,y)=>x+y).foreach(println(_))
} }

java实现

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2; public class SparkReduceByKeyJava { public static void main(String[] main){ SparkConf conf = new SparkConf().setAppName("SparkReduceJava").setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); reduceByKeyJava(sc); reduceByKeyJava8(sc); } public static void reduceByKeyJava(JavaSparkContext sc){ JavaPairRDD<Integer,Integer> numData = sc.textFile("./avg").mapToPair(new PairFunction<String, Integer, Integer>() {
@Override
public Tuple2<Integer, Integer> call(String s) throws Exception {
return new Tuple2<Integer, Integer>(Integer.parseInt(s)%10,1);
}
}); System.out.println(numData.reduceByKey(new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer integer, Integer integer2) throws Exception {
return integer+integer2;
}
}).collectAsMap()); } public static void reduceByKeyJava8(JavaSparkContext sc){
JavaPairRDD<Integer,Integer> numData = sc.textFile("./avg").mapToPair(s->new Tuple2<>(Integer.parseInt(s)%10,1)); System.out.println(numData.reduceByKey((x,y)->x+y).collectAsMap());
} }

python实现

from pyspark import SparkConf,SparkContext

conf = SparkConf().setMaster("local").setAppName("SparkReduce")

sc = SparkContext(conf=conf)

print(sc.textFile("./avg").map(lambda s:(int(s)%10,1)).reduceByKey(lambda x,y:x+y).collectAsMap())

运行结果

scala运行结果

(4,522)
(0,462)
(1,495)
(6,519)
(3,463)
(7,544)
(9,518)
(8,533)
(5,483)
(2,461)

java运行结果

{8=533, 2=461, 5=483, 4=522, 7=544, 1=495, 9=518, 3=463, 6=519, 0=462}

python运行结果

{3: 463, 4: 522, 0: 462, 7: 544, 5: 483, 9: 518, 8: 533, 6: 519, 2: 461, 1: 495}

我们注意到三个程序输出的顺序不一样,但是本质的结果都是一致的。这里体现了spark的一个优点,由于是在单机本地上,该优点表现出来的是相同输入输出结果顺序不同。但是在集群中,该优点表现出来的是在集群中各自处理,而后返回结果。当数量足够大的时候,这个优点就更加明显。

对结果进行排序

那么为了能够使得输出结果顺序一致,我们可以对数据进行排序后输出,那么这里就涉及到了sortByKey。

scala实现

import org.apache.spark.{SparkConf, SparkContext}

object SparkReduceByKey {

  def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local").setAppName("SparkReduce") val sc = new SparkContext(conf) //将String转成Long类型
val numData = sc.textFile("./avg").map(num => (num.toLong%10,1)) //根据key排序后输出
numData.reduceByKey((x,y)=>x+y).sortByKey().foreach(println(_))
} }

java实现

特别注意这里用的是collect,而不是collectMap,因为java中转换成Map会打乱顺序

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2; public class SparkReduceByKeyJava { public static void main(String[] main){ SparkConf conf = new SparkConf().setAppName("SparkReduceJava").setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); reduceByKeyJava(sc); reduceByKeyJava8(sc); } public static void reduceByKeyJava(JavaSparkContext sc){ JavaPairRDD<Integer,Integer> numData = sc.textFile("./avg").mapToPair(new PairFunction<String, Integer, Integer>() {
@Override
public Tuple2<Integer, Integer> call(String s) throws Exception {
return new Tuple2<Integer, Integer>(Integer.parseInt(s)%10,1);
}
}); System.out.println(numData.reduceByKey(new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer integer, Integer integer2) throws Exception {
return integer+integer2;
}
}).sortByKey().collect()); } public static void reduceByKeyJava8(JavaSparkContext sc){
JavaPairRDD<Integer,Integer> numData = sc.textFile("./avg").mapToPair(s->new Tuple2<>(Integer.parseInt(s)%10,1)); System.out.println(numData.reduceByKey((x,y)->x+y).sortByKey().collect());
} }

python实现

from pyspark import SparkConf,SparkContext

conf = SparkConf().setMaster("local").setAppName("SparkReduce")

sc = SparkContext(conf=conf)

print(sc.textFile("./avg").map(lambda s:(int(s)%10,1)).reduceByKey(lambda x,y:x+y).sortByKey().collectAsMap())

得到结果,这里只给出scala输出的结果,其他输出的结果一致,只是表现形式不同

(0,462)
(1,495)
(2,461)
(3,463)
(4,522)
(5,483)
(6,519)
(7,544)
(8,533)
(9,518)

数据集以及代码都可以在github上下载。

转自:https://juejin.im/post/5c791d4fe51d453ed866248a

Spark入门(五)--Spark的reduce和reduceByKey的更多相关文章

  1. 二、spark入门之spark shell:文本中发现5个最常用的word

    scala> val textFile = sc.textFile("/Users/admin/spark-1.5.1-bin-hadoop2.4/README.md") s ...

  2. 一、spark入门之spark shell:wordcount

    1.安装完spark,进入spark中bin目录: bin/spark-shell   scala> val textFile = sc.textFile("/Users/admin/ ...

  3. spark实验(五)--Spark SQL 编程初级实践(1)

    一.实验目的 (1)通过实验掌握 Spark SQL 的基本编程方法: (2)熟悉 RDD 到 DataFrame 的转化方法: (3)熟悉利用 Spark SQL 管理来自不同数据源的数据. 二.实 ...

  4. Spark入门:Spark运行架构(Python版)

    此文为个人学习笔记如需系统学习请访问http://dblab.xmu.edu.cn/blog/1709-2/ 基本概念 *  RDD:是弹性分布式数据集(Resilient Distributed ...

  5. Spark 入门

    Spark 入门 目录 一. 1. 2. 3. 二. 三. 1. 2. 3. (1) (2) (3) 4. 5. 四. 1. 2. 3. 4. 5. 五.         Spark Shell使用 ...

  6. Spark入门(六)--Spark的combineByKey、sortBykey

    spark的combineByKey combineByKey的特点 combineByKey的强大之处,在于提供了三个函数操作来操作一个函数.第一个函数,是对元数据处理,从而获得一个键值对.第二个函 ...

  7. Spark入门实战系列--1.Spark及其生态圈简介

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .简介 1.1 Spark简介 年6月进入Apache成为孵化项目,8个月后成为Apache ...

  8. Spark入门实战系列--2.Spark编译与部署(下)--Spark编译安装

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .编译Spark .时间不一样,SBT是白天编译,Maven是深夜进行的,获取依赖包速度不同 ...

  9. Spark入门实战系列--3.Spark编程模型(上)--编程模型及SparkShell实战

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .Spark编程模型 1.1 术语定义 l应用程序(Application): 基于Spar ...

随机推荐

  1. Windows Server 2012 R2 强制卸载域控制器

    本次实验要演示的是强制卸载域控制器并且在其他域控制器上删除不需要的服务器对象,这种情况在现实的生产使用环境中经常使用,每个企业每年都会有增减域控制器的时候,而且在减少了域控制器之后,原本的域还会继续使 ...

  2. Eclipse中项目过大引起的 IDE 加载缓慢,JVM 内存不足的情况解决

    如果 IDE 加载项目非常缓慢,甚至常常出现卡死的情况,有可能是开发工具设置的 JVM 内存不够引起的.解决办法:找到 Eclipse 的安装目录,修改 Eclipse.ini 配置文件.修改此配置文 ...

  3. NIO详解

    目录 NIO 前言 IO与NIO的区别 Buffer(缓冲区) Channel(通道) Charset(字符集) NIO遍历文件 NIO 前言 NIO即New IO,这个库是在JDK1.4中才引入的. ...

  4. win10安装mudbox失败,怎么强力卸载删除注册表并重新安装

    一些搞设计的朋友在win10系统下安装mudbox失败或提示已安装,也有时候想重新安装mudbox的时候会出现本电脑windows系统已安装mudbox,你要是不留意直接安装mudbox,只会安装mu ...

  5. js事件节流

    背景:在监听浏览器滚动条的scroll事件时该事件会触发很多次,这样当快速滚动时会有很差的性能,所以要限制事件触发的频率,可以防抖和节流,这里我记录简单的节流方法 <!DOCTYPE html& ...

  6. Mercurial 小结

    基本操作 # 拉取 并 更新 pull pull && hg update # 撤销上一个命令(不能重复运行) hg rollback # 恢复到指定的 changeset hg st ...

  7. spring基于@Value绑定属Bean性失

    用spring注解@Value绑定属性失败 环境: eclipse Version: Luna Release (4.4.0) spring 4.0 Junit4 其他依赖包 描述: JsrDAO类, ...

  8. Mac 下配置 adb 环境

    使用 adb 命令可以很直接的观察你的应用 第一步 打开终端,敲入命令:sudo vi .bash_profile(如果有密码就为本机登录密码, 如果没有这个文件就会创建一个新的). 第二步 在文件中 ...

  9. C++走向远洋——61(项目一、排序函数模板)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  10. k8s环境部署本地.net core web项目

    上一篇文章,我们部署了docker+k8s环境,简单测试通过,但是,还没能将我们自己的项目部署上去,继续记录部署踩坑过程. 一.准备工作 1.当然是docker+k8s环境了,详情请看上一篇文档 ht ...