Spark:如何基于用户ID和时间戳创建sessionId

Spark:如何基于用户ID和时间戳创建sessionId,session,apache-spark,dataframe,Session,Apache Spark,Dataframe,很抱歉问了个新手问题 目前我有日志文件,其中包含诸如:userId、event和timestamp等字段,但缺少sessionId。我的目标是基于时间戳和预定义的超时值为每个记录创建一个sessionId 如果超时值为10,且示例数据帧为: scala> eventSequence.show(false) +----------+------------+----------+ |uerId |event |timestamp | +----------

很抱歉问了个新手问题

目前我有日志文件,其中包含诸如:userId、event和timestamp等字段,但缺少sessionId。我的目标是基于时间戳和预定义的超时值为每个记录创建一个sessionId

如果超时值为10,且示例数据帧为:

scala> eventSequence.show(false)

  +----------+------------+----------+ 
  |uerId     |event       |timestamp |
  +----------+------------+----------+ 
  |U1        |A           |1         | 
  |U2        |B           |2         |
  |U1        |C           |5         |
  |U3        |A           |8         |
  |U1        |D           |20        |
  |U2        |B           |23        |
  +----------+------------+----------+
目标是:

  +----------+------------+----------+----------+
  |uerId     |event       |timestamp |sessionId |
  +----------+------------+----------+----------+
  |U1        |A           |1         |S1        |
  |U2        |B           |2         |S2        |
  |U1        |C           |5         |S1        |
  |U3        |A           |8         |S3        |
  |U1        |D           |20        |S4        |
  |U2        |B           |23        |S5        |
  +----------+------------+----------+----------+
我在R()中找到了一个解决方案,而在Spark中我无法找到它

感谢您对这个问题的任何建议。

dt.withColumn('sessionId',
新列sessionId的表达式)
例如:
dt.timestamp+预定义值TIMEOUT

Shawn的回答涉及“如何创建新列”,而我的目标是“如何基于timestamp创建sessionId列”。经过几天的努力后,窗口功能作为一个简单的解决方案应用于此场景

窗口自Spark 1.4引入以来,在需要此类操作时提供以下功能:

两者都对一组行进行操作,同时仍为每个输入行返回一个值

为了基于时间戳创建sessionId,首先我需要获得用户a的两个即时操作之间的差异。windowDef定义窗口将按“userId”分区并按时间戳排序,然后diff是一列,它将为每一行返回一个值,其值将在分区(组)中当前行之后1行,如果当前行是该分区中的最后一行,则为null

def handleDiff(timeOut: Int) = {
  udf {(timeDiff: Int, timestamp: Int) => if(timeDiff > timeOut) timestamp + ";" else timestamp + ""}
}
val windowDef = Window.partitionBy("userId").orderBy("timestamp")
val diff: Column = lead(eventSequence("timestamp"), 1).over(windowDef)
val dfTSDiff = eventSequence.
withColumn("time_diff", diff - eventSequence("timestamp")).
withColumn("event_seq", handleDiff(TIME_OUT)(col("time_diff"), col("timestamp"))).
groupBy("userId").agg(GroupConcat(col("event_seq")).alias("event_seqs"))

更新: 然后利用Window函数应用类似于“cumsum”的操作(在手册中提供):


以前: 然后按“;”分割,得到每个会话,创建一个sessionId;然后被“,”分割并爆炸到最终结果。因此,sessionId是在字符串操作的帮助下创建的。 (这部分应该改为累积和运算,但我没有找到一个好的解决方案)

任何关于这个问题的想法都是受欢迎的


GroupConcat可在此处找到:


参考:

可能重复的问题与链接的问题不同,它不是重复的问题。链接的问题显示了“如何在DataFrame中添加新列”,而我需要的是“如何在DataFrame中计算新列的值(例如,这里的sessionId)”
// Define a Window, partitioned by userId (partitionBy), ordered by timestamp (orderBy), and delivers all rows before current row in this partition as frame (rowsBetween)
val windowSpec = Window.partitionBy("userId").orderBy("timestamp").rowsBetween(Long.MinValue, 0)
val sessionDf = dfTSDiff.
  withColumn("ts_diff_flag", genTSFlag(TIME_OUT)(col("time_diff"))).
  select(col("userId"), col("eventSeq"), col("timestamp"), sum("ts_diff_flag").over(windowSpec).alias("sessionInteger")).
  withColumn("sessionId", genSessionId(col("userId"), col("sessionInteger")))