由於最近業務遇到了這個場景,而百度後沒有找到解決方法。
我是通過Stack Overflow的提問,獲得了可以實現的答案。
原問題地址是:https://stackoverflow.com/questions/58317153/how-to-split-the-pyspark-dataframe-based-on-the-content-of-the-line。如果有其他解決方法我也會及時更新。
下面詳細描述一下需求。
原始數據示例如下:
+------------+
| value|
+------------+
|Date20191009|
| 1|
| 2|
| 3|
|Date20191010|
| 1|
| 4|
| 5|
+------------+
可以看到,原始數據爲1列PySpark DataFrame格式。這1列的數據包括兩類
- 文件名(例如“ DATE20191009”)
- 文件內容(例如“ 1”,“ 2”,“ 3”)
最終期望結果如下:
+------------+-------+
| value|content|
+------------+-------+
|Date20191009| 1,2,3|
|Date20191010| 1,4,5|
+------------+-------+
可以看到,期望實現的功能是,將1列數據分爲文件名和文件內容。
注意事項爲:
- 文件名和內容的區分在於,是否Date開頭。
- 兩個文件名之間的內容,認爲是第一個文件名的內容。
- 各文件名的內容並不等長,因此不能直接取間隔劃分。
用Pyspark實現的代碼如下:
from pyspark.sql import SparkSession
from pyspark.sql.functions import *
from pyspark.sql.window import Window
spark = SparkSession.builder.appName("DataFrame").getOrCreate()
df = spark.read.text("C:\\mypath\\myfile.txt")
w = Window.rowsBetween(Window.unboundedPreceding, 0)
df1 = df.withColumn('tmp', when(df.value.startswith('Date'), df.value).otherwise(None)).withColumn('temp', last('tmp',
True).over(
w)).drop('tmp')
df1.show()
df2 = df1.filter(df1.value != df1.temp).groupBy(df1.temp).agg(
concat_ws(',', collect_list(df1.value)).alias('content')).withColumnRenamed("temp", "value")
df2.show()