Ausgabe
Ich habe eine Spalte in meinem Datenrahmen, die eine Liste von JSONs enthält, aber der Typ ist String. Ich muss explode
diese Spalte ausführen, also muss ich sie zuerst in eine Liste umwandeln. Ich konnte nicht viele Hinweise auf diesen Anwendungsfall finden.
Beispieldaten:
columnName: "[{"name":"a","info":{"age":"1","grade":"b"},"other":7},{"random":"x"}, {...}]"
So sehen die Daten aus, die Felder sind nicht festgelegt (Index 0 enthält möglicherweise JSON mit einigen Feldern, während Index 1 Felder mit einigen anderen Feldern enthält). In der Liste können mehr verschachtelte JSONs oder einige zusätzliche Felder enthalten sein. Ich verwende derzeit diese –
"""explode(split(regexp_replace(regexp_replace(colName, '(\\\},)','}},'), '(\\\[|\\\])',''), "},")) as colName"""
wo ich nur “}” durch “}}” ersetze, dann “[]” entferne und dann split auf “}” aufrufe, aber dieser Ansatz funktioniert nicht, da es verschachtelte JSONs gibt.
Wie kann ich das Array aus der Zeichenfolge extrahieren?
Lösung
Sie können es auf diese Weise versuchen:
// Initial DataFrame
df.show(false)
+----------------------------------------------------------------------+
|columnName |
+----------------------------------------------------------------------+
|[{"name":"a","info":{"age":"1","grade":"b"},"other":7},{"random":"x"}]|
+----------------------------------------------------------------------+
df.printSchema()
root
|-- columnName: string (nullable = true)
// toArray is a user defined function that parses an array of json objects which is present as a string
import org.json.JSONArray
val toArray = udf { (data: String) => {
val jsonArray = new JSONArray(data)
var arr: Array[String] = Array()
val objects = (0 until jsonArray.length).map(x => jsonArray.getJSONObject(x))
objects.foreach { elem =>
arr :+= elem.toString
}
arr
}
}
// Using the udf and exploding the resultant array
val df1 = df.withColumn("columnName",explode(toArray(col("columnName"))))
df1.show(false)
+-----------------------------------------------------+
|columnName |
+-----------------------------------------------------+
|{"other":7,"name":"a","info":{"grade":"b","age":"1"}}|
|{"random":"x"} |
+-----------------------------------------------------+
df1.printSchema()
root
|-- columnName: string (nullable = true)
// Parsing the json string by obtaining the schema dynamically
val schema = spark.read.json(df1.select("columnName").rdd.map(x => x(0).toString)).schema
val df2 = df1.withColumn("columnName",from_json(col("columnName"),schema))
df2.show(false)
+---------------+
|columnName |
+---------------+
|[[1, b], a, 7,]|
|[,,, x] |
+---------------+
df2.printSchema()
root
|-- columnName: struct (nullable = true)
| |-- info: struct (nullable = true)
| | |-- age: string (nullable = true)
| | |-- grade: string (nullable = true)
| |-- name: string (nullable = true)
| |-- other: long (nullable = true)
| |-- random: string (nullable = true)
// Extracting all the fields from the json
df2.select(col("columnName.*")).show(false)
+------+----+-----+------+
|info |name|other|random|
+------+----+-----+------+
|[1, b]|a |7 |null |
|null |null|null |x |
+------+----+-----+------+
Bearbeiten:
Sie können es auf diese Weise versuchen, wenn Sie die get_json_object
Funktion verwenden können
// Get the list of columns dynamically
val columns = spark.read.json(df1.select("columnName").rdd.map(x => x(0).toString)).columns
// define an empty array of Column type and get_json_object function to extract the columns
var extract_columns: Array[Column] = Array()
columns.foreach { column =>
extract_columns :+= get_json_object(col("columnName"), "$." + column).as(column)
}
df1.select(extract_columns: _*).show(false)
+-----------------------+----+-----+------+
|info |name|other|random|
+-----------------------+----+-----+------+
|{"grade":"b","age":"1"}|a |7 |null |
|null |null|null |x |
+-----------------------+----+-----+------+
Bitte beachten Sie, dass die info
Spalte nicht vom Strukturtyp ist. Möglicherweise müssen Sie auf ähnliche Weise vorgehen, um die Spalten des verschachtelten JSON zu extrahieren
Beantwortet von – Praneeth Sai
Antwort geprüft von – Pedro (FixError Volunteer)