如何在PySpark(或SQL)中跨不同列聚合值? 让我们考虑下面的输入数据< /P> | incremental_id | session_start_id | session_end_id | items_bought | |----------------|------------------|----------------|--------------| | 1 | a | b | 1 | | 2 | z | t | 7 | | 3 | b | c | 0 | | 4 | c | d | 3 |

如何在PySpark(或SQL)中跨不同列聚合值? 让我们考虑下面的输入数据< /P> | incremental_id | session_start_id | session_end_id | items_bought | |----------------|------------------|----------------|--------------| | 1 | a | b | 1 | | 2 | z | t | 7 | | 3 | b | c | 0 | | 4 | c | d | 3 |,sql,apache-spark,pyspark,apache-spark-sql,Sql,Apache Spark,Pyspark,Apache Spark Sql,其中: 每行代表一个用户会话 每个会话记录一个开始/结束会话id 我们知道前3行与同一用户关联,因为session\u end\u id=session\u start\u id。第4行与第二个用户关联 我希望能够汇总上述数据,以便获得: 第一位客户购买了4件物品 第二位客户购买了7件物品 如何在PySpark或最终在纯SQL中实现这一点?我希望避免在PySpark中使用UDF,但如果这是唯一的方法,那也没关系 谢谢你的帮助 编辑: 我已经更新了示例dataframe,由于连续会话公共表表达式是

其中:

每行代表一个用户会话 每个会话记录一个开始/结束会话id 我们知道前3行与同一用户关联,因为session\u end\u id=session\u start\u id。第4行与第二个用户关联 我希望能够汇总上述数据,以便获得:

第一位客户购买了4件物品 第二位客户购买了7件物品 如何在PySpark或最终在纯SQL中实现这一点?我希望避免在PySpark中使用UDF,但如果这是唯一的方法,那也没关系

谢谢你的帮助

编辑:
我已经更新了示例dataframe,由于连续会话公共表表达式是其一部分,因此不能单独使用增量id对行进行排序

使用CTE,我们可以使用以下查询

WITH cte(session_start_id, session_end_id, items_bought) AS (
  select session_start_id, session_end_id, items_bought from user_session where session_start_id not in (
    select session_end_id from user_session)
UNION ALL
select a.session_start_id, b.session_end_id, b.items_bought from cte a 
  inner join user_session b on a.session_end_id = b.session_start_id)
  select session_start_id, sum(items_bought) from cte group by (session_start_id)
说明:

在锚查询中,选择所有没有父记录的记录。i、 例如,没有其他记录以当前会话\u开始\u id结束 递归地,从表中将cte的session_end_id与session_start_id连接起来。 将记录分组并返回结果。 SQL Fiddle链接:
注意:在小提琴中使用了甲骨文。但是任何支持CTE的DB引擎都应该工作。

这里是PySpark版本

from pyspark.sql import Window
from pyspark.sql import functions as F
from pyspark.sql.types import *

# create a window over the full data so we can lag the session end id
win = Window().partitionBy().orderBy("incremental_id")

# This is logic to indicate a user change
df = df.withColumn('user_boundary', F.lag(F.col("session_end_id"), 1).over(win) != F.col("session_start_id"))
df = df.withColumn('user_boundary', F.when(F.col("user_boundary").isNull(), F.lit(False)).otherwise(F.col("user_boundary")))

# Now create an artificial user id
df = df.withColumn('user_id', F.sum(F.col("user_boundary").cast(IntegerType())).over(win))

# Aggregate
df.groupby('user_id').agg(F.sum(F.col("items_bought")).alias("total_bought")).show()

+-------+------------+
|user_id|total_bought|
+-------+------------+
|      0|           4|
|      1|           7|
+-------+------------+


如果您能够访问临时表创建和受影响的行计数元数据,则可以移植以下内容:

insert into #CTESubs
select
    session_start_id,
    session_end_id,
    items_bought
from #user_session
WHERE
    session_start_id not in (select session_end_id from #user_session)

while(@@ROWCOUNT <> 0)
begin
    insert into #CTESubs
    select distinct
        p.session_start_id,
        c.session_end_id,
        c.items_bought
    from #user_session c
        inner join #CTESubs p on c.session_start_id = p.session_end_id
    WHERE
        p.session_start_id not in (select session_end_id from #user_session) 
        and c.session_end_id not in (select session_end_id from #CTESubs)
end

select
    session_start_id,
    sum(items_bought) items_bought
from #CTESubs
group by 
    session_start_id;

AFAI可以看到,序列中的两条记录可以通过从前一行中提取值来关联,但我看不到单独在查询中如何关联3+条记录。我认为UDF是必要的。@jxc我认为b.a.不是这样的。我猜是5,d,e,1,看起来像是一个典型的问题。或者,如果样本只是组的一部分,请使用networkx中相同的方法使用pandas_udf。谢谢,但不幸的是,使用lag1的此解决方案假设增量_id表示来自同一用户的后续会话。我补充说,这只是为了上下文,但不管怎样,它都应该起作用。我正在更新示例数据框以使其更加明确。hanks,这似乎可行,但不幸的是,我使用的是prestodb,并且特定版本不支持您建议的递归WITH语句查询。很不幸,我不能使用你提出的方法