• Spark DataFrame的groupBy vs groupByKey


    在使用Spark SQL的过程中,经常会用到groupBy这个函数进行一些统计工作。但是会发现除了groupBy外,还有一个groupByKey(注意RDD也有一个groupByKey,而这里的groupByKey是DataFrame的)。这个groupByKey引起了我的好奇,那我们就到源码里面一探究竟吧。

    所用spark版本:spark2.1.0

    先从使用的角度来说,
    groupBy:groupBy类似于传统SQL语言中的group by子语句,但比较不同的是groupBy()可以带多个列名,对多个列进行group。比如想根据"id"和"name"进行groupBy的话可以

    df.goupBy("id","name")
    

    groupBy返回的类型是RelationalGroupedDataset。

    groupByKey:groupByKey则更加灵活,可以根据用户自己对列的组合来进行groupBy,比如上面的那个例子,根据"id"和"name"进行groupBy,使用groupByKey可以这样。

    //同前面的goupBy效果是一样的,但返回的类型是不一样的
    df..toDF("id","name").goupByKey(row =>{
    	row.getString(0) + row.getString(1)
    })
    

    但和groupBy不同的是groupByKey返回的类型是KeyValueGroupedDataset。

    下面来看看这两个方法的实现有何区别。

    groupBy源码

      def groupBy(cols: Column*): RelationalGroupedDataset = {
        RelationalGroupedDataset(toDF(), cols.map(_.expr), RelationalGroupedDataset.GroupByType)
      }
    

    最终会去新建一个RelationalGroupedDataset,而这个方法提供count(),max(),agg(),等方法。值得一提的是,这个类在spark1.x的时候类名为“GroupedData”。看看类中的注释吧

    /**
     * A set of methods for aggregations on a `DataFrame`, created by `Dataset.groupBy`.
     *
     * The main method is the agg function, which has multiple variants. This class also contains
     * convenience some first order statistics such as mean, sum for convenience.
     *
     * This class was named `GroupedData` in Spark 1.x.
     *
     * @since 2.0.0
     */
    @InterfaceStability.Stable
    class RelationalGroupedDataset protected[sql](
    

    groupByKey源码

      @Experimental
      @InterfaceStability.Evolving
      def groupByKey[K: Encoder](func: T => K): KeyValueGroupedDataset[K, T] = {
        val inputPlan = logicalPlan
        val withGroupingKey = AppendColumns(func, inputPlan)
        val executed = sparkSession.sessionState.executePlan(withGroupingKey)
    
        new KeyValueGroupedDataset(
          encoderFor[K],
          encoderFor[T],
          executed,
          inputPlan.output,
          withGroupingKey.newColumns)
      }
    

    可以发现最后生成和返回的类是KeyValueGroupedDataset。这是dataset的子类,表示聚合过之后的dataset。
    我们再看看这个类中的注释吧

    /**
     * :: Experimental ::
     * A [[Dataset]] has been logically grouped by a user specified grouping key.  Users should not
     * construct a [[KeyValueGroupedDataset]] directly, but should instead call `groupByKey` on
     * an existing [[Dataset]].
     *
     * @since 2.0.0
     */
    @Experimental
    @InterfaceStability.Evolving
    class KeyValueGroupedDataset[K, V] private[sql](
    

    可以发现groupByKey还处于实验阶段。它是希望可以由用户自己来实现groupBy的规则,而不像groupBy()一样,需要被列属性所束缚。
    通过groupByKey用户可以按照自己的需求来进行grouping。

    总而言之,groupByKey虽然提供了更加灵活的处理grouping的方式,但groupByKey后返回的类是KeyValueGroupedDataset,它里面所提供的操作接口也不如groupBy返回的RelationalGroupedDataset所提供的接口丰富。除非真的有一些特殊的grouping操作,否则还是使用groupBy吧。

  • 相关阅读:
    Java内置包装类
    for循环思路题
    常用函数
    函数
    冒泡排序
    数组的运用
    for循环中有意思的练习题。
    for循环
    运算中容易出现的错误
    分支的运用
  • 原文地址:https://www.cnblogs.com/listenfwind/p/9860228.html
Copyright © 2020-2023  润新知