Es wird gesagt, dass es ein Muster gibt, das sich unbeabsichtigt verhält, wenn der Zeichenkettentyp des Datumsformats bei der Berechnung des TimeStampType von PySpark unachtsam verwendet wird.
Daher ist es möglich, mit einer Zeichenfolge für TimeStampType zu berechnen, es ist jedoch sicherer, datetime zu verwenden.
Ein spezielles Beispiel wird beschrieben.
Das hier gezeigte Beispiel stammt aus PySPark 2.4.4.
Erstellen Sie mit dem folgenden Code einen Spark DataFrame mit Datumsdaten vom 1. Januar 2000 bis 5. Januar 2000 und führen Sie eine bedingte Verarbeitung für diese Datumsdaten durch.
Überprüfungsdaten
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'])
Die Operation mit datetime für TimeStampType funktioniert normal.
Berechnung von TimeStampType und 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()
Ausgabeergebnis
== 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|
+-------------------+
Als nächstes wird das Ergebnis angezeigt, wenn die Zeichenfolge im Datum / Uhrzeit-Format (JJJJ-MM-TT HH: MM: SS) angegeben wird. Die Zeichenfolge scheint implizit gegossen zu sein, und Operationen können problemlos ausgeführt werden.
TimeStampType und Zeichenfolge(Datum / Uhrzeit-Format)Berechnung
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()
Ausgabeergebnis
== 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|
+-------------------+
Schließlich wird das Ergebnis angezeigt, wenn die Zeichenfolge im Datumsformat (JJJJ-MM-TT) angegeben wird. In diesem Fall gibt es ein Muster, das zu einem Verhalten führt, das nicht intuitiv beabsichtigt ist.
TimeStampType und Zeichenfolge(Datumsformat)Berechnung
print('== string(2000-01-03)')
sdf.where(F.col('timestamp') == '2000-01-03').show()
print('> string(2000-01-03)') #Unbeabsichtigtes Muster
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)') #Unbeabsichtigtes Muster
sdf.where(F.col('timestamp') <= '2000-01-03').show()
print('between string(2000-01-02) and string(2000-01-04)') #Unbeabsichtigtes Muster
sdf.where(F.col('timestamp').between('2000-01-02', '2000-01-04')).show()
Ausgabeergebnis
== 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|
+-------------------+
Aufgrund der impliziten Umwandlung von Zeichenfolgen in TimeStamp zum Zeitpunkt des Betriebs sind "TimeStamp (2000-01-01 00:00:00)" und "TimeStamp (Zeichenfolge (2000-01-01 00:00:00))" gleichwertig. Das Ergebnis ist wie "TimeStamp (2000-01-01 00:00:00) <TimeStamp (Zeichenfolge (2000-01-01))".
Daraus kann man sich vorstellen, dass die Werte für Stunden ("00: 00: 00" im obigen Beispiel) nicht richtig verarbeitet werden. (Für strenge Spezifikationen müssen Sie die Scala-Quelle auf Details des Vorgangs überprüfen.)
Übrigens scheint es beim Casting von StringType nach TimeStampType richtig zu sein. Ein Beispiel wird hier nicht gezeigt, aber wie beim obigen Muster funktioniert es normal, auch wenn die arithmetische Verarbeitung mit TimeStampType ausgeführt wird (natürlich, weil es zwischen TimeStampType-Typen liegt).
Umwandlung von StringType in 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()
Ausgabeergebnis
+-------------------+-------------------+
| 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