Spark collect_list ändert den Datentyp von Array zu String
Ich habe eine folgende Aggregation
val df_date_agg = df
.groupBy($"a",$"b",$"c") .agg(sum($"d").alias("data1"),sum($"e").alias("data2")) .groupBy($"a")
.agg(collect_list(array($"b",$"c",$"data1")).alias("final_data1"), collect_list(array($"b",$"c",$"data2")).alias("final_data2"))
Hier mache ich eine Aggregation und sammle das Ergebnis mit collect_list. Früher haben wir Funken 1 verwendet und es gab mir unten Datentypen.
|-- final_data1: array (nullable = true)
| |-- element: string (containsNull = true)
|-- final_data2: array (nullable = true)
| |-- element: string (containsNull = true)
Jetzt müssen wir auf Spark 2 migrieren, aber wir kommen unter das Schema.
|-- final_data1: array (nullable = true)
| |-- element: array (containsNull = true)
| | |-- element: string (containsNull = true)
|-- final_data1: array (nullable = true)
| |-- element: array (containsNull = true)
| | |-- element: string (containsNull = true)
Bei der first()Aufzeichnung unten ist der Unterschied
spark 1.6
[2020-09-26, Ayush, 103.67] => datatype string
spark 2
WrappedArray(2020-09-26, Ayush, 103.67)
Wie kann ich den gleichen Datentyp beibehalten?
Bearbeiten - Mit Concat versucht
Eine Möglichkeit, ein genaues Schema wie Spark 1.6 zu erhalten, ist die Verwendung von concat wie diesem
val df_date_agg = df
.groupBy($"msisdn",$"event_date",$"network") .agg(sum($"data_mou").alias("data_mou_dly"),sum($"voice_mou").alias("voice_mou_dly")) .groupBy($"msisdn")
.agg(collect_list(concat(lit("["),lit($"event_date"),lit(","),lit($"network"),lit(","),lit($"data_mou_dly"),lit("]")))
Beeinträchtigt es meine Codeleistung? Gibt es einen besseren Weg, dies zu tun?
Antworten
Wie wäre es, wenn Sie das Array in eine Zeichenfolge wie diese umwandeln möchten, da Sie eine Zeichenfolgendarstellung eines Arrays wünschen?
val df_date_agg = df
.groupBy($"a",$"b",$"c") .agg(sum($"d").alias("data1"),sum($"e").alias("data2")) .groupBy($"a")
.agg(collect_list(array($"b",$"c",$"data1") cast "string").alias("final_data1"), collect_list(array($"b",$"c",$"data2") cast "string").alias("final_data2"))
Es könnte einfach das sein, was Ihre alte Version von Spark tat.
Die von Ihnen vorgeschlagene Lösung würde wahrscheinlich auch funktionieren, aber das Umschließen Ihrer Spaltenreferenzen litist nicht erforderlich ( lit($"event_date")). $"event_date"reicht.
Das Füllen der Spalten final1 und final2 würde dieses Problem beheben.
val data = Seq((1,"A", "B"), (1, "C", "D"), (2,"E", "F"), (2,"G", "H"), (2,"I", "J"))
val df = spark.createDataFrame(
data
).toDF("col1", "col2", "col3")
val old_df = df.groupBy(col("col1")).agg(
collect_list(
array(
col("col2"),
col("col3")
)
).as("final")
)
val new_df = old_df.select(col("col1"), flatten(col("final")).as("final_new"))
println("Input Dataframe")
df.show(false)
println("Old schema format")
old_df.show(false)
old_df.printSchema()
println("New schema format")
new_df.show(false)
new_df.printSchema()
Ausgabe:
Input Dataframe
+----+----+----+
|col1|col2|col3|
+----+----+----+
|1 |A |B |
|1 |C |D |
|2 |E |F |
|2 |G |H |
|2 |I |J |
+----+----+----+
Old schema format
+----+------------------------+
|col1|final |
+----+------------------------+
|1 |[[A, B], [C, D]] |
|2 |[[E, F], [G, H], [I, J]]|
+----+------------------------+
root
|-- col1: integer (nullable = false)
|-- final: array (nullable = true)
| |-- element: array (containsNull = true)
| | |-- element: string (containsNull = true)
New schema format
+----+------------------+
|col1|final_new |
+----+------------------+
|1 |[A, B, C, D] |
|2 |[E, F, G, H, I, J]|
+----+------------------+
root
|-- col1: integer (nullable = false)
|-- final_new: array (nullable = true)
| |-- element: string (containsNull = true)
In Ihrem speziellen Fall
val df_date_agg = df
.groupBy($"a",$"b",$"c") .agg(sum($"d").alias("data1"),sum($"e").alias("data2")) .groupBy($"a")
.agg(collect_list(array($"b",$"c",$"data1")).alias("final_data1"), collect_list(array($"b",$"c",$"data2")).alias("final_data2"))
.select(flatten(col("final_data1").as("final_data1"), flatten(col("final_data2).as("final_data2))