是否可以在 spark sql 中以编程方式为列添加别名?
Is it possible to alias columns programmatically in spark sql?
在 spark SQL(也许只有 HiveQL)中可以做到:
select sex, avg(age) as avg_age
from humans
group by sex
这将导致 DataFrame
的列名为 "sex"
和 "avg_age"
.
如何在不使用文本 SQL 的情况下将 avg(age)
别名为 "avg_age"
?
编辑:
在 zero323 的回答之后,我需要添加约束:
要重命名的列的名称可能known/guaranteed甚至不可寻址。在文本 SQL 中,使用 "select EXPR as NAME" 消除了对 EXPR 具有中间名称的要求。在上面的示例中也是如此,其中 "avg(age)" 可以获得各种自动生成的名称(这在 spark 版本和 sql-context 后端之间也有所不同)。
事实证明 def toDF(colNames: String*): DataFrame
正是这样做的。从 2.11.7 文档粘贴:
def toDF(colNames: String*): DataFrame
Returns a new DataFrame with columns renamed. This can be quite
convenient in conversion from a RDD of tuples into a DataFrame
with meaningful names. For example:
val rdd: RDD[(Int, String)] = ...
rdd.toDF() // this implicit conversion creates a DataFrame
// with column name _1 and _2
rdd.toDF("id", "name") // this creates a DataFrame with
// column name "id" and "name"
如果您更喜欢重命名单个列,可以使用 withColumnRenamed
方法:
case class Person(name: String, age: Int)
val df = sqlContext.createDataFrame(
Person("Alice", 2) :: Person("Bob", 5) :: Nil)
df.withColumnRenamed("name", "first_name")
或者您可以使用 alias
方法:
import org.apache.spark.sql.functions.avg
df.select(avg($"age").alias("average_age"))
你可以用小帮手更进一步:
import org.apache.spark.sql.Column
def normalizeName(c: Column) = {
val pattern = "\W+".r
c.alias(pattern.replaceAllIn(c.toString, "_"))
}
df.select(normalizeName(avg($"age")))
匿名列,例如由 avg(age)
生成而没有 AS avg_age
的列,会自动分配名称。正如您在问题中指出的那样,名称是特定于实现的,由命名策略生成。如果需要,您可以编写代码来嗅探环境并根据特定的命名策略实例化适当的发现和重命名策略。数量不多。
在带有 HiveContext
的 Spark 1.4.1 中,格式为“_cN”,其中 N 是table 中的匿名列。在您的情况下,名称将是 _c1
.
让我们假设 human_df
是人类的 DataFrame。从 Spark 1.3 开始:
human_df.groupBy("sex").agg(avg("age").alias("avg_age"))
在 spark SQL(也许只有 HiveQL)中可以做到:
select sex, avg(age) as avg_age
from humans
group by sex
这将导致 DataFrame
的列名为 "sex"
和 "avg_age"
.
如何在不使用文本 SQL 的情况下将 avg(age)
别名为 "avg_age"
?
编辑: 在 zero323 的回答之后,我需要添加约束:
要重命名的列的名称可能known/guaranteed甚至不可寻址。在文本 SQL 中,使用 "select EXPR as NAME" 消除了对 EXPR 具有中间名称的要求。在上面的示例中也是如此,其中 "avg(age)" 可以获得各种自动生成的名称(这在 spark 版本和 sql-context 后端之间也有所不同)。
事实证明 def toDF(colNames: String*): DataFrame
正是这样做的。从 2.11.7 文档粘贴:
def toDF(colNames: String*): DataFrame
Returns a new DataFrame with columns renamed. This can be quite
convenient in conversion from a RDD of tuples into a DataFrame
with meaningful names. For example:
val rdd: RDD[(Int, String)] = ...
rdd.toDF() // this implicit conversion creates a DataFrame
// with column name _1 and _2
rdd.toDF("id", "name") // this creates a DataFrame with
// column name "id" and "name"
如果您更喜欢重命名单个列,可以使用 withColumnRenamed
方法:
case class Person(name: String, age: Int)
val df = sqlContext.createDataFrame(
Person("Alice", 2) :: Person("Bob", 5) :: Nil)
df.withColumnRenamed("name", "first_name")
或者您可以使用 alias
方法:
import org.apache.spark.sql.functions.avg
df.select(avg($"age").alias("average_age"))
你可以用小帮手更进一步:
import org.apache.spark.sql.Column
def normalizeName(c: Column) = {
val pattern = "\W+".r
c.alias(pattern.replaceAllIn(c.toString, "_"))
}
df.select(normalizeName(avg($"age")))
匿名列,例如由 avg(age)
生成而没有 AS avg_age
的列,会自动分配名称。正如您在问题中指出的那样,名称是特定于实现的,由命名策略生成。如果需要,您可以编写代码来嗅探环境并根据特定的命名策略实例化适当的发现和重命名策略。数量不多。
在带有 HiveContext
的 Spark 1.4.1 中,格式为“_cN”,其中 N 是table 中的匿名列。在您的情况下,名称将是 _c1
.
让我们假设 human_df
是人类的 DataFrame。从 Spark 1.3 开始:
human_df.groupBy("sex").agg(avg("age").alias("avg_age"))