在spark中,reduceByKey、groupByKey和combineByKey这三种算子用的较多,结合使用过程中的体会简单总结:

  我的代码实践:https://github.com/wwcom614/Spark

•reduceByKey

  用于对每个key对应的多个value进行merge操作,最重要的是它能够在本地先进行merge操作,并且merge操作可以通过函数自定义;

•groupByKey

  也是对每个key进行操作,但只生成一个sequence,groupByKey本身不能自定义函数,需要先用groupByKey生成RDD,然后才能对此RDD通过map进行自定义函数操作。

使用groupByKey时,spark会将所有的键值对进行移动,不会进行局部merge,会导致集群节点之间的开销很大,导致传输延时。

•combineByKey

一个相对底层的基于键进行聚合的基础方法(因为大多数基于键聚合的方法,例如reduceByKey,groupByKey都是用它实现的),所以感觉这个方法还是挺重要的。

该方法的入参主要为前三个:

  • createCombiner:遍历一个分区中每个元素,如果不存在,createCombiner创建累加器C,把原变量V放入,对相同K,把V合并成一个集合,例如将(key,88),映射建立集合(key,(88,1))
  • mergeValue:遍历一个分区中每个元素,如果已存在,将相同的值累加,例如将(key,(88,1)),(key,(88,1)),mergeValue累加集合为(key,(88,2))
  • mergeCombiners:createCombiner  和  mergeValue 是处理单个分区中数据,  mergeCombiners是每个分区处理完了,多个分区合并数据使用,例如分区1累加集合值为(key,(88,2)),分区2累加集合值为(key,(88,3)),mergeCombiners累加集合为(key,(88,5))

写个求每个学生的平均成绩的例子

    //2个学生及他们的成绩
val scoreList = Array(("ww1", 88), ("ww1", 95), ("ww2", 91), ("ww2", 93), ("ww2", 95), ("ww2", 98)) //将2个学生成绩转为RDD,分2个partition存储
val scoreRDD: RDD[(String, Int)] = sc.parallelize(scoreList, 2)
println("【scoreRDD.partitions.size】:" + scoreRDD.partitions.size)
//分区数,【scoreRDD.partitions.size】:2
println("【scoreRDD.glom.collect】:" + scoreRDD.glom().collect().mkString(",")) //每个分区的内容 //使用combineByKey,按每个学生累积分数和科目数量
val rddCombineByKey: RDD[(String, (Int, Int))] = scoreRDD.combineByKey(v => (v, 1),
(param1: (Int, Int), v) => (param1._1 + v, param1._2 + 1),
(p1: (Int, Int), p2: (Int, Int)) => (p1._1 + p2._1, p1._2 + p2._2))
println("【combineByKey】:" + rddCombineByKey.collect().mkString(","))
//【combineByKey】:(ww2,(377,4)),(ww1,(183,2)) //在map中使用case是scala的用法,按每个学生总成绩/科目数量,得到平均分
val avgScore = rddCombineByKey.map { case (key, value) => (key, value._1 / value._2.toDouble) }
println("【avgScore】:" + avgScore.collect().mkString(","))
//【avgScore】:(ww2,94.25),(ww1,91.5)

说明:

1.首先:各个分区createCombiner 和 mergeValue先干活

  第一个分区遍历开始: 数据为

Array(("ww1", 88), ("ww1", 95), ("ww2", 91))

    --> 处理(ww1,88), 因为是第一次遇到键“ww1”, 所以调用createCombiner方法 (v)=> (v,1) , 这里就是(ww1,88) =>( ww1, (88,1))

    --> 处理(ww1,95),不是第一次遇到键“ww1”,所以会调用mergeValue方法(param1:(Int,Int),v)=>(param1._1+v,param1._2+1),这里就是(ww1,(88,1)),(ww1,95)=>(ww1,(88+95, 1+1))= (ww1,(183,2))  ---(成绩相加,科目数量+1)

    --> 处理(ww2,91),因为是第一次遇到键“ww2”, 所以调用createCombiner方法 (v)=> (v,1) ,这里就是(ww2,91) => (ww2, (91,1))

    第一个分区遍历结束:返回 (ww1,(183,2) ),  ( ww2,(91,1))

  第二个分区遍历开始: 数据为

Array(("ww2", 93), ("ww2", 95), ("ww2", 98))

   --> 处理(ww2,93), 因为是第一次遇到键“ww2”, 所以调用createCombiner方法 (v)=> (v,1) ,这里就是(ww2,93 )=>(ww2, (93,1))

   --> 处理(ww2,95),不是第一次遇到键“ww2”,所以会调用mergeValue方法(param1:(Int,Int),v)=>(param1._1+v,param1._2+1),这里就是(ww2,(93,1)),(ww2,95)=>(ww2,(93+95, 1+1))= (ww2,(188,2))  ---(成绩相加,科目数量+1)

   --> 处理(ww2,98),不是第一次遇到键“ww2”,所以会调用mergeValue方法(param1:(Int,Int),v)=>(param1._1+v,param1._2+1),这里就是(ww2,(188,2)),(ww2,98)=>(ww2,(188+98, 2+1))= (ww2,(286,3) ) ---(成绩相加,科目数量+1)

    第二个分区遍历结束:返回 (ww2,(286,3) )

