1
resposta

Renomear colunas aninhadas (pyspark)

Tenho o seguinte estrutura em um dataframe pyspark:

root
|-- id: string (nullable = true)  
|-- customer: struct (nullable = true)  
|    |-- name: string (nullable = true)  
|-- customerId: long (nullable = true)  
|-- driver: struct (nullable = true)  
|    |-- cpf: long (nullable = true)  
|    |-- driverId: long (nullable = true)  
|    |-- name: string (nullable = true)  
|    |-- registration: long (nullable = true)  |    
|-- ntwkMedium: string (nullable = true)  
|-- numSats: long (nullable = true)  
|-- positionDate: string (nullable = true)  
|-- shadow: string (nullable = true)  
|-- smartCameras: struct (nullable = true)  
|    |-- cameras: array (nullable = true)  
|    |    |-- element: struct (containsNull = true)  
|    |    |    |-- camera_id: long (nullable = true)  
|    |    |    |-- files: array (nullable = true)  
|    |    |    |    |-- element: struct (containsNull = true)  
|    |    |    |    |    |-- begin_time: string (nullable = true)  
|    |    |    |    |    |-- duration: long (nullable = true)  
|    |    |    |    |    |-- url: string (nullable = true)  
|    |    |    |    |    |-- url_provider: string (nullable = true)      
|    |-- eventId: long (nullable = true)  
|    |-- eventType: long (nullable = true)  
|    |-- hwOriginalEventId: long (nullable = true)  
|    |-- messageId: long (nullable = true)  
|    |-- metadata: struct (nullable = true)    
|    |    |-- uploadVideoInfo: struct (nullable = true)  
|    |    |    |-- downloadRetries: boolean (nullable = true)  
|    |    |    |-- requested: boolean (nullable = true)  
|    |    |    |-- showButton: boolean (nullable = true)  
|    |    |    |-- totalVehicleChannel: long (nullable = true)  
|    |-- provider: struct (nullable = true)  
|    |    |-- customer: struct (nullable = true)  
|    |    |    |-- orgId: long (nullable = true)  
|    |    |-- hwtype: string (nullable = true)  
|    |    |-- vehicle: struct (nullable = true)  
|    |    |    |-- deviceId: long (nullable = true)  
|    |-- providerRequestId: long (nullable = true)  
|    |-- requestId: long (nullable = true)  
|    |-- validGps: long (nullable = true)  
|-- yearMonth: string (nullable = true)  

Preciso renomear no array cameras, os seguintes campos: camera_id -> cameraId / begin_time -> beginTime e url_provider -> urlProvider mantendo toda o restante da estutura completa para nova saida.

Tentei inferindo um schema completo do smartCameras mas da erro na saída. Tentei com withColumnRenamed e só deu certo para o cameraId, abaixo dele nao.

** A saída deve ser.**

root
|-- id: string (nullable = true)  
|-- customer: struct (nullable = true)  
|    |-- name: string (nullable = true)  
|-- customerId: long (nullable = true)  
|-- driver: struct (nullable = true)  
|    |-- cpf: long (nullable = true)  
|    |-- driverId: long (nullable = true)  
|    |-- name: string (nullable = true)  
|    |-- registration: long (nullable = true)  |  
|-- ntwkMedium: string (nullable = true)  
|-- numSats: long (nullable = true)  
|-- positionDate: string (nullable = true)  
|-- shadow: string (nullable = true)  
|-- smartCameras: struct (nullable = true)  
|    |-- cameras: array (nullable = true)  
|    |    |-- element: struct (containsNull = true)  
|    |    |    |-- cameraId: long (nullable = true)  
|    |    |    |-- files: array (nullable = true)  
|    |    |    |    |-- element: struct (containsNull = true)  
|    |    |    |    |    |-- beginTime: string (nullable = true)  
|    |    |    |    |    |-- duration: long (nullable = true)  
|    |    |    |    |    |-- url: string (nullable = true)  
|    |    |    |    |    |-- urlProvider: string (nullable = true)      
|    |-- eventId: long (nullable = true)  
|    |-- eventType: long (nullable = true)  
|    |-- hwOriginalEventId: long (nullable = true)  
|    |-- messageId: long (nullable = true)  
|    |-- metadata: struct (nullable = true)    
|    |    |-- uploadVideoInfo: struct (nullable = true)  
|    |    |    |-- downloadRetries: boolean (nullable = true)  
|    |    |    |-- requested: boolean (nullable = true)  
|    |    |    |-- showButton: boolean (nullable = true)  
|    |    |    |-- totalVehicleChannel: long (nullable = true)  
|    |-- provider: struct (nullable = true)  
|    |    |-- customer: struct (nullable = true)  
|    |    |    |-- orgId: long (nullable = true)  
|    |    |-- hwtype: string (nullable = true)  
|    |    |-- vehicle: struct (nullable = true)  
|    |    |    |-- deviceId: long (nullable = true)  
|    |-- providerRequestId: long (nullable = true)  
|    |-- requestId: long (nullable = true)  
|    |-- validGps: long (nullable = true)  
|-- yearMonth: string (nullable = true)      

