web-dev-qa-db-fra.com

Groupe spark dataframe par date

J'ai chargé un DataFrame à partir d'une table SQLServer. Cela ressemble à ceci:

>>> df.show()
+--------------------+----------+
|           timestamp|    Value |
+--------------------+----------+
|2015-12-02 00:10:...|     652.8|
|2015-12-02 00:20:...|     518.4|
|2015-12-02 00:30:...|     524.6|
|2015-12-02 00:40:...|     382.9|
|2015-12-02 00:50:...|     461.6|
|2015-12-02 01:00:...|     476.6|
|2015-12-02 01:10:...|     472.6|
|2015-12-02 01:20:...|     353.0|
|2015-12-02 01:30:...|     407.9|
|2015-12-02 01:40:...|     475.9|
|2015-12-02 01:50:...|     513.2|
|2015-12-02 02:00:...|     569.0|
|2015-12-02 02:10:...|     711.4|
|2015-12-02 02:20:...|     457.6|
|2015-12-02 02:30:...|     392.0|
|2015-12-02 02:40:...|     459.5|
|2015-12-02 02:50:...|     560.2|
|2015-12-02 03:00:...|     252.9|
|2015-12-02 03:10:...|     228.7|
|2015-12-02 03:20:...|     312.2|
+--------------------+----------+

Maintenant, je voudrais grouper (et additionner) les valeurs par heure (ou jour, ou mois ou ...), mais je n'ai pas vraiment la moindre idée de comment je peux faire ça.

Voilà comment je charge le DataFrame. J'ai le sentiment que ce n'est pas la bonne façon de le faire, cependant:

query = """
SELECT column1 AS timestamp, column2 AS value
FROM table
WHERE  blahblah
"""

sc = SparkContext("local", 'test')
sqlctx = SQLContext(sc)

df = sqlctx.load(source="jdbc",
                 url="jdbc:sqlserver://<CONNECTION_DATA>",
                 dbtable="(%s) AS alias" % query)

Est-ce que c'est bon?

16

Depuis 1.5.0 Spark fournit un certain nombre de fonctions comme dayofmonth, hour, month ou year qui peuvent fonctionner sur les dates et les horodatages. Donc, si timestamp est un TimestampType tout ce dont vous avez besoin est une expression correcte. Par exemple:

from pyspark.sql.functions import hour, mean

(df
    .groupBy(hour("timestamp").alias("hour"))
    .agg(mean("value").alias("mean"))
    .show())

## +----+------------------+
## |hour|              mean|
## +----+------------------+
## |   0|508.05999999999995|
## |   1| 449.8666666666666|
## |   2| 524.9499999999999|
## |   3|264.59999999999997|
## +----+------------------+

Avant la version 1.5.0, votre meilleure option est d'utiliser HiveContext et Hive UDF avec selectExpr:

df.selectExpr("year(timestamp) AS year", "value").groupBy("year").sum()

## +----+---------+----------+   
## |year|SUM(year)|SUM(value)|
## +----+---------+----------+
## |2015|    40300|    9183.0|
## +----+---------+----------+

ou SQL brut:

df.registerTempTable("df")

sqlContext.sql("""
    SELECT MONTH(timestamp) AS month, SUM(value) AS values_sum
    FROM df
    GROUP BY MONTH(timestamp)""")

N'oubliez pas que l'agrégation est effectuée par Spark non poussé vers le bas vers la source externe. Habituellement, c'est un comportement souhaité mais il y a des situations où vous pouvez préférer effectuer l'agrégation en tant que sous-requête pour limiter le transfert de données .

23
zero323

En outre, vous pouvez utiliser date_format pour créer la période que vous souhaitez. Groupby jour spécifique:

from pyspark.sql import functions as F

df.select(F.date_format('timestamp','yyyy-MM-dd').alias('day')).groupby('day').count().show()

Grouper un mois spécifique (il suffit de changer le format):

df.select(F.date_format('timestamp','yyyy-MM').alias('month')).groupby('month').count().show()
3
Morit