[FIXED] Extrahieren Sie ein Array aus einer Liste von JSON-Strings mit Spark

Ausgabe

Ich habe eine Spalte in meinem Datenrahmen, die eine Liste von JSONs enthält, aber der Typ ist String. Ich muss explodediese 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_objectFunktion 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 infoSpalte 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)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like

[FIXED] Long zu HexString

Ausgabe Ich habe das folgende Scala-Snippet: someLong.formatted("%016x") Als Ergebnis erhalte ich den Hex-String. Ich musste jedoch die Scala-Version…