python - स्पार्क डेटाफ़्रेम में नेस्टेड फ़ील्ड का नाम बदलें



apache-spark dataframe (1)

अजगर

एकल नेस्टेड फ़ील्ड को संशोधित करना संभव नहीं है। आपको एक पूरी संरचना को फिर से बनाना होगा। इस विशेष मामले में सबसे आसान समाधान cast का उपयोग करना है।

पहले आयात का एक गुच्छा:

from collections import namedtuple
from pyspark.sql.functions import col
from pyspark.sql.types import (
    ArrayType, LongType, StringType, StructField, StructType)

और उदाहरण डेटा:

Record = namedtuple("Record", ["a", "b", "c"])

df = sc.parallelize([([Record("foo", 1, 3)], )]).toDF(["array_field"])

आइए पुष्टि करते हैं कि स्कीमा आपके मामले में समान है:

df.printSchema()
root
 |-- array_field: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- a: string (nullable = true)
 |    |    |-- b: long (nullable = true)
 |    |    |-- c: long (nullable = true)

आप एक स्ट्रिंग के रूप में उदाहरण के लिए एक नया स्कीमा परिभाषित कर सकते हैं:

str_schema = "array<struct<a_renamed:string,b:bigint,c:bigint>>"

df.select(col("array_field").cast(str_schema)).printSchema()
root
 |-- array_field: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- a_renamed: string (nullable = true)
 |    |    |-- b: long (nullable = true)
 |    |    |-- c: long (nullable = true)

या एक DataType :

struct_schema = ArrayType(StructType([
    StructField("a_renamed", StringType()),
    StructField("b", LongType()),
    StructField("c", LongType())
]))

 df.select(col("array_field").cast(struct_schema)).printSchema()
root
 |-- array_field: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- a_renamed: string (nullable = true)
 |    |    |-- b: long (nullable = true)
 |    |    |-- c: long (nullable = true)

स्काला

स्काला में समान तकनीकों का उपयोग किया जा सकता है:

case class Record(a: String, b: Long, c: Long)

val df = Seq(Tuple1(Seq(Record("foo", 1, 3)))).toDF("array_field")

val strSchema = "array<struct<a_renamed:string,b:bigint,c:bigint>>"

df.select($"array_field".cast(strSchema))

या

import org.apache.spark.sql.types._

val structSchema = ArrayType(StructType(Seq(
    StructField("a_renamed", StringType),
    StructField("b", LongType),
    StructField("c", LongType)
)))

df.select($"array_field".cast(structSchema))

संभावित सुधार :

यदि आप एक अभिव्यंजक डेटा हेरफेर या JSON प्रोसेसिंग लाइब्रेरी का उपयोग करते हैं, तो डेटा प्रकारों को dict या JSON स्ट्रिंग में डंप करना और उदाहरण के लिए इसे वहां से ले जाना आसान हो सकता है (पायथन / toolz ):

from toolz.curried import pipe, assoc_in, update_in, map
from operator import attrgetter

# Update name to "a_updated" if name is "a"
rename_field = update_in(
    keys=["name"], func=lambda x: "a_updated" if x == "a" else x)

updated_schema = pipe(
   #  Get schema of the field as a dict
   df.schema["array_field"].jsonValue(),
   # Update fields with rename
   update_in(
       keys=["type", "elementType", "fields"],
       func=lambda x: pipe(x, map(rename_field), list)),
   # Load schema from dict
   StructField.fromJson,
   # Get data type
   attrgetter("dataType"))

df.select(col("array_field").cast(updated_schema)).printSchema()

स्पार्क में डेटाफ्रेम df होने:

 |-- array_field: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- a: string (nullable = true)
 |    |    |-- b: long (nullable = true)
 |    |    |-- c: long (nullable = true)

फ़ील्ड array_field.a को array_field.a_renamed कैसे बदला array_field.a_renamed ?

[अद्यतन करें]:

.withColumnRenamed() नेस्टेड फ़ील्ड्स के साथ काम नहीं करता है, इसलिए मैंने इस हैक किए गए और असुरक्षित तरीके की कोशिश की:

# First alter the schema:
schema = df.schema
schema['array_field'].dataType.elementType['a'].name = 'a_renamed'

ind = schema['array_field'].dataType.elementType.names.index('a')
schema['array_field'].dataType.elementType.names[ind] = 'a_renamed'

# Then set dataframe's schema with altered schema
df._schema = schema

मुझे पता है कि एक निजी विशेषता सेट करना एक अच्छा अभ्यास नहीं है, लेकिन मैं df के लिए स्कीमा सेट करने का कोई अन्य तरीका नहीं जानता

मुझे लगता है कि मैं एक सही रास्ते पर df.printSchema() लेकिन df.printSchema() अभी भी array_field.a लिए पुराना नाम array_field.a , हालांकि df.schema == schema True





rename