如何在组中找到第一个非空值? (使用数据集api进行二级排序)

时间:2017-03-23 21:05:16

标签: apache-spark apache-spark-sql apache-spark-dataset

我正在处理一个代表事件流的数据集(比如从网站上发布的跟踪事件)。所有活动都有时间戳。我们经常遇到的一个用例是尝试找到给定字段的第一个非空值。因此,例如像我们一样的东西:

val eventsDf = spark.read.json(jsonEventsPath) 

case class ProjectedFields(visitId: String, userId: Int, timestamp: Long ... )

val projectedEventsDs = eventsDf.select(
    eventsDf("message.visit.id").alias("visitId"),
    eventsDf("message.property.user_id").alias("userId"),
    eventsDf("message.property.timestamp"),

    ...

).as[ProjectedFields]

projectedEventsDs.groupBy($"visitId").agg(first($"userId", true))

上述代码的问题在于无法保证馈送到first聚合函数的数据的顺序。我希望它按timestamp排序,以确保它是时间戳的第一个非null userId,而不是任何随机的非null userId。

有没有办法在分组中定义排序?

使用Spark 2.10

BTW,SPARK DataFrame: select the first row of each group中为Spark 2.10建议的方法是在分组之前进行排序 - 这不起作用。例如,以下代码:

case class OrderedKeyValue(key: String, value: String, ordering: Int)
val ds = Seq(
  OrderedKeyValue("a", null, 1), 
  OrderedKeyValue("a", null, 2), 
  OrderedKeyValue("a", "x", 3), 
  OrderedKeyValue("a", "y", 4), 
  OrderedKeyValue("a", null, 5)
).toDS()

ds.orderBy("ordering").groupBy("key").agg(first("value", true)).collect()

有时会返回Array([a,y]),有时会返回Array([a,x])

1 个答案:

答案 0 :(得分:5)

使用我的心爱的窗口(......体验生活变得更简单

import org.apache.spark.sql.expressions.Window
val byKeyOrderByOrdering = Window
  .partitionBy("key")
  .orderBy("ordering")
  .rangeBetween(Window.unboundedPreceding, Window.unboundedFollowing)

import org.apache.spark.sql.functions.first
val firsts = ds.withColumn("first",
  first("value", ignoreNulls = true) over byKeyOrderByOrdering)

scala> firsts.show
+---+-----+--------+-----+
|key|value|ordering|first|
+---+-----+--------+-----+
|  a| null|       1|    x|
|  a| null|       2|    x|
|  a|    x|       3|    x|
|  a|    y|       4|    x|
|  a| null|       5|    x|
+---+-----+--------+-----+

注意:不知何故,Spark 2.2.0-SNAPSHOT(今天建成)无法给出正确的答案,没有rangeBetween我认为应该是默认的无限范围。