文章目录

  • 1 官方说明
  • 2 使用时涉及到的的包
  • 3 df.col , df['col'] , col('col')之间的区别
  • 3.1 df.col
  • 3.2 df['col']
  • 3.3 col('col')



1 官方说明

df("columnName")            // On a specific DataFrame.
col("columnName")           // A generic column no yet associated with a DataFrame.
col("columnName.field")     // Extracting a struct field
col("`a.column.with.dots`") // Escape `.` in column names.
expr("a + 1")               // A column that is constructed from a parsed SQL Expression.
lit("abc")                  // A column that produces a literal (constant) value.
$"columnName"               // Scala short hand for a named column.

2 使用时涉及到的的包

  1. on a specific DataFrame.
import org.apache.spark.sql.Column
df("columnName")
  1. A generic column no yet associated with a DataFrame.
import org.apache.spark.sql.functions._
col("columnName")
  1. Scala short hand for a named column.
import spark.implicits._
df.select($"name")
  1. Scala short hand for a named column.
import spark.implicits._
df.select('name)

org.apache.spark.sql.functions是一个Object,提供了约两百多个函数。大部分函数与Hive的差不多。除UDF函数,均可在spark-sql中直接使用。经过import org.apache.spark.sql.functions._ ,也可以用于Dataframe,Dataset。

org.apache.spark.sql.functions导入后可用的函数集合:Spark SQL 函数全集

3 df.col , df[‘col’] , col(‘col’)之间的区别

在大多数实际应用中,都有几乎没有差别。

但是,它们是通过调用不同的基础函数来实现的 (源) ,因此不完全相同。

我们可以举一个小例子来说明:

df = spark.createDataFrame(
 [[1,'a',0),(2,'b',None), (none,'c',3)],
 ['col','2col','third col'] 
)
 
 df.show()
#+ ---- + ---- + --------- + 
#| col | 2col |third col | 
#+ ---- + ---- + --------- + 
#| 1 | a | 0 | 
#| 2 | b | null | 
#| null | c | 3 | 
#+ ---- + ---- + --------- +

3.1 df.col

这是最不灵活的,只能引用使用。运算符可以访问的有效列。这排除了包含空格或特殊字符的列名以及以整数开头的列名。

此语法调用 df.__getattr __(" col"; )

#返回用name表示的:class:`Column。
 print(df .__ getattr __.__ doc__)

>> df.select(df.age).collect()
[行(年龄= 2),行(年龄= 5)]

只能访问其第一列

>>> df.2col 
文件"< ipython-input-39-8e82c2dd5b7c>",第1行
 df.2col 
 ^ 
 SyntaxError:无效语法
 < / code>

3.2 df[‘col’]

这将调用 df.__getitem __ 。您具有更大的灵活性,因为您可以做 __ getattr __ 可以做的所有事情,还可以指定任何列名。

# Column< 2col> 
df [" 2col"]

再次检查一些条件,在本例中为 pyspark.sql。返回由输入字符串指定的列。

此外,您还可以传入多个列(作为列表或 tuple )或列表达式。

from pyspark.sql.functions import expr
df[['col', expr('`third col` IS NULL')]].show()

#+----+-------------------+
#| col|(third col IS NULL)|
#+----+-------------------+
#|   1|              false|
#|   2|               true|
#|null|              false|
#+----+-------------------+

请注意,在多列的情况下, __ getitem __ 只是在调用 pyspark.sql.DataFrame.select

最后,您还可以按索引访问列:

#Column<third col>
df[2]

3.3 col(‘col’)

这是Spark的一种选择列并返回的本地方法expression (所有列函数都是这种情况),根据给定名称选择列。当您需要指定要使用列而不是字符串文字时,这非常有用。

例如,假设我们要创建一个新列,该列将使用任一值基于" 2col"" 的确定要从值从" col" 或"third col" 列拿值。

from pyspark.sql.functions import when

df.withColumn(
    'new', # 新的列名
    f.when(df['2col'].isin(['a', 'c']), 'third col').otherwise('col')
).show()
#+----+----+---------+---------+
#| col|2col|third col|      new|
#+----+----+---------+---------+
#|   1|   a|        0|third col|
#|   2|   b|     null|      col|
#|null|   c|        3|third col|
#+----+----+---------+---------+

oops,这不是我的意思。 Spark认为我想要文字字符串" col" 和" third col" 。相反,我应该写的是:

from pyspark.sql.functions import col
df.withColumn(
    'new', 
    when(df['2col'].isin(['a', 'c']), col('third col')).otherwise(col('col'))
).show()
#+----+----+---------+---+
#| col|2col|third col|new|
#+----+----+---------+---+
#|   1|   a|        0|  0|
#|   2|   b|     null|  2|
#|null|   c|        3|  3|
#+----+----+---------+---+

因为是col(),它创建了列表达式而没有检查以下2方面:

  • It can be re-used as it’s not df specific - 它可以重复使用不特定于df
  • It can be used before the df is assigned - 可以在分配df之前使用

可以理解成它是游离的,类似于一个”series游侠“

age = col('dob') / 365
if_expr = when(age < 18, 'underage').otherwise('adult')

df1 = df.read.csv(path).withColumn('age_category', if_expr)

df2 = df.read.parquet(path)\
        .select('*', age.alias('age'), if_expr.alias('age_category'))
  • age generates Column<b'(dob / 365)'>
  • if_expr generates Column<b'CASE WHEN ((dob / 365) < 18) THEN underage ELSE adult END'>


举例说明

假设有两个表:

  • df1 : account_id
  • df2 : account_id
# 这里选中的是左表的‘account_id’
df1.join(df2,'account_id','left').select(col('account_id'))
# 等价于写
df1.join(df2,'account_id','left').select(df1.account_id)

# 这里选中的是右表的‘account_id’
df1.join(df2,'account_id','right').select(col('account_id'))
# 等价于写
df1.join(df2,'account_id','right').select(df2.account_id)

# 这里不知道选中谁的时候,体现出了col的牛逼之处
df1.join(df2,'account_id','outer').select(col('account_id'))

总而言之,用col就是很省心

用col吧,大兄弟