Если конструкция плоская:
val df = Seq((1L, "a", "foo", 3.0)).toDF
df.printSchema
Самое простое, что вы можете сделать, - это использовать toDF
метод:
val newNames = Seq("id", "x1", "x2", "x3")
val dfRenamed = df.toDF(newNames: _*)
dfRenamed.printSchema
Если вы хотите переименовать отдельные столбцы , которые вы можете использовать либо select
с alias
:
df.select($"_1".alias("x1"))
который можно легко обобщить на несколько столбцов:
val lookup = Map("_1" -> "foo", "_3" -> "bar")
df.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)
или withColumnRenamed
:
df.withColumnRenamed("_1", "x1")
которые используются foldLeft
для переименования нескольких столбцов:
lookup.foldLeft(df)((acc, ca) => acc.withColumnRenamed(ca._1, ca._2))
С вложенными структурами ( structs
) одним из возможных вариантов является переименование путем выбора всей структуры:
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
Обратите внимание, что это может повлиять на nullability
метаданные. Другая возможность - переименовать с помощью приведения:
nested.select($"foobar".cast(
"struct<location:struct<point:struct<x:double,y:double>>>"
).alias("record")).printSchema
или:
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
: _*)
значит вdf.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)
: _*
это так называемый оператор splat в scala. По сути, он превращает объект, похожий на массив, в неограниченный список, что полезно, когда вы хотите передать массив функции, которая принимает произвольное количество аргументов, но не имеет версии, которая принимаетList[]
. Если вы хоть немного знакомы с Perl, то это разница междуsome_function(@my_array) # "splatted"
иsome_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))): _*)
.. Не могли бы вы разложить его, пожалуйста? особенноlookup.getOrElse(c,c)
часть.Для тех, кто интересуется версией PySpark (на самом деле она такая же в Scala - см. Комментарий ниже):
merchants_df_renamed = merchants_df.toDF( 'merchant_id', 'category', 'subcategory', 'merchant') merchants_df_renamed.printSchema()
Результат:
источник
toDF()
для переименования столбцов в DataFrame нужно быть осторожным. Этот метод работает намного медленнее, чем другие. У меня DataFrame содержит 100 миллионов записей, и простой запрос на подсчет занимает ~ 3 секунды, тогда как тот же запрос сtoDF()
методом занимает ~ 16 секунд. Но при использованииselect col AS col_new
метода переименования я снова получаю ~ 3 секунды. Более чем в 5 раз быстрее! 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) } : _* ) }
Если это неочевидно, это добавляет префикс и суффикс к каждому из текущих имен столбцов. Это может быть полезно, когда у вас есть две таблицы с одним или несколькими столбцами с одинаковыми именами, и вы хотите их объединить, но все же можете устранить неоднозначность столбцов в результирующей таблице. Было бы неплохо, если бы аналогичный способ был реализован в «обычном» SQL.
источник
Предположим, фрейм данных df имеет 3 столбца id1, name1, price1, и вы хотите переименовать их в id2, name2, price2
val list = List("id2", "name2", "price2") import spark.implicits._ val df2 = df.toDF(list:_*) df2.columns.foreach(println)
Я нашел этот подход полезным во многих случаях.
источник
соединение таблицы буксировки не переименовывать объединенный ключ
// 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) }
работает!
источник
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: _*)
источник