web-dev-qa-db-ja.com

Spark Window Functions-rangeBetween dates

Spark SQL DataFrameにデータがあり、取得しようとしているのは、指定された日付範囲で現在の行の前にあるすべての行です。たとえば、特定の行の前の7日間のすべての行があります。次のようなWindow Functionを使用する必要があることがわかりました。

Window \
    .partitionBy('id') \
    .orderBy('start')

ここに問題があります。 rangeBetweenを7日間にしたいのですが、Sparkでこれについて見つけることができるドキュメントには何もありません。Sparkそのようなオプション?今のところ、私はちょうど前の行をすべて取得しています:

.rowsBetween(-sys.maxsize, 0)

しかし、次のようなものを達成したいと思います:

.rangeBetween("7 days", 0)

誰かがこれについて私を助けることができれば、私は非常に感謝します。前もって感謝します!

27
Nhor

Spark> = 2.3

Spark 2.3なので、SQL APIを使用して間隔オブジェクトを使用できますが、DataFrame AP​​Iサポートは still work in progress です。

df.createOrReplaceTempView("df")

spark.sql(
    """SELECT *, mean(some_value) OVER (
        PARTITION BY id 
        ORDER BY CAST(start AS timestamp) 
        RANGE BETWEEN INTERVAL 7 DAYS PRECEDING AND CURRENT ROW
     ) AS mean FROM df""").show()

## +---+----------+----------+------------------+       
## | id|     start|some_value|              mean|
## +---+----------+----------+------------------+
## |  1|2015-01-01|      20.0|              20.0|
## |  1|2015-01-06|      10.0|              15.0|
## |  1|2015-01-07|      25.0|18.333333333333332|
## |  1|2015-01-12|      30.0|21.666666666666668|
## |  2|2015-01-01|       5.0|               5.0|
## |  2|2015-01-03|      30.0|              17.5|
## |  2|2015-02-01|      20.0|              20.0|
## +---+----------+----------+------------------+

スパーク<2.3

私の知る限り、SparkもHiveでも直接は不可能です。どちらもRANGEで使用されるORDER BY句を数値にする必要があります。 start列にdateタイプが含まれていると仮定すると、

from pyspark.sql import Row

row = Row("id", "start", "some_value")
df = sc.parallelize([
    row(1, "2015-01-01", 20.0),
    row(1, "2015-01-06", 10.0),
    row(1, "2015-01-07", 25.0),
    row(1, "2015-01-12", 30.0),
    row(2, "2015-01-01", 5.0),
    row(2, "2015-01-03", 30.0),
    row(2, "2015-02-01", 20.0)
]).toDF().withColumn("start", col("start").cast("date"))

小さなヘルパーとウィンドウ定義:

from pyspark.sql.window import Window
from pyspark.sql.functions import mean, col


# Hive timestamp is interpreted as UNIX timestamp in seconds*
days = lambda i: i * 86400 

最後にクエリ:

w = (Window()
   .partitionBy(col("id"))
   .orderBy(col("start").cast("timestamp").cast("long"))
   .rangeBetween(-days(7), 0))

df.select(col("*"), mean("some_value").over(w).alias("mean")).show()

## +---+----------+----------+------------------+
## | id|     start|some_value|              mean|
## +---+----------+----------+------------------+
## |  1|2015-01-01|      20.0|              20.0|
## |  1|2015-01-06|      10.0|              15.0|
## |  1|2015-01-07|      25.0|18.333333333333332|
## |  1|2015-01-12|      30.0|21.666666666666668|
## |  2|2015-01-01|       5.0|               5.0|
## |  2|2015-01-03|      30.0|              17.5|
## |  2|2015-02-01|      20.0|              20.0|
## +---+----------+----------+------------------+

かなりきれいですが、動作します。


* Hive言語マニュアル、タイプ

52
zero323