我有以下数据框:
+---------------+--------------+--------------+-----+
| column0| column1| column2|label|
+---------------+--------------+--------------+-----+
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2|
+---------------+--------------+--------------+-----+
我想应用groupBy并依靠它并产生以下结果:
+--------------+--------------+-----+
| column1| column2|count|
+--------------+--------------+-----+
|10.0.0.2.54880| 10.0.0.3.5001| 19|
| 10.0.0.3.5001|10.0.0.2.54880| 10|
+--------------+--------------+-----+
我知道我必须使用它:
dataFrame_Train.groupBy("column1", "column2").count().show()
但问题是我需要将“count”列添加为数据框的永久列。
在上述情况下,如果我在dataFrame_Train.show()
之后使用groupBy
,我会看到第一个没有“count”列的数据框。这段代码:
dataFrame_Train.groupBy("column1", "column2").count().show()
`dataFrame_Train.show()`
您能帮我将groupBy("column1", "column2").count()
添加到数据框吗? (因为我将来需要使用“count”列来训练数据)谢谢。
答案 0 :(得分:4)
我们将使用您以csv
格式提供的相同数据。
让我们阅读这些数据:
scala> val df = spark.read.format("csv").load("data.txt").toDF("column0","column1","column2","label")
// df: org.apache.spark.sql.DataFrame = [column0: string, column1: string ... 2 more fields]
我们现在可以通过聚合执行我们的小组:
scala> val df2 = df.groupBy("column1","column2").count
df2: org.apache.spark.sql.DataFrame = [column1: string, column2: string ... 1 more field]
我们需要做的就是在按键执行分组的相同列上进行等同连接:
scala> val df3 = df.join(df2, Seq("column1","column2"))
df3: org.apache.spark.sql.DataFrame = [column1: string, column2: string ... 3 more fields]
Etvoilà!
scala> df3.show
+--------------+--------------+---------------+-----+-----+
| column1| column2| column0|label|count|
+--------------+--------------+---------------+-----+-----+
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604899| 2| 13|
| 10.0.0.3.5001|10.0.0.2.54880|05:49:56.604908| 2| 7|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604900| 2| 13|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604899| 2| 13|
| 10.0.0.3.5001|10.0.0.2.54880|05:49:56.604908| 2| 7|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604900| 2| 13|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604899| 2| 13|
| 10.0.0.3.5001|10.0.0.2.54880|05:49:56.604908| 2| 7|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604900| 2| 13|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604899| 2| 13|
| 10.0.0.3.5001|10.0.0.2.54880|05:49:56.604908| 2| 7|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604900| 2| 13|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604899| 2| 13|
| 10.0.0.3.5001|10.0.0.2.54880|05:49:56.604908| 2| 7|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604900| 2| 13|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604899| 2| 13|
| 10.0.0.3.5001|10.0.0.2.54880|05:49:56.604908| 2| 7|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604900| 2| 13|
|10.0.0.2.54880| 10.0.0.3.5001|05:49:56.604899| 2| 13|
| 10.0.0.3.5001|10.0.0.2.54880|05:49:56.604908| 2| 7|
+--------------+--------------+---------------+-----+-----+
答案 1 :(得分:4)
每当您发现需要groupBy
和join
时,尤其是对于这样一个简单的用例,请考虑窗口聚合函数。
groupBy
和窗口聚合之间的主要区别在于,前者最多为您提供源数据集中的行数,而后者(窗口聚合)为您提供完全源数据集中的行数。这似乎完全符合您的要求,不是吗?
有了这个,让我们看看代码。
import org.apache.spark.sql.expressions.Window
val columns1and2 = Window.partitionBy("column1", "column2") // <-- matches groupBy
import org.apache.spark.sql.functions._
// using count aggregate function over entire partition frame
val counts = ips.withColumn("count", count($"label") over columns1and2)
scala> counts.show
+---------------+--------------+--------------+-----+-----+
| column0| column1| column2|label|count|
+---------------+--------------+--------------+-----+-----+
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604900|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604899|10.0.0.2.54880| 10.0.0.3.5001| 2| 13|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2| 7|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2| 7|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2| 7|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2| 7|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2| 7|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2| 7|
|05:49:56.604908| 10.0.0.3.5001|10.0.0.2.54880| 2| 7|
+---------------+--------------+--------------+-----+-----+
完成!干净简单。这是我心爱的窗口聚合功能!
现在,有趣的部分来了。这个和@eliasah的解决方案之间的区别仅仅是纯语法吗?我不这么认为(但我还在学习如何得出正确的结论)。查看执行计划并自我判断。
以下是窗口聚合的执行计划。
以下是groupBy
和join
的执行计划(由于计划太大而无法合并到一个计划中,我不得不拍两张截图)。
Job-wise groupBy
和join
查询轻松打开窗口聚合,前者为2个Spark工作,后者为5个。
操作员,他们的号码,最重要的是Exchange(Spark SQL的shuffle),窗口聚合可能与groupBy
一起击败join
。