使用group by时在Spark中保留一个未使用的列?

时间:2016-10-26 20:19:26

标签: apache-spark pyspark

所以我有一个用户名的数据框,他们发布了什么线程以及这些帖子的时间戳。如果弄清楚谁是线程的第一个用户以及它是什么时候我想做什么。我知道要弄清楚第一篇文章是在一个帖子上做一个小组然后在时间戳上做一个小时。但是这会删除用户名。如何使用group by并保留用户名?

3 个答案:

答案 0 :(得分:1)

您可以使用HiveContext和Hive named_struct函数对一个groupBy执行此操作。诀窍是min将通过按从左到右的顺序评估列来处理结构,并且只有当前列相等时才移动到下一个。因此,在这种情况下,它实际上只是比较timestamp列,但是通过创建一个包含名称的结构,您可以在min函数吐出结果后访问该结构。

data = [
    ('user', 'thread', 'ts'),
    ('ryan', 1, 1234),
    ('bob', 1, 2345),
    ('bob', 2, 1234),
    ('john', 2, 2223)
]

header = data[0]
rdd = sc.parallelize(data[1:])
df = sqlContext.createDataFrame(rdd, header)
df.registerTempTable('table')

sql = """
SELECT thread, min(named_struct('ts', ts, 'user', user)) as earliest
FROM table
GROUP BY thread
"""

grouped = sqlContext.sql(sql)
final = grouped.selectExpr('thread', 'earliest.user as user', 'earliest.ts as timestamp')

答案 1 :(得分:1)

这可以使用row_number()窗口函数来完成,这将保持所有其他列的完整性。 使用withColumn创建一个类似" thread_user_order"的新列。它的值应该是 row_number()PARTITION BY线程ORDER BY ts 。 然后过滤" thread_user_order" == 1

这是一些伪代码:

df.withColumn("thread_user_order", row_number().over(Window.partitionBy(col("thread")).orderBy(col("ts")))).where(col("thread_user_order").equalTo(1))

答案 2 :(得分:1)

您可以使用结构排序顺序按顺序对字段进行排序,并一次保留两列。然后,当您致电min时,它将按时间戳排序,然后按用户名排序,如果/当两次平局时。

user_time = functions.struct(df.timestamp, df.username).alias('user_time')
min_thread_users_df = df.select(df.thread, user_time).groupby('thread').agg(
    functions.min('user_time').alias('user_time')).select(
    'thread', 'user_time.username', 'user_time.timestamp')