Spark数据帧:collect()vs select()

时间:2017-05-25 07:27:32

标签: apache-spark dataframe apache-spark-sql bigdata

在RDD上调用collect()会将整个数据集返回给驱动程序,导致内存不足,我们应该避免这种情况。

如果在数据帧上调用,collect()会表现出相同的行为吗? select()方法怎么样?
如果在数据框上调用它是否也与collect()的工作方式相同?

6 个答案:

答案 0 :(得分:24)

Actions vs Transformations

  
      
  • 收集(操作) - 在驱动程序中将数据集的所有元素作为数组返回。这通常在过滤器或之后有用   返回足够小的数据子集的其他操作。
  •   

spark-sql doc

  

select(* cols)(转换) - 投影一组表达式并返回一个新的DataFrame。

     

参数:cols - 列名(字符串)或表达式列表   (柱)。如果其中一个列名称为“*”,则会扩展该列   包括当前DataFrame中的所有列。**

df.select('*').collect()
[Row(age=2, name=u'Alice'), Row(age=5, name=u'Bob')]
df.select('name', 'age').collect()
[Row(name=u'Alice', age=2), Row(name=u'Bob', age=5)]
df.select(df.name, (df.age + 10).alias('age')).collect()
[Row(name=u'Alice', age=12), Row(name=u'Bob', age=15)]

数据框上的执行select(column-name1,column-name2,etc)方法返回一个新数据框,该数据框仅包含select()函数中选定的列。

e.g。假设df有几列,包括“name”和“value”以及其他一些列。

df2 = df.select("name","value")

df2只会在df

的整列中保留两列(“名称”和“值”)

df2作为select的结果将在执行程序中而不在驱动程序中(如使用collect()的情况)

sql-programming-guide

df.printSchema()
# root
# |-- age: long (nullable = true)
# |-- name: string (nullable = true)

# Select only the "name" column
df.select("name").show()
# +-------+
# |   name|
# +-------+
# |Michael|
# |   Andy|
# | Justin|
# +-------+

您可以在数据框(spark docs)上运行collect()

>>> l = [('Alice', 1)]
>>> spark.createDataFrame(l).collect()
[Row(_1=u'Alice', _2=1)]
>>> spark.createDataFrame(l, ['name', 'age']).collect()
[Row(name=u'Alice', age=1)]

spark docs

  

要打印驱动程序上的所有元素,可以使用collect()方法   首先将RDD带到驱动程序节点:   rdd.collect()。的foreach(的println)。 这可能导致驱动程序耗尽   但是,因为collect()将整个RDD提取到a   单机;如果你只需要打印一些RDD元素,a   更安全的方法是使用take():rdd.take(100).foreach(println)。

答案 1 :(得分:4)

调用select将导致lazy评估:例如:

val df1 = df.select("col1")
val df2 = df1.filter("col1 == 3")

以上两个语句都会在您对df调用操作时执行的延迟路径,例如showcollect等。

val df3 = df2.collect()

在转化结束时使用.explain来遵循其计划 这里有更详细的信息Transformations and Actions

答案 2 :(得分:3)

直接回答问题:

如果在数据帧上调用,collect()的行为将相同吗?

是的,spark.DataFrame.collect在功能上与spark.RDD.collect相同。它们在这些不同的对象上具有相同的目的。

select()方法怎么样?

没有spark.RDD.select这样的东西,因此它不能与spark.DataFrame.select相同。

如果在数据帧上调用,它是否也与collect()一样工作?

selectcollect之间唯一相似的地方是它们都是DataFrame上的函数。它们的功能重叠绝对为零。

这是我自己的描述:collectsc.parallelize相反。 select与任何SQL语句中的SELECT相同。

如果仍然难以理解collect的实际功能(对于RDD或DataFrame),则需要查找一些有关火花在幕后进行的文章。例如:

答案 3 :(得分:2)

Select用于投射dataframe的部分或全部字段。它不会为您提供value作为输出,而是为您提供新的dataframe。它是transformation

答案 4 :(得分:1)

Select是一个转换,而不是一个动作,因此它被懒惰地评估(实际上并不会只是映射操作来进行计算)。 Collect是一个动作。

尝试:

df.limit(20).collect()

答案 5 :(得分:0)

以粗体显示的简短答案:

  • collect主要用于序列化
    (失去并行性,保留了数据帧的所有其他数据特征)
    例如使用PrintWriter {{ 1}}您无法直接进行pw,必须在df.foreach( r => pw.write(r) )collect之前使用foreach
    PS:“并行性损失”不是“全部损失”,因为在序列化之后它可以再次分配给执行者。

  • df.collect.foreach(etc)主要用于选择列,类似于projection in relational algebra
    (仅在框架上下文中类似,因为Spark select不会进行重复数据删除数据)。
    因此,它也是框架上下文中select的补充。


评论其他答案:我喜欢{em> {em} 中的Jeff's classification of Spark operations(如filter)和 actions (如select )。还要记住,变换(包括collect)是lazily evaluated