Il est dit qu'il existe un modèle qui se comporte involontairement si le type de chaîne de caractères du format de date est utilisé avec négligence lors du calcul de TimeStampType de PySpark.
Par conséquent, il est possible de calculer avec une chaîne pour TimeStampType, mais il est plus sûr d'utiliser datetime.
Un exemple spécifique sera décrit.
L'exemple présenté ici provient de PySPark 2.4.4.
Avec le code suivant, créez un Spark DataFrame avec des données de date du 1er janvier 2000 au 5 janvier 2000 et effectuez un traitement conditionnel sur ces données de date.
Données de vérification
import pandas as pd
from pyspark.sql import functions as F
pdf = pd.DataFrame(pd.date_range(start='1/1/2000', periods=5), columns=['date'])
sdf = spark.createDataFrame(pdf, ['timestamp'])
L'opération utilisant datetime pour TimeStampType fonctionne normalement.
Calcul de TimeStampType et de datetime
target_datetime = datetime.strptime('2000-01-03', '%Y-%m-%d')
print('== datetime(2000-01-03)')
sdf.where(F.col('timestamp') == datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('> datetime(2000-01-03)')
sdf.where(F.col('timestamp') > datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('>= datetime(2000-01-03)')
sdf.where(F.col('timestamp') >= datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('< datetime(2000-01-03)')
sdf.where(F.col('timestamp') < datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('<= datetime(2000-01-03)')
sdf.where(F.col('timestamp') <= datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('between datetime(2000-01-02) and datetime(2000-01-04)')
sdf.where(F.col('timestamp').between(datetime.strptime('2000-01-02', '%Y-%m-%d'), datetime.strptime('2000-01-04', '%Y-%m-%d'))).show()
Résultat de sortie
== datetime(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-03 00:00:00|
+-------------------+
> datetime(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+
>= datetime(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+
< datetime(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
+-------------------+
<= datetime(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
+-------------------+
between datetime(2000-01-02) and datetime(2000-01-04)
+-------------------+
| timestamp|
+-------------------+
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
+-------------------+
Ensuite, le résultat lorsque la chaîne est donnée au format datetime (aaaa-mm-jj hh: mm: ss) est affiché. string semble être transtypé implicitement et les opérations peuvent être effectuées sans problème.
TimeStampType et chaîne(format datetime)Calcul
print('== string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') == '2000-01-03 00:00:00').show()
print('> string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') > '2000-01-03 00:00:00').show()
print('>= string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') >= '2000-01-03 00:00:00').show()
print('< string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') < '2000-01-03 00:00:00').show()
print('<= string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') <= '2000-01-03 00:00:00').show()
print('between string(2000-01-02 00:00:00) and string(2000-01-04 00:00:00)')
sdf.where(F.col('timestamp').between('2000-01-02 00:00:00', '2000-01-04 00:00:00')).show()
Résultat de sortie
== string(2000-01-03 00:00:00)
+-------------------+
| timestamp|
+-------------------+
|2000-01-03 00:00:00|
+-------------------+
> string(2000-01-03 00:00:00)
+-------------------+
| timestamp|
+-------------------+
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+
>= string(2000-01-03 00:00:00)
+-------------------+
| timestamp|
+-------------------+
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+
< string(2000-01-03 00:00:00)
+-------------------+
| timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
+-------------------+
<= string(2000-01-03 00:00:00)
+-------------------+
| timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
+-------------------+
between string(2000-01-02 00:00:00) and string(2000-01-04 00:00:00)
+-------------------+
| timestamp|
+-------------------+
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
+-------------------+
Enfin, le résultat lorsque la chaîne est donnée au format date (aaaa-mm-jj) est affiché. Dans ce cas, il existe un modèle qui entraîne un comportement qui n'est pas intuitivement prévu.
TimeStampType et chaîne(format de date)Calcul
print('== string(2000-01-03)')
sdf.where(F.col('timestamp') == '2000-01-03').show()
print('> string(2000-01-03)') #Motif involontaire
sdf.where(F.col('timestamp') > '2000-01-03').show()
print('>= string(2000-01-03)')
sdf.where(F.col('timestamp') >= '2000-01-03').show()
print('< string(2000-01-03)')
sdf.where(F.col('timestamp') < '2000-01-03').show()
print('<= string(2000-01-03)') #Motif involontaire
sdf.where(F.col('timestamp') <= '2000-01-03').show()
print('between string(2000-01-02) and string(2000-01-04)') #Motif involontaire
sdf.where(F.col('timestamp').between('2000-01-02', '2000-01-04')).show()
Résultat de sortie
== string(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-03 00:00:00|
+-------------------+
> string(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+
>= string(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+
< string(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
+-------------------+
<= string(2000-01-03)
+-------------------+
| timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
+-------------------+
between string(2000-01-02) and string(2000-01-04)
+-------------------+
| timestamp|
+-------------------+
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
+-------------------+
En raison de la conversion implicite de la chaîne en TimeStamp au moment de l'opération, «TimeStamp (2000-01-01 00:00:00)» et «TimeStamp (string (2000-01-01 00:00:00))» sont équivalents. Et le résultat est comme TimeStamp (2000-01-01 00:00:00) <TimeStamp (string (2000-01-01))
.
À partir de là, on peut imaginer que les valeurs des heures («00: 00: 00» dans l'exemple ci-dessus) ne sont pas traitées correctement. (Pour des spécifications strictes, vous devez vérifier la source Scala pour les détails de l'opération)
À propos, lors de la conversion de StringType en TimeStampType, il semble que la conversion soit correcte. Un exemple n'est pas montré ici, mais comme avec le modèle ci-dessus, même si le traitement arithmétique avec TimeStampType est effectué, il fonctionne normalement (naturellement car il est entre les types TimeStampType).
Conversion de StringType en TimeStampType
df = spark.createDataFrame([('2000',), ('2000-01-01',), ('2000-01-01 00:00:00',) ], ['str'])
df = df.withColumn('timestamp', F.col('str').cast('timestamp'))
df.show()
Résultat de sortie
+-------------------+-------------------+
| str| timestamp|
+-------------------+-------------------+
| 2000|2000-01-01 00:00:00|
| 2000-01-01|2000-01-01 00:00:00|
|2000-01-01 00:00:00|2000-01-01 00:00:00|
+-------------------+-------------------+
Recommended Posts