Scala Spark-如何按键进行条件还原?

Scala Spark-如何按键进行条件还原?,scala,apache-spark,dataframe,reduce,Scala,Apache Spark,Dataframe,Reduce,我有一个包含两列(键、值)的数据框,如下所示: +------------+--------------------+ | key| value| +------------+--------------------+ |[sid2, sid5]| value1 | | [sid2]| value2 | | [sid6]| value3 | +---------

我有一个包含两列(键、值)的数据框,如下所示:

+------------+--------------------+
|         key|               value|
+------------+--------------------+
|[sid2, sid5]|             value1 |
|      [sid2]|             value2 |
|      [sid6]|             value3 |
+------------+--------------------+
键是一组字符串,我想应用reduceByKey变换,其中如果两个键之间存在交集,则两个键相等,并且输出应如下所示:

+------------+--------------------+
|         key|               value|
+------------+--------------------+
|[sid2, sid5]|   [value1, value2] |
|      [sid6]|             value3 |
+------------+--------------------+
我尝试使用case类作为键wapper,并重写equals和hashCode函数,但没有成功()

知道怎么做吗? 提前谢谢

更新-数据帧架构:

root
 |-- id1: array (nullable = true)
 |    |-- element: string (containsNull = true)
 |-- events1: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- sid: string (nullable = true)
 |    |    |-- uid: string (nullable = true)
 |    |    |-- action: string (nullable = true)
 |    |    |-- touchPoint: string (nullable = true)
 |    |    |-- result: string (nullable = true)
 |    |    |-- timestamp: long (nullable = false)
 |    |    |-- url: string (nullable = true)
 |    |    |-- onlineId: long (nullable = false)
 |    |    |-- channel: string (nullable = true)
 |    |    |-- category: string (nullable = true)
 |    |    |-- clientId: long (nullable = false)
 |    |    |-- newUser: boolean (nullable = false)
 |    |    |-- userAgent: string (nullable = true)
 |    |    |-- group: string (nullable = true)
 |    |    |-- pageType: string (nullable = true)
 |    |    |-- clientIP: string (nullable = true)

这无法通过
reduceByKey
解决,因为问题定义不适用于
byKey
转换。核心要求是密钥具有定义良好的标识,但这里的情况并非如此

考虑数据集,其中有键
[sid2,sid4,sid5]
[sid2,sid3,sid5]
。在这种情况下,无法唯一地将对象分配给分区。重写哈希代码对您毫无帮助

更糟糕的是,一般情况下的问题是分布式的。考虑一组集合,例如对于每个集合至少有一个集合与非空交。在这种情况下,所有值都应该合并到一个“集群”中

总的来说,对于Spark来说,如果没有严格的限制,这不是一个好问题,并且根本无法通过基本的
byKey
转换来解决

低效的解决方案(可能部分解决您的问题)是使用笛卡尔积:

rdd.cartesian(rdd)
  .filter { case ((k1, _), (k2, _)) => intersects(v1, v2) }
  .map { case ((k, _), (_, v)) => (k, v) }
  .groupByKey
  .mapValues(_.flatten.toSet)

然而,这是低效的,不能解决歧义。

这不能用
reduceByKey
解决,因为问题定义不适用于
byKey
转换。核心要求是密钥具有定义良好的标识,但这里的情况并非如此

考虑数据集,其中有键
[sid2,sid4,sid5]
[sid2,sid3,sid5]
。在这种情况下,无法唯一地将对象分配给分区。重写哈希代码对您毫无帮助

更糟糕的是,一般情况下的问题是分布式的。考虑一组集合,例如对于每个集合至少有一个集合与非空交。在这种情况下,所有值都应该合并到一个“集群”中

总的来说,对于Spark来说,如果没有严格的限制,这不是一个好问题,并且根本无法通过基本的
byKey
转换来解决

低效的解决方案(可能部分解决您的问题)是使用笛卡尔积:

rdd.cartesian(rdd)
  .filter { case ((k1, _), (k2, _)) => intersects(v1, v2) }
  .map { case ((k, _), (_, v)) => (k, v) }
  .groupByKey
  .mapValues(_.flatten.toSet)

然而,这是低效的,并且不能解决含糊不清的问题。

我认为使用Spark SQL的Dataset API是可行的(结果是直接翻译了基于RDD的@user9003280解决方案)


我认为使用Spark SQL的Dataset API是可行的(并直接翻译了基于RDD的@user9003280解决方案)


我在100000行数据框上尝试了笛卡尔乘积解决方案。它花费了大量的时间来处理,所以我决定使用graph,在线性时间内(根据图的顶点和边的数量)计算图的连接组件非常简单

  • 创建顶点和边数据帧
  • 构建图表
  • 查找连接的组件
最终结果如下所示:

+------------+------+----------
|         key| value|component
+------------+------+----------
|      [sid5]|value1|component1
|      [sid2]|value2|component1
|      [sid6]|value3|component2
+------------+------+-----------
然后是groupBy(“组件”)


就是这样:)

我在100000行数据框上尝试了笛卡尔乘积解决方案。它花费了很多时间来处理,所以我决定使用graph,在线性时间内计算图的连接组件是很简单的(根据图的顶点和边的数量)

  • 创建顶点和边数据帧
  • 构建图表
  • 查找连接的组件
最终结果如下所示:

+------------+------+----------
|         key| value|component
+------------+------+----------
|      [sid5]|value1|component1
|      [sid2]|value2|component1
|      [sid6]|value3|component2
+------------+------+-----------
然后是groupBy(“组件”)

就这样:)