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(“组件”)
就这样:)