在Apache Spark中,将Dataframe的列值提取为列表。
问题的原因是作者在使用Apache Spark时,想要将DataFrame的某一列的值转换成一个列表。作者给出了三种不同的方法来解决这个问题。
第一种方法是使用collect()
方法将数据收集到Driver端,然后从每条记录中选择元素零。然而,这种方法并不是非常好,因为它将所有的计算负载都放在了Driver上。
为了改进这个方法,作者提出了第二种方法。这种方法使用rdd.map()
将计算负载分散到多个Worker上,而不是只在一个Driver上进行计算。
然而,作者认为rdd.map()
的写法不够优雅,所以在第三种方法中提出了改进。这种方法是将DataFrame转换为Dataset,并使用map()
方法来获取每条记录的第一个元素。由于DataFrame的编码问题,不能直接使用r => r(0)
或_(0)
,而是需要使用r => r.getString(0)
。
最后,作者总结说,虽然这三种方法都可以得到相同的输出,但是第二种和第三种方法更有效和更优雅。作者在Databricks的笔记本中尝试了多种方法,其中第一种方法解决了在集群作业中无法将列表填充的问题。
文章链接:点击查看
问题的原因是想要将Spark的Dataframe中的一列值提取为一个列表,然后使用提取的列表进行后续的处理。在没有进行映射的情况下,直接使用dataFrame.select("YOUR_COLUMN_NAME").collect()只会返回一个包含所有列的Row对象,而不是想要的单个列表。
解决方法是使用dataFrame.select("YOUR_COLUMN_NAME").rdd.map(r => r(0)).collect()进行映射操作。这样可以将每一行的第一个元素提取出来,并将结果以列表的形式返回。但需要注意的是,由于没有指定结果类型,返回的列表类型可能是Any类型。如果想要指定结果类型,可以在映射操作中使用.asInstanceOf[YOUR_TYPE]进行类型转换,例如r => r(0).asInstanceOf[YOUR_TYPE]。
另外,由于Spark自动进行了类型转换,可以省略.rdd部分。而在Spark 2.1.0版本中,使用collect().map(r => r(0))的顺序也可以实现相同的功能,但这种方式可能会慢一些。因为这种解决方案首先在driver上收集所有数据,然后在driver上进行映射(没有使用executor的帮助),只使用了单个driver的处理能力。
如果想要将Spark的Dataframe中的一列值提取为一个列表,可以使用dataFrame.select("YOUR_COLUMN_NAME").rdd.map(r => r(0)).collect()进行映射操作,并根据需要进行类型转换。但需要注意的是,这种解决方案可能会导致性能下降。