Spark:根据两列

时间:2017-05-19 14:11:22

标签: apache-spark pyspark pyspark-sql

我有一个表格,其中包含由uid分组的事件。所有行都包含uidvisit_numevent_num列。

visit_num是一个偶尔增加的任意计数器。 event_num是访问中互动的反击。

我想将这两个计数器合并到一个交互计数器中,该计数器对每个事件保持增加1,并在下次访问开始时继续增加。

由于我只看事件之间的相对距离,如果我不在1开始计数器,那就没问题。

|uid |visit_num|event_num|interaction_num| | 1 | 1 | 1 | 1 | | 1 | 1 | 2 | 2 | | 1 | 2 | 1 | 3 | | 1 | 2 | 2 | 4 | | 2 | 1 | 1 | 500 | | 2 | 2 | 1 | 501 | | 2 | 2 | 2 | 502 |

我可以通过重新分区数据并使用monotonically_increasing_id这样来实现这一点:

df.repartition("uid")\
  .sort("visit_num", "event_num")\
  .withColumn("iid", fn.monotonically_increasing_id())

然而,文件说明:

生成的ID保证单调增加且唯一,但不是连续的。当前实现将分区ID放在高31位中,将每个分区中的记录号放在低33位中。假设数据框的分区少于10亿,每个分区的记录少于80亿。

由于id似乎通过分区单调增加,这似乎很好。但是:

  • 我接近达到10亿分区/ uid阈值。
  • 我不想依赖当前实现而不改变。

有没有办法可以用1作为第一个交互数量来启动每个uid?

修改

经过测试后,我注意到有些用户似乎没有使用上述方法连续iid值。

编辑2:窗口

不幸的是,有一些(罕见)情况超过one row has the same visit_num and event_num`。我已尝试使用如下窗口函数,但由于这会将相同的排名分配给两个相同的列,因此这不是一个真正的选项。

iid_window = Window.partitionBy("uid").orderBy("visit_num", "event_num")
df_sample_iid=df_sample.withColumn("iid", fn.rank().over(iid_window))    

1 个答案:

答案 0 :(得分:0)

最好的解决方案是具有等级的窗口函数,如Jacek Laskowski所建议的那样。

iid_window = Window.partitionBy("uid").orderBy("visit_num", "event_num")
df_sample_iid=df_sample.withColumn("iid", fn.rank().over(iid_window))

在我的具体情况下,需要更多数据清理,但一般来说,这应该有效。