我首先说我是SQL的新手,所以这个问题可能很简单。
我有两个带时间戳键的表。
对于t_i
中的每个事件table 1
,我希望q
中的所有事件table 2
都可以:
q.timeStamp < t_i.timeStamp and q.timeStamp > t_{i-1}.timeStamp
也就是说,如果事件按此顺序按时间戳发生:
q1
t1 q2
q3
q4
t2 q5
q6
t3 q7
然后生成的查询应为:
t1: q1
t2: q2 q3 q4
t3: q5 q6
我正在使用Scala和SQL Spark以及DataSet和DataFrame类,所以要么是一个纯粹的功能性的&group 39&quot;或者SQL查询会很好。
答案 0 :(得分:1)
首先,它不是一个非常“简单”的查询...
首先 - 让我们用一些示例数据创建数据框 - 我创建了只有时间和字符串值的小案例类,您可以用更复杂的类替换它们:
case class A(time: Long, aValue: String)
case class B(time: Long, bValue: String)
val tableA = Seq(A(1, "q1"), A(2, "q2"), A(3, "q3"), A(4, "q4"), A(5, "q5"), A(6, "q6"), A(7, "q7"))
val tableB = Seq(B(2, "t1"), B(5, "t2"), B(7, "t3"))
val dfA: DataFrame = sqlContext.createDataFrame(tableA)
val dfB: DataFrame = sqlContext.createDataFrame(tableB)
现在 - 两个替代方案(概念上相同):
使用SQL :
dfA.registerTempTable("a")
dfB.registerTempTable("b")
sqlContext.sql(
"""
|SELECT collect_list(c.time), collect_list(c.aValue), first(b.time), first(b.bValue)
|FROM (
| SELECT FIRST(a.time) as time, FIRST(a.aValue) as aValue, MIN(b.time) AS bTime
| FROM a
| JOIN b ON b.time > a.time
| GROUP BY a.time) AS c
|JOIN b ON c.bTime = b.time
|GROUP BY b.time
""".stripMargin).show()
将为b(时间和b值)的每个值打印一个时间列表和一个值列表。
使用DataFrames :
import org.apache.spark.sql.functions._
val aWithMinB: DataFrame = dfA
.join(dfB, dfA("time") < dfB("time"))
.groupBy(dfA("time"))
.agg(first(dfA("aValue")), min(dfB("time")))
.withColumnRenamed("FIRST(aValue)", "aValue")
.withColumnRenamed("min(time)", "bTime")
aWithMinB
.join(dfB, dfB("time") === aWithMinB("bTime"))
.groupBy(dfB("time"))
.agg(collect_list(aWithMinB("time")), collect_list(aWithMinB("aValue")), first(dfB("time")), first(dfB("bValue")))
.show()
请注意,两者都只适用于Spark 1.6.0或更高版本,因为早期版本中不存在collect_list
。
更新:此流程的一些解释:
a
中应分组的所有记录创建“公共值”成为结果中的单个记录a
中应分组的值是b
中两个连续记录之间的值。因此,他们与更多的b.time
共享最小值,然后是他们的时间。换句话说 - 对于a
中的每次X,我们在b
中查找大于X的最小时间。这将是相同的值表示a
中两个连续b
s a
加入b
,条件为b.time > a.time
(为b
的每条记录获取a
的许多记录,然后按a.time
分组(将结果缩减回a
中每条记录的一条记录),为每条此类记录和最小 b.time
>每个a
列的第一个值(取第一个值并不重要 - 所有分组记录对所有a
列都具有相同的值!)a
中的每条记录提供了这个“额外信息”,我们将其加载到b
列上的time
和该列的分组。具有相同a
的所有bTime
条记录都会加入相应的b
记录,我们就完成了:我们再次对所有first
使用b
s列(同样,所有分组记录的所有值都相同,因为我们将b
的唯一标识符分组),并在collect_list
列上使用a
将所有值都设为一个清单。