我正在使用Spark 2.4.0,并且想知道如何使用Spark处理以下问题:
以下数据框中的每个条目可以具有两种不同的格式,并提供其ID。我想做的是,如果两个条目共享相同的ID(格式1或格式2),则将它们分组在一起,并为每个组分配一个组ID。
例如
输入数据帧:
$route->setAction($routeAction);
输出数据帧:
-------------------------------
Format1 Id | Format2 Id |
-------------------------------
Format1_1 | Format2_1 |
Format1_2 | Format2_1 |
Format1_3 | Format2_1 |
Format1_4 | Format2_2 |
由于前3个条目以格式2共享相同的ID,因此它们被分组在一起并分配了相同的组ID。
最后一个条目与珍贵的三个条目没有任何关系。它被视为一个单独的组。
我尝试使用HashMap(String,Int)将每个格式ID映射到相应的组ID,但是由于此HashMap不在节点之间分布,因此其他工作节点无法读取先前插入的映射值。
我是Spark的新手,想知道如何在Spark中实现此分组问题?
答案 0 :(得分:1)
这可以看作是图形问题,其中每个id是一个节点,一对id代表边。因此,问题是找到所有连接的组件,并将组件ID附加回原始数据帧。
import org.graphframes._ //execute: spark-shell --packages graphframes:graphframes:0.7.0-spark2.4-s_2.11
import spark.implicits._
import org.apache.spark.sql.functions._
import org.apache.spark.sql._
case class Data(id1: Int, id2: Int)
val data = Seq(Data(1,2), Data(1,3), Data(4,3), Data(4,5)) //sample dataset for testing
val df = data.toDF()
+---+---+
|id1|id2|
+---+---+
| 1| 2|
| 1| 3|
| 4| 3|
| 4| 5|
+---+---+
val nodes = df.select(concat(lit("id1_"), col("id1")).alias("id")).distinct.union(df.select(concat(lit("id2_"), col("id2")).alias("id")).distinct)
val edges = df.select(concat(lit("id1_"), col("id1")).alias("src"), concat(lit("id2_"), col("id2")).alias("dst"))
spark.sparkContext.setCheckpointDir("/tmp/checkpoints")
val g = GraphFrame(nodes, edges)
val comDf = g.connectedComponents.run()
val result = df.withColumn("id", concat(lit("id1_"), col("id1"))).join(comDf, Seq("id"), "left_outer").select("id1","id2","component")
+---+---+------------+
|id1|id2| component|
+---+---+------------+
| 1| 2|154618822656|
| 1| 3|154618822656|
| 4| 3|154618822656|
| 4| 5|154618822656|
+---+---+------------+
答案 1 :(得分:0)
您可以使用dense_rank()
功能。
scala> df.show()
+---------+---------+
| _c0| _c1|
+---------+---------+
|Format1_1|Format2_1|
|Format1_2|Format2_1|
|Format1_3|Format2_1|
|Format1_4|Format2_2|
+---------+---------+
// dataframe api
scala> df.withColumn("group_id",dense_rank().over(Window.orderBy('_c1))).show()
+---------+---------+--------+
| _c0| _c1|group_id|
+---------+---------+--------+
|Format1_1|Format2_1| 1|
|Format1_2|Format2_1| 1|
|Format1_3|Format2_1| 1|
|Format1_4|Format2_2| 2|
+---------+---------+--------+
// sql
scala> spark.sql("select df.*, dense_rank() over (order by _c1) as group_id from df").show()