J'ai un Spark SQL DataFrame
avec des données et ce que j'essaie d'obtenir, c'est toutes les lignes précédant la ligne actuelle dans une plage de dates donnée. Donc, par exemple, je veux avoir toutes les lignes de 7 jours précédant la ligne donnée. J'ai compris que je devais utiliser un Window Function
comme:
Window \
.partitionBy('id') \
.orderBy('start')
et voici le problème. Je veux avoir un rangeBetween
7 jours, mais il n'y a rien dans les documents Spark que j'ai pu trouver à ce sujet. Est-ce que Spark fournit même une telle option? Pour l'instant, je reçois juste toutes les lignes précédentes avec:
.rowsBetween(-sys.maxsize, 0)
mais souhaite réaliser quelque chose comme:
.rangeBetween("7 days", 0)
Si quelqu'un pouvait m'aider à ce sujet, je lui en serais très reconnaissant. Merci d'avance!
Spark> = 2,3
Depuis Spark 2.3, il est possible d'utiliser des objets d'intervalle à l'aide de l'API SQL, mais le support de l'API DataFrame
est toujours en cours) .
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|
## +---+----------+----------+------------------+
Spark <2,3
Pour autant que je sache, ce n'est pas possible directement ni dans Spark ni Hive. Les deux nécessitent ORDER BY
clause utilisée avec RANGE
pour être numérique. La chose la plus proche que j'ai trouvée est la conversion en horodatage et le fonctionnement en secondes. En supposant que la colonne start
contient date
type:
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"))
Une petite aide et définition de fenêtre:
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
Enfin, interrogez:
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|
## +---+----------+----------+------------------+
Loin d'être jolie mais ça marche.