2.然后:各个分区干完了, mergeCombiners方法汇总处理

    --> 处理分区1的ww1,(183,2)   ww2,(91,1) ,分区2的ww2,(286,3) ,  会调用mergeCombiners方法(p1: (Int, Int), p2: (Int, Int)) => (p1._1 + p2._1, p1._2 + p2._2)),这里就是

(    (ww1,(183,2)),(ww2,(91,1)) ,  (ww2,(286,3))  )=>  (  (ww1,(183,2)) ,   (ww2,(91+286,1+3)) ) =   (  (ww1,(183,2)) ,   (ww2,(377,4)) )

【Spark算子】:reduceByKey、groupByKey和combineByKey的更多相关文章

  1. Spark算子--reduceByKey

    reduceByKey--Transformation类算子 代码示例 result  

  2. (转)Spark 算子系列文章

    http://lxw1234.com/archives/2015/07/363.htm Spark算子:RDD基本转换操作(1)–map.flagMap.distinct Spark算子:RDD创建操 ...

  3. Spark算子总结及案例

    spark算子大致上可分三大类算子: 1.Value数据类型的Transformation算子,这种变换不触发提交作业,针对处理的数据项是Value型的数据. 2.Key-Value数据类型的Tran ...

  4. Spark算子总结(带案例)

    Spark算子总结(带案例) spark算子大致上可分三大类算子: 1.Value数据类型的Transformation算子,这种变换不触发提交作业,针对处理的数据项是Value型的数据. 2.Key ...

  5. Spark算子使用

    一.spark的算子分类 转换算子和行动算子 转换算子:在使用的时候,spark是不会真正执行,直到需要行动算子之后才会执行.在spark中每一个算子在计算之后就会产生一个新的RDD. 二.在编写sp ...

  6. Spark:常用transformation及action,spark算子详解

    常用transformation及action介绍,spark算子详解 一.常用transformation介绍 1.1 transformation操作实例 二.常用action介绍 2.1 act ...

  7. UserView--第二种方式(避免第一种方式Set饱和),基于Spark算子的java代码实现

      UserView--第二种方式(避免第一种方式Set饱和),基于Spark算子的java代码实现   测试数据 java代码 package com.hzf.spark.study; import ...

  8. UserView--第一种方式set去重,基于Spark算子的java代码实现

    UserView--第一种方式set去重,基于Spark算子的java代码实现 测试数据 java代码 package com.hzf.spark.study; import java.util.Ha ...

  9. spark算子之DataFrame和DataSet

    前言 传统的RDD相对于mapreduce和storm提供了丰富强大的算子.在spark慢慢步入DataFrame到DataSet的今天,在算子的类型基本不变的情况下,这两个数据集提供了更为强大的的功 ...

随机推荐

  1. bootstrap之css样式

    一 bootstrap的介绍 Bootstrap是将html,css和js的代码打包好了,只管我们拿来调用.是基于jquery开发的. 使用BootCDN提供的免费CDN加速服务,同时支持http和h ...

  2. java保存繁体字到数据库时就报错Incorrect string value: '\xF0\xA6\x8D\x8B\xE5\xA4...' for column 'name' at row 1

    问题分析 普通的字符串或者表情都是占位3个字节,所以utf8足够用了,但是移动端的表情符号占位是4个字节,普通的utf8就不够用了,为了应对无线互联网的机遇和挑战.避免 emoji 表情符号带来的问题 ...

  3. 2018.10.31 NOIP训练 锻造(方程式期望入门题)(期望dp)

    传送门 根据题目列出方程: fi=pi∗(fi−1+fi−2)+(1−pi)∗(fi+1+fi)f_i=p_i*(f_{i-1}+f_{i-2})+(1-p_i)*(f_{i+1}+f_i)fi​=p ...

  4. 2018.10.24 bzoj2064: 分裂(状压dp)

    传送门 状压dp好题. 考虑对于两个给出的集合. 如果没有两个元素和相等的子集,那么只能全部拼起来之后再拆开,一共需要n1+n2−2n1+n2-2n1+n2−2. 如果有呢? 那么对于没有的就是子问题 ...

  5. 第13章:MongoDB-聚合操作--初体验

    ①MongoDB 的聚合功能 MongoDB 的聚合功能,聚合操作主要用于对数据的批量处理,往往将记录按条件分组以后,然后再进行一系列操作,例如,求最大值.最小值.平均值,求和等操作. 聚合操作还能够 ...

  6. UVa 10561 Treblecross (SG函数)

    题意:给定上一行字符串,其中只有 X 和 . 并且没有连续的三个 X,两个玩家要分别在 . 上放 X,如果出现三个连续的 X,则该玩家胜利,现在问你先手胜还是败,如果是胜则输出第一步可能的位置. 析: ...

  7. 简单MVC实现增删改查

    反射工具类RelfectionUtils package Utils; import java.lang.reflect.Field; import java.lang.reflect.Invocat ...

  8. Servlet Life Cycle

    Servlet Life Cycle http://docs.oracle.com/javaee/5/tutorial/doc/bnafi.html Servlet Filters and Event ...

  9. 使用freemarker导出word

    最近需要将jsp部分页面导出为word文件,环境是Spring+SpringMVC+Hibernate. 我使用的是FreeMarker模板引擎来完成.这是FreeMarker的中文参考手册,感兴趣的 ...

  10. web-day15

    第15章WEB15-AJAX和JQuery案例篇 今日任务 使用AJAX完成用户名的异步校验 使用JQuery完成用户名异步校验 使用JQuery完成商品信息模糊显示 使用JQuery完成省市联动效果 ...