在Spark中有许多聚类操作是基于combineByKey的,例如group那个家族的操作等。所以combineByKey这个函数也是比较重要,所以下午花了点时间看来下这个函数。也参考了http://www.tuicool.com/articles/miueaqv这篇博客。

先看下combineByKey定义:
/**
   * Generic function to combine the elements for each key using a custom set of aggregation
   * functions. Turns an RDD[(K, V)] into a result of type RDD[(K, C)], for a "combined type" C
   * Note that V and C can be different -- for example, one might group an RDD of type
   * (Int, Int) into an RDD of type (Int, Seq[Int]). Users provide three functions:
   *
   * - `createCombiner`, which turns a V into a C (e.g., creates a one-element list)
   * - `mergeValue`, to merge a V into a C (e.g., adds it to the end of a list)
   * - `mergeCombiners`, to combine two C's into a single one.
   *
   * In addition, users can control the partitioning of the output RDD, and whether to perform
   * map-side aggregation (if a mapper can produce multiple items with the same key).
   */
  def combineByKey[C](createCombiner: V => C,
    mergeValue: (C, V) => C,
    mergeCombiners: (C, C) => C,
    partitioner: Partitioner,
    mapSideCombine: Boolean = true,
    serializer: Serializer = null): RDD[(K, C)] = {
  //实现略
  }
这个函数主要是将键值对[(K,V)]转换为[(K,C)],并且这里的V,C类型可以不同。
对于里面的三个函数的作用,上述的博客的例子讲得很通俗,所以就拿过来直接讲下。
假设我们要将一堆的各类水果给榨果汁,并且要求果汁只能是纯的,不能有其他品种的水果。那么我们需要一下几步:
1 定义我们需要什么样的果汁
2 定义一个榨果汁机,即给定水果,就能给出我们定义的果汁
3 定义一个果汁混合器,即能将相同类型的水果果汁给混合起来。
那么有了这三步,我们就只需要往这个果汁机中仍水果,那么这个果汁机就会产生果汁,并且果汁经过果汁混合器就能将相同品种的水果给聚在一块了。
那么对比上述三步,combineByKey的三个函数也就是这三个功能
1 createCombiner就是定义了v如何转换为c
2 mergeValue 就是定义了如何给定一个V将其与原来的C合并成新的C
3 就是定义了如何将相同key下的C给合并成一个C
下面以一个例子来说明,例如有
data=sc.parallelize([("a",2),("a",3),("b",4)])这个数据,后面的数字表示该字符权重,我们现在想求每个字符出现的平均权重。
data.combineByKey((lambda v:(v,1)),
                              (lambda c,v:(c[0]+v,c[1]+1)),
                              (lambda x,y:(x[0]+y[0],x[1]+y[1])))
那么第一个函数
第二个函数
(lambda c,v:(c[0]+v,c[1]+1)) 这里的参数c可以理解为已经榨好的果汁,v为新加进去的水果,在这里假设此时c为(2,1)v为3,那么应该对应的权重相加,并且计数加1,c[0]+v就是权重相加,c[0]是2,接着就是对其计数加1.(其实这里已经是对相同的key进行归类了,否则c和v的key不同,在这里就会混乱)
第三个函数
(lambda x,y:(x[0]+y[0],x[1]+y[1])),这里是将相同品种的水果果汁给混合起来,所以这里的参数x,y其实都是c类型的。所以这里需要做的就是相应的的权重相加,并且计数相加。这里的x[0]+y[0]就是权重相加,x[1]+y[1]就是计数相加。
 
利用combineByKey实现groupByKey
groupByKey是将key相同的value聚合成一个list
data=sc.parallelize([("a",2),("a",3),("b",4),("b",2)])
一开始自己的写法是:

temp=data.combineByKey((lambda v:[v]),
            (lambda c,v:c.append(v)),
            (lambda x,y:x.extend(y)))

但总是返回[("a",None),("b",None)]后来才发现原来是因为python中对于list.append()没有返回值,所以c.append(v)返回值为None。但是这三个函数都是需要返回值的。对于第二个而言返回的是V加入C后的C,对于第三个而言返回的是C和另一个C合并后的C

所以

def g(c,v);

  c.append(v)

  return c

def h(c1,c2):

  c1.extend(c2)

  return c1

data.combineByKey((lambda v:[v]),g,h)这样就能正确返回了

 
总结:
虽然对于细节了解不够深,但是猜测第二个函数像是Hadoop中的local combiner就是对本地中的相同的key的水果进行榨汁混合,第三个函数像是在全局中对相同的key的水果进行混合(此时不需要榨汁了)。
 
 
 

