PysparkでSparkSQLを使用していくつかのPostgreSQLテーブルをDataFrameに格納し、タイプstart
のstop
列とdate
列に基づいていくつかの時系列を生成するクエリを作成しています。
仮定 my_table
含まれています:
start | stop
-------------------------
2000-01-01 | 2000-01-05
2012-03-20 | 2012-03-23
PostgreSQLでは、これを行うのは非常に簡単です。
SELECT generate_series(start, stop, '1 day'::interval)::date AS dt FROM my_table
そしてそれはこのテーブルを生成します:
dt
------------
2000-01-01
2000-01-02
2000-01-03
2000-01-04
2000-01-05
2012-03-20
2012-03-21
2012-03-22
2012-03-23
しかし、プレーンなSparkSQLを使用してそれを行う方法は? UDFまたはいくつかのDataFrameメソッドを使用する必要がありますか?
spark sqlからのデータフレームdf
があるとします、これを試してください
from pyspark.sql.functions as F
from pyspark.sql.types as T
def timeseriesDF(start, total):
series = [start]
for i xrange( total-1 ):
series.append(
F.date_add(series[-1], 1)
)
return series
df.withColumn("t_series", F.udf(
timeseriesDF,
T.ArrayType()
) ( df.start, F.datediff( df.start, df.stop ) )
).select(F.explode("t_series")).show()
@Rakeshの答えは正しいですが、より冗長でない解決策を共有したいと思います。
import datetime
import pyspark.sql.types
from pyspark.sql.functions import UserDefinedFunction
# UDF
def generate_date_series(start, stop):
return [start + datetime.timedelta(days=x) for x in range(0, (stop-start).days + 1)]
# Register UDF for later usage
spark.udf.register("generate_date_series", generate_date_series, ArrayType(DateType()) )
# mydf is a DataFrame with columns `start` and `stop` of type DateType()
mydf.createOrReplaceTempView("mydf")
spark.sql("SELECT explode(generate_date_series(start, stop)) FROM mydf").show()
既存の回答は機能しますが、非常に非効率的です。代わりに、range
を使用してからデータをキャストすることをお勧めします。 Pythonの場合
from pyspark.sql.functions import col
from pyspark.sql import SparkSession
def generate_series(start, stop, interval):
"""
:param start - lower bound, inclusive
:param stop - upper bound, exclusive
:interval int - increment interval in seconds
"""
spark = SparkSession.builder.getOrCreate()
# Determine start and stops in Epoch seconds
start, stop = spark.createDataFrame(
[(start, stop)], ("start", "stop")
).select(
[col(c).cast("timestamp").cast("long") for c in ("start", "stop")
]).first()
# Create range with increments and cast to timestamp
return spark.range(start, stop, interval).select(
col("id").cast("timestamp").alias("value")
)
使用例:
generate_series("2000-01-01", "2000-01-05", 60 * 60).show(5) # By hour
+-------------------+
| value|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-01 01:00:00|
|2000-01-01 02:00:00|
|2000-01-01 03:00:00|
|2000-01-01 04:00:00|
+-------------------+
only showing top 5 rows
generate_series("2000-01-01", "2000-01-05", 60 * 60 * 24).show() # By day
+-------------------+
| value|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
+-------------------+
Sparkv2.4はsequence
関数をサポートします:
sequence(start、stop、step)-開始から停止まで(両端を含む)要素の配列を生成し、ステップごとに増分します。返される要素のタイプは、引数式のタイプと同じです。
サポートされているタイプは、バイト、ショート、整数、ロング、日付、タイムスタンプです。
例:
SELECTシーケンス(1、5);
[1,2,3,4,5]
SELECTシーケンス(5、1);
[5,4,3,2,1]
SELECTシーケンス(to_date( '2018-01-01')、to_date( '2018-03-01')、間隔1か月);
[2018-01-01,2018-02-01,2018-03-01]
https://docs.databricks.com/spark/latest/spark-sql/language-manual/functions.html#sequence