Supongamos que tengo un marco de datos como este

val customer = Seq(
    ("C1", "Jackie Chan", 50, "Dayton", "M"),
    ("C2", "Harry Smith", 30, "Beavercreek", "M"),
    ("C3", "Ellen Smith", 28, "Beavercreek", "F"),
    ("C4", "John Chan", 26, "Dayton","M")
  ).toDF("cid","name","age","city","sex")

¿Cómo puedo obtener valores cid en una columna y obtener el resto de los valores en un array < struct < column_name, column_value > > en chispa

0
Srinivas 10 may. 2019 a las 16:34

3 respuestas

La mejor respuesta

La única dificultad es que las matrices deben contener elementos del mismo tipo. Por lo tanto, debe convertir todas las columnas en cadenas antes de colocarlas en una matriz (age es un int en su caso). Aquí es cómo va:

val cols = customer.columns.tail
val result = customer.select('cid,
    array(cols.map(c => struct(lit(c) as "name", col(c) cast "string" as "value")) : _*) as "array")

result.show(false)

+---+-----------------------------------------------------------+
|cid|array                                                      |
+---+-----------------------------------------------------------+
|C1 |[[name,Jackie Chan], [age,50], [city,Dayton], [sex,M]]     |
|C2 |[[name,Harry Smith], [age,30], [city,Beavercreek], [sex,M]]|
|C3 |[[name,Ellen Smith], [age,28], [city,Beavercreek], [sex,F]]|
|C4 |[[name,John Chan], [age,26], [city,Dayton], [sex,M]]       |
+---+-----------------------------------------------------------+

result.printSchema()

root
 |-- cid: string (nullable = true)
 |-- array: array (nullable = false)
 |    |-- element: struct (containsNull = false)
 |    |    |-- name: string (nullable = false)
 |    |    |-- value: string (nullable = true)
4
Oli 10 may. 2019 a las 14:24

Puede hacerlo utilizando las funciones de matriz y estructura:

customer.select($"cid", array(struct(lit("name") as "column_name", $"name" as "column_value"), struct(lit("age") as "column_name", $"age" as "column_value") ))

Hará:

 |-- cid: string (nullable = true)
 |-- array(named_struct(column_name, name AS `column_name`, NamePlaceholder(), name AS `column_value`), named_struct(column_name, age AS `column_name`, NamePlaceholder(), age AS `column_value`)): array (nullable = false)
 |    |-- element: struct (containsNull = false)
 |    |    |-- column_name: string (nullable = false)
 |    |    |-- column_value: string (nullable = true)
2
Michel Lemay 10 may. 2019 a las 14:03

Las columnas del mapa podrían ser una mejor manera de lidiar con el problema general. Puede mantener diferentes tipos de valores en el mismo mapa, sin tener que convertirlo en cadena.

df.select('cid',
    create_map(lit("name"), col("name"), lit("age"), col("age"),
               lit("city"), col("city"), lit("sex"),col("sex")
               ).alias('map_col')
  )

O envuelva el mapa col en una matriz si lo desea

De esta manera, aún puede realizar transformaciones numéricas o de cadena en la clave o valor relevante. Por ejemplo:

df.select('cid',
    create_map(lit("name"), col("name"), lit("age"), col("age"),
               lit("city"), col("city"), lit("sex"),col("sex")
               ).alias('map_col')
  )
df.select('*', 
      map_concat( col('cid'), create_map(lit('u_age'),when(col('map_col')['age'] < 18, True)))
)

Espero que tenga sentido, escribí esto directamente aquí, así que perdona si falta un soporte en alguna parte

1
Diogo Marques 10 mar. 2020 a las 13:40