Conseguem me ajudar?

1 resposta

Oii Lisnete, como você está?

Peço desculpas pela demora em obter um retorno.

Renomear um dataframe que possui várias colunas aninhadas é um grande desafio no spark, pois não é possível modificar um único campo aninhado. É necessário recriar toda uma estrutura.

Para o seu cenário em específico, a título de exemplo, criei a seguinte estrutura:

root
 |-- smartCameras: struct (nullable = true)
 |    |-- cameras: array (nullable = true)
 |    |    |-- element: struct (containsNull = true)
 |    |    |    |-- camera_id: string (nullable = true)
 |    |    |    |-- files: array (nullable = true)
 |    |    |    |    |-- element: struct (containsNull = true)
 |    |    |    |    |    |-- begin_time: string (nullable = true)
 |    |    |    |    |    |-- duration: string (nullable = true)
 |    |    |    |    |    |-- url: string (nullable = true)
 |    |    |    |    |    |-- url_provider: string (nullable = true)

Para renomear, foi necessário utilizar a função col para selecionar o campo de interesse e em seguida a função cast para substituir a estrutura, como mostro abaixo:

spark = SparkSession.builder.getOrCreate()

schema = StructType([
    StructField("smartCameras", StructType([
    StructField("cameras", ArrayType(
        StructType([
            StructField('camera_id', StringType(), True),
            StructField('files', ArrayType(
                StructType([
                    StructField('begin_time', StringType(), True),
                    StructField('duration', StringType(), True),
                    StructField('url', StringType(), True),
                    StructField('url_provider', StringType(), True)
                ]))
        )])),
    )
    ]), True),
    ])

df = spark.createDataFrame(data={}, schema=schema)

struct_schema = ArrayType(StructType([
       StructField('cameraID', StringType(), True),
            StructField('files', ArrayType(
                StructType([
                    StructField('beginTime', StringType(), True),
                    StructField('duration', StringType(), True),
                    StructField('url', StringType(), True),
                    StructField('urlProvider', StringType(), True)
                ]))
        )
]))

df.select(col("smartCameras.cameras").cast(struct_schema)).printSchema()

Resultado:

root
 |-- smartCameras.cameras: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- cameraID: string (nullable = true)
 |    |    |-- files: array (nullable = true)
 |    |    |    |-- element: struct (containsNull = true)
 |    |    |    |    |-- beginTime: string (nullable = true)
 |    |    |    |    |-- duration: string (nullable = true)
 |    |    |    |    |-- url: string (nullable = true)
 |    |    |    |    |-- urlProvider: string (nullable = true)

Deixo abaixo algumas referências sobre o assunto:

Observação: Os links estão em inglês, mas utilizando o recurso de tradução de páginas do próprio navegador é possível compreender.

Qualquer dúvida fico à disposição.

Grande abraço e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.Bons Estudos!