如何在数据帧上使用combineByKey

时间:2017-10-09 16:19:46

标签: scala apache-spark spark-dataframe

我正在尝试在spark中实现二次排序。确切地说,对于用户会话的所有事件,我想基于时间戳对它们进行排序。在二级排序后,我需要遍历会话的每个事件以实现业务逻辑。我这样做:

def createCombiner = (row: Row) => Array(row)

def mergeValue = (rows: Array[Row], row: Row) => {
  rows :+ row
}

def mergeCombiner = (rows1: Array[Row], rows2: Array[Row]) => rows1 ++ rows2

def attribute(eventsList: List[Row]): List[Row] = {
  for (row: Row <- eventsList) {
    // some logic
  }
}

var groupedAndSortedRows = rawData.rdd.map(row => {
  (row.getAs[String]("session_id"), row)
}).combineByKey(createCombiner, mergeValue, mergeCombiner)
  .mapValues(_.toList.sortBy(_.getAs[String]("client_ts")))
  .mapValues(attribute)

但我担心这不是最有效的方法,因为转换为RDD需要反序列化和序列化,我认为在处理数据帧/数据集时不需要这样做。

我不确定是否有一个聚合器函数返回整行

rawData.groupBy("session_id").someAggregateFunction()

我希望someAggregateFunction()返回Rows列表。我不想在某些列上进行汇总,但希望整个Rows列表与session_id对应。有可能这样做吗?

1 个答案:

答案 0 :(得分:0)

答案是肯定的,但可能不是您所期望的。取决于您的业务逻辑有多复杂,除了combineByKey之外还有2个alernative

  1. 如果您只需要[spark.sql.functions]中定义的mean,min,max和其他已知函数[1]

    [1]:https://github.com/apache/spark/blob/v2.0.2/sql/core/src/main/scala/org/apache/spark/sql/functions.scala你当然可以使用groupBy(...)。agg(...)。我想那不是你的情况。因此,如果您希望实现自己的UDAF并不比combineByKey好,除非此业务逻辑非常常见且可以重复用于其他数据集

  2. 或者您需要稍微复杂的逻辑才能使用窗口功能 要使用Window.partitionBy($&#34; session_id&#34;)。orderBy($&#34; client_ts&#34; desc)指定窗口规范,那么您可以轻松实现topN,移动平均值,ntile等。请{{{ 3}}您也可以自己实现自定义窗口aggegration函数