我正在尝试在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
对应。有可能这样做吗?
答案 0 :(得分:0)
答案是肯定的,但可能不是您所期望的。取决于您的业务逻辑有多复杂,除了combineByKey之外还有2个alernative
如果您只需要[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好,除非此业务逻辑非常常见且可以重复用于其他数据集
或者您需要稍微复杂的逻辑才能使用窗口功能 要使用Window.partitionBy($&#34; session_id&#34;)。orderBy($&#34; client_ts&#34; desc)指定窗口规范,那么您可以轻松实现topN,移动平均值,ntile等。请{{{ 3}}您也可以自己实现自定义窗口aggegration函数