Jeśli konstrukcja jest płaska:
val df = Seq((1L, "a", "foo", 3.0)).toDF
df.printSchema
najprostszą rzeczą jaką możesz zrobić jest użycie toDF
metody:
val newNames = Seq("id", "x1", "x2", "x3")
val dfRenamed = df.toDF(newNames: _*)
dfRenamed.printSchema
Jeśli chcesz zmienić nazwę poszczególne kolumny można skorzystać z jednego select
z alias
:
df.select($"_1".alias("x1"))
które można łatwo uogólnić na wiele kolumn:
val lookup = Map("_1" -> "foo", "_3" -> "bar")
df.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)
lub withColumnRenamed
:
df.withColumnRenamed("_1", "x1")
które używają foldLeft
do zmiany nazwy wielu kolumn:
lookup.foldLeft(df)((acc, ca) => acc.withColumnRenamed(ca._1, ca._2))
W przypadku struktur zagnieżdżonych ( structs
) jedną z możliwych opcji jest zmiana nazwy poprzez wybranie całej struktury:
val nested = spark.read.json(sc.parallelize(Seq(
"""{"foobar": {"foo": {"bar": {"first": 1.0, "second": 2.0}}}, "id": 1}"""
)))
nested.printSchema
@transient val foobarRenamed = struct(
struct(
struct(
$"foobar.foo.bar.first".as("x"), $"foobar.foo.bar.first".as("y")
).alias("point")
).alias("location")
).alias("record")
nested.select(foobarRenamed, $"id").printSchema
Pamiętaj, że może to wpłynąć na nullability
metadane. Inną możliwością jest zmiana nazwy poprzez rzutowanie:
nested.select($"foobar".cast(
"struct<location:struct<point:struct<x:double,y:double>>>"
).alias("record")).printSchema
lub:
import org.apache.spark.sql.types._
nested.select($"foobar".cast(
StructType(Seq(
StructField("location", StructType(Seq(
StructField("point", StructType(Seq(
StructField("x", DoubleType), StructField("y", DoubleType)))))))))
).alias("record")).printSchema
: _*)
znaczy wdf.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)
: _*
jest to tak zwany operator scali "ikona". Zasadniczo rozbija obiekt podobny do tablicy na niezabezpieczoną listę, co jest przydatne, gdy chcesz przekazać tablicę do funkcji, która przyjmuje dowolną liczbę argumentów, ale nie ma wersji, która przyjmuje rozszerzenieList[]
. Jeśli w ogóle znasz Perla, to jest różnica międzysome_function(@my_array) # "splatted"
isome_function(\@my_array) # not splatted ... in perl the backslash "\" operator returns a reference to a thing
.df.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)
... Czy mógłbyś je rozłożyć? zwłaszczalookup.getOrElse(c,c)
część.Dla tych z Was, którzy są zainteresowani wersją PySpark (właściwie tak samo jest w Scali - patrz komentarz poniżej):
merchants_df_renamed = merchants_df.toDF( 'merchant_id', 'category', 'subcategory', 'merchant') merchants_df_renamed.printSchema()
Wynik:
źródło
toDF()
do zmiany nazw kolumn w DataFrame, należy zachować ostrożność. Ta metoda działa znacznie wolniej niż inne. Mam DataFrame zawiera 100M rekordów, a proste zapytanie liczące zajmuje ~ 3s, podczas gdy to samo zapytanie ztoDF()
metodą zajmuje ~ 16s. Ale kiedy używamselect col AS col_new
metody zmiany nazwy, ponownie otrzymuję ~ 3s. Ponad 5 razy szybciej! Spark 2.3.2.3def aliasAllColumns(t: DataFrame, p: String = "", s: String = ""): DataFrame = { t.select( t.columns.map { c => t.col(c).as( p + c + s) } : _* ) }
W przypadku, gdy nie jest to oczywiste, dodaje to przedrostek i sufiks do każdej z bieżących nazw kolumn. Może to być przydatne, gdy masz dwie tabele z jedną lub więcej kolumnami o tej samej nazwie i chcesz do nich dołączyć, ale nadal możesz rozróżnić kolumny w tabeli wynikowej. Z pewnością byłoby miło, gdyby istniał podobny sposób zrobienia tego w „normalnym” języku SQL.
źródło
Załóżmy, że df ramki danych ma 3 kolumny id1, nazwa1, cena1 i chcesz zmienić ich nazwy na id2, nazwa2, cena2
val list = List("id2", "name2", "price2") import spark.implicits._ val df2 = df.toDF(list:_*) df2.columns.foreach(println)
To podejście okazało się przydatne w wielu przypadkach.
źródło
sprzężenie tabeli holowania nie zmienia nazwy połączonego klucza
// method 1: create a new DF day1 = day1.toDF(day1.columns.map(x => if (x.equals(key)) x else s"${x}_d1"): _*) // method 2: use withColumnRenamed for ((x, y) <- day1.columns.filter(!_.equals(key)).map(x => (x, s"${x}_d1"))) { day1 = day1.withColumnRenamed(x, y) }
Pracuje!
źródło
Sometime we have the column name is below format in SQLServer or MySQL table Ex : Account Number,customer number But Hive tables do not support column name containing spaces, so please use below solution to rename your old column names. Solution: val renamedColumns = df.columns.map(c => df(c).as(c.replaceAll(" ", "_").toLowerCase())) df = df.select(renamedColumns: _*)
źródło