• Spark 的combineByKey函数


     在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的水果进行混合(此时不需要榨汁了)。
     
     
     
  • 相关阅读:
    C#委托本质探索 四、方法变量内、外混合调用
    calibredrv 对layer做操作
    2021年11月工作笔记
    2022年1月工作资料
    2021年12月工作资料
    MySQL 5.7 MGR原理及部署
    在虚拟机上安装redis集群,redis使用版本为4.0.5,本机通过命令客户端可以连接访问,外部主机一直访问不了
    mongoDB中的的常用语法
    使用Nginx做图片服务器时候,配置之后图片访问一直是 404问题解决
    jquery.cookie() 方法的使用(读取、写入、删除)
  • 原文地址:https://www.cnblogs.com/sunrye/p/4608122.html
Copyright © 2020-2023  润新知