Apache spark 如何找到连续日期的最长序列?

Apache spark 如何找到连续日期的最长序列?,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我有一个数据库,时间戳是这样的 ID, time 1, 1493596800 1, 1493596900 1, 1493432800 2, 1493596800 2, 1493596850 2, 1493432800 我使用spark SQL,需要为每个ID设置最长的连续日期序列 ID, longest_seq (days) 1, 2 2, 5 3, 1 我试图使这个答案适应我的情况,但我没有达到我的预期 SELECT ID, MIN (d), MAX(d) FROM (

我有一个数据库,时间戳是这样的

ID, time
1, 1493596800
1, 1493596900
1, 1493432800
2, 1493596800
2, 1493596850
2, 1493432800
我使用spark SQL,需要为每个ID设置最长的连续日期序列

ID, longest_seq (days)
1, 2
2, 5
3, 1
我试图使这个答案适应我的情况,但我没有达到我的预期

 SELECT ID, MIN (d), MAX(d)
    FROM (
      SELECT ID, cast(from_utc_timestamp(cast(time as timestamp), 'CEST') as date) AS d, 
                ROW_NUMBER() OVER(
         PARTITION BY ID ORDER BY cast(from_utc_timestamp(cast(time as timestamp), 'CEST') 
                                                           as date)) rn
      FROM purchase
      where ID is not null
      GROUP BY ID, cast(from_utc_timestamp(cast(time as timestamp), 'CEST') as date) 
    )
    GROUP BY ID, rn
    ORDER BY ID
如果有人对如何修复此请求或其中的错误有一些线索,我将非常感谢您的帮助 谢谢

[编辑]更明确的输入/输出

ID, time
1, 1
1, 2
1, 3
2, 1
2, 3
2, 4
2, 5
2, 10
2, 11
3, 1
3, 4
3, 9
3, 11
结果将是:

ID, MaxSeq (in days)
1,3
2,3
3,1

所有访问都在时间戳中,但我需要连续的天数,然后每天的每次访问都会按天计数一次

这就是我喜爱的窗口聚合函数的情况

我认为下面的示例可以帮助您解决问题(至少可以开始)

下面是我使用的数据集。我将您的时间(以长为单位)转换为数字时间来表示一天(并避免在Spark SQL中混淆时间戳,这可能会使解决方案更难理解…可能)

在下面的
visit
数据集中,
time
列表示日期之间的天数,因此
1
s逐个表示连续的天数

scala> visits.show
+---+----+
| ID|time|
+---+----+
|  1|   1|
|  1|   1|
|  1|   2|
|  1|   3|
|  1|   3|
|  1|   3|
|  2|   1|
|  3|   1|
|  3|   2|
|  3|   2|
+---+----+
让我们定义窗口规范,将
id
行分组在一起

import org.apache.spark.sql.expressions.Window
val idsSortedByTime = Window.
  partitionBy("id").
  orderBy("time")
这样,您可以对行进行排序,并对具有相同排序的行进行计数

val answer = visits.
  select($"id", $"time", rank over idsSortedByTime as "rank").
  groupBy("id", "time", "rank").
  agg(count("*") as "count")
scala> answer.show
+---+----+----+-----+
| id|time|rank|count|
+---+----+----+-----+
|  1|   1|   1|    2|
|  1|   2|   3|    1|
|  1|   3|   4|    3|
|  3|   1|   1|    1|
|  3|   2|   2|    2|
|  2|   1|   1|    1|
+---+----+----+-----+

这似乎(非常接近)解决方案。你好像完了

我下面的答案改编自Spark SQL。您将使用以下内容包装SQL查询:

spark.sql("""
SQL_QUERY
""")
因此,对于第一个查询:

CREATE TABLE intermediate_1 AS
SELECT 
    id,
    time,
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY time) AS rn,
    time - ROW_NUMBER() OVER (PARTITION BY id ORDER BY time) AS grp
FROM purchase
这将为您提供:

id, time, rn, grp
1,  1,    1,  0
1,  2,    2,  0
1,  3,    3,  0
2,  1,    1,  0
2,  3,    2,  1
2,  4,    3,  1
2,  5,    4,  1
2,  10,   5,  5
2,  11,   6,  5
3,  1,    1,  0
3,  4,    2,  2
3,  9,    3,  6
3,  11,   4,  7
id, max_consecutive
1,  3
2,  3
3,  1
我们可以看到,连续的行具有相同的grp值。然后我们将使用GROUP BY和COUNT来获得连续时间的数量

CREATE TABLE intermediate_2 AS
SELECT 
    id,
    grp,
    COUNT(*) AS num_consecutive
FROM intermediate_1
GROUP BY id, grp
CREATE TABLE final AS
SELECT 
    id,
    MAX(num_consecutive) as max_consecutive
FROM intermediate_2
GROUP BY id
这将返回:

id, grp, num_consecutive
1,  0,   3
2,  0,   1
2,  1,   3
2,  5,   2
3,  0,   1
3,  2,   1
3,  6,   1
3,  7,   1
现在我们只需使用MAX和GROUP BY来获得最大连续时间数

CREATE TABLE intermediate_2 AS
SELECT 
    id,
    grp,
    COUNT(*) AS num_consecutive
FROM intermediate_1
GROUP BY id, grp
CREATE TABLE final AS
SELECT 
    id,
    MAX(num_consecutive) as max_consecutive
FROM intermediate_2
GROUP BY id
这将给你:

id, time, rn, grp
1,  1,    1,  0
1,  2,    2,  0
1,  3,    3,  0
2,  1,    1,  0
2,  3,    2,  1
2,  4,    3,  1
2,  5,    4,  1
2,  10,   5,  5
2,  11,   6,  5
3,  1,    1,  0
3,  4,    2,  2
3,  9,    3,  6
3,  11,   4,  7
id, max_consecutive
1,  3
2,  3
3,  1

希望这有帮助

使用spark.sql和中间表

scala> val df = Seq((1, 1),(1, 2),(1, 3),(2, 1),(2, 3),(2, 4),(2, 5),(2, 10),(2, 11),(3, 1),(3, 4),(3, 9),(3, 11)).toDF("id","time")
df: org.apache.spark.sql.DataFrame = [id: int, time: int]

scala> df.createOrReplaceTempView("tb1")

scala> spark.sql(""" with tb2(select id,time, time-row_number() over(partition by id order by time) rw1 from tb1), tb3(select id,count(rw1) rw2 from tb2 group by id,rw1) select id, rw2 from tb3 where (id,rw2) in (select id,max(rw2) from tb3 group by id) group by id, rw2 """).show(false)
+---+---+
|id |rw2|
+---+---+
|1  |3  |
|3  |1  |
|2  |3  |
+---+---+


scala>

你提到的一些方法对解决我的问题很有帮助。