Je génère une nouvelle trame de données basée sur le code suivant:
from pyspark.sql.functions import split, regexp_extract
split_log_df = log_df.select(regexp_extract('value', r'^([^\s]+\s)', 1).alias('Host'),
regexp_extract('value', r'^.*\[(\d\d/\w{3}/\d{4}:\d{2}:\d{2}:\d{2} -\d{4})]', 1).alias('timestamp'),
regexp_extract('value', r'^.*"\w+\s+([^\s]+)\s+HTTP.*"', 1).alias('path'),
regexp_extract('value', r'^.*"\s+([^\s]+)', 1).cast('integer').alias('status'),
regexp_extract('value', r'^.*\s+(\d+)$', 1).cast('integer').alias('content_size'))
split_log_df.show(10, truncate=False)
le nouveau dataframe est comme:
J'ai besoin d'une autre colonne montrant la journée de la semaine, quelle serait la meilleure façon élégante de la créer? idéalement, il suffit d'ajouter un champ de type udf dans la sélection.
Merci beaucoup.
Mise à jour: ma question est différente de celle du commentaire, ce dont j'ai besoin est de faire le calcul en fonction d'une chaîne dans log_df, pas en fonction de l'horodatage comme le commentaire, donc ce n'est pas une question en double. Merci.
J'ai finalement résolu la question moi-même, voici la solution complète:
Je ne suis pas satisfait de ma solution car elle semble tellement en zig-zag, il serait apprécié que quelqu'un puisse trouver une solution plus élégante, merci d'avance.
Je suggère une méthode un peu différente
from pyspark.sql.functions import date_format
df.select('capturetime', date_format('capturetime', 'u').alias('dow_number'), date_format('capturetime', 'E').alias('dow_string'))
df3.show()
Il donne ...
+--------------------+----------+----------+
| capturetime|dow_number|dow_string|
+--------------------+----------+----------+
|2017-06-05 10:05:...| 1| Mon|
|2017-06-05 10:05:...| 1| Mon|
|2017-06-05 10:05:...| 1| Mon|
|2017-06-05 10:05:...| 1| Mon|
|2017-06-05 10:05:...| 1| Mon|
|2017-06-05 10:05:...| 1| Mon|
|2017-06-05 10:05:...| 1| Mon|
|2017-06-05 10:05:...| 1| Mon|
J'ai fait cela pour obtenir les jours de semaine à partir de la date:
def get_weekday(date):
import datetime
import calendar
month, day, year = (int(x) for x in date.split('/'))
weekday = datetime.date(year, month, day)
return calendar.day_name[weekday.weekday()]
spark.udf.register('get_weekday', get_weekday)
Exemple d'utilisation:
df.createOrReplaceTempView("weekdays")
df = spark.sql("select DateTime, PlayersCount, get_weekday(Date) as Weekday from weekdays")
Puisque SPARK 1.5.0 a une fonction date_format qui accepte un format comme argument. Ce format renvoie le nom d'un jour de la semaine à partir d'un horodatage:
select date_format(my_timestamp, 'EEEE') from ....
Résultat: ex. 'Mardi'
cela a fonctionné pour moi:
recréer des données similaires à votre exemple:
df = spark.createDataFrame(\
[(1, "2017-11-01 22:05:01 -0400")\
,(2, "2017-11-02 03:15:16 -0500")\
,(3, "2017-11-03 19:32:24 -0600")\
,(4, "2017-11-04 07:47:44 -0700")\
], ("id", "date"))
df.toPandas()
id date
0 1 2017-11-01 22:05:01 -0400
1 2 2017-11-02 03:15:16 -0500
2 3 2017-11-03 19:32:24 -0600
3 4 2017-11-04 07:47:44 -0700
créer une fonction lambda pour gérer la conversion en semaine
funcWeekDay = udf(lambda x: datetime.strptime(x, '%Y-%m-%d').strftime('%w'))
shortdate
shortdate
le code:
from pyspark.sql.functions import udf,col
from datetime import datetime
df=df.withColumn('shortdate',col('date').substr(1, 10))\
.withColumn('weekDay', funcWeekDay(col('shortdate')))\
.drop('shortdate')
résultat:
df.toPandas()
id date weekDay
0 1 2017-11-01 22:05:01 -0400 3
1 2 2017-11-02 03:15:16 -0500 4
2 3 2017-11-03 19:32:24 -0600 5
3 4 2017-11-04 07:47:44 -0700 6