Spark 的combineByKey函数的更多相关文章

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

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

  2. 自定义实现spark的分区函数

    有时自己的业务需要自己实现spark的分区函数 以下代码是实现一个自定义spark分区的demo 实现的功能是根据key值的最后一位数字,写到不同的文件 例如: 10写入到part-00000 11写 ...

  3. Spark远程调试函数

    Spark远程调试函数 1.sendInfo 该函数用于分布式程序的调试,非常方便,在spark的rdd操作中嵌入sendInfo,启动nc服务器后,可以收集到所有需要的运行时信息,该函数可以捕获ho ...

  4. Spark SQL 自定义函数类型

    Spark SQL 自定义函数类型 一.spark读取数据 二.自定义函数结构 三.附上长长的各种pom 一.spark读取数据 前段时间一直在研究GeoMesa下的Spark JTS,Spark J ...

  5. spark中的combineByKey函数的用法

    一.函数的源码 /** * Simplified version of combineByKeyWithClassTag that hash-partitions the resulting RDD ...

  6. Spark核心RDD:combineByKey函数详解

    https://blog.csdn.net/jiangpeng59/article/details/52538254 为什么单独讲解combineByKey? 因为combineByKey是Spark ...

  7. Spark RDD——combineByKey

    为什么单独讲解combineByKey? 因为combineByKey是Spark中一个比较核心的高级函数,其他一些高阶键值对函数底层都是用它实现的.诸如 groupByKey,reduceByKey ...

  8. spark之combineByKey

    combineByKey def combineByKey[C](createCombiner: (V) => C, mergeValue: (C, V) => C, mergeCombi ...

  9. Spark SQL 用户自定义函数UDF、用户自定义聚合函数UDAF 教程(Java踩坑教学版)

    在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...

随机推荐

  1. java操作oracle的blob,clob数据

    一.区别和定义 LONG: 可变长的字符串数据,最长2G,LONG具有VARCHAR2列的特性,可以存储长文本一个表中最多一个LONG列 LONG RAW: 可变长二进制数据,最长2G CLOB:  ...

  2. ios开发使用lipo命令合并真机库和模拟器库

    在开发ios时,我们经常会遇到编译两套库文件,使用模拟器时链接模拟器库,使用真机时使用真机库,这样操作会对后期的维护带来麻烦,所以Apple提供了一个把多个不同平台的.a库文件合并成一个适用于多平台的 ...

  3. 设置TabBar分栏控制器上图片的大小问题

    我们都知道,iOS因为屏幕分辨率的问题,UID在交付我们iOS开发人员程序配图的时候,一般是三套图,分别对应三种不同的分辨率,对不同size的屏幕系统会自动使用不同像素的图片,我们只需要在命名时给三套 ...

  4. js中子页面父页面方法和变量相互调用

    (1)子页面调用父页面的方法或者变量: window.parent.方法()或者变量名window.parent相当于定位到父页面 之后的操作和在父页面中写代码一样写 window.parent.aa ...

  5. Anton and Making Potions

    Anton and Making Potions time limit per test 4 seconds memory limit per test 256 megabytes input sta ...

  6. 快学Scala-第三章 数组相关操作

    知识点: 1.定长数组 Array val nums = new Array[Int](10) //10个整数的数组,所有元素初始化为0 val a = new Array[String](10) / ...

  7. [转]Android 导入v7包常见错误,以及项目引用v7包错误解决

    android下v4    v7   v21等包是android系统的扩展支持包,就想windows的系统补丁一个道理. android的扩展包主要是用来兼容低版本的,比如android3.0以后出现 ...

  8. iframe2016/4/12

    js操作iframe contentWindow    在服务器环境下测试contentDocument二种方法的区别子级iframe修改父级元素内容window.parentwindow.top与w ...

  9. javascript语句语义大全(2)

    1. 四则运算相关 +,-,*,/,% 分别是加减乘除和取余 2.Math.pow(a,b) a的b次方 3.toFixed(a) 四舍五入为指定小数位数的数字 4. k++; ++K 看似相同但是在 ...

  10. HDU 1814 Peaceful Commission

    2-SAT,输出字典序最小的解,白书模板. //TwoSAT输出字典序最小的解的模板 //注意:0,1是一组,1,2是一组..... #include<cstdio> #include&l ...