所以目前我有一张这样的桌子
userID, day, itemID
1, 1, A
1, 1, B
2, 2, A
2, 2, C
...
,这意味着用户1在第1天购买了商品A,依此类推。我首先需要提取具有相同itemID的不同数据集,例如以下
userID, day, itemID
1, 1, A
2, 2, A
...
userID, day, itemID
1, 1, B
...
然后,每个数据集将产生遵循相同格式的输出,例如:
userID result
1, x
...
然后,我将外部连接所有这些结果。 如您所见,我遇到的问题是性能,结果数据集的数量取决于我拥有多少个不同的itemID,数量为6时效果很好,整个过程在2分钟内完成,但数量为45时,需要30分钟,我还在等待。该程序只是停留在ContextCleaner:54上,运行非常缓慢。
我已经尝试过在具有超过100G RAM的云上运行此程序,我很好奇为什么连接大量表太慢了。
更新: 最终我出现了stackoverflow错误... 我看了一下执行查询,它很长,我想做一个for循环来连接45个以上的表不是一个好主意。
仅需使用代码示例进一步说明问题
List<String> itemIDs = ...;
Dataset<Row> ret = null;
for (String itemID : itemIDs) {
Dataset<Row> df = mainDF.filter(col("itemID").equalTo(itemID));
Dataset<Row> result = someFunction(df);
if (ret == null) ret = combined;
else {
combined = combined.withColumnRenamed("userID", "userID_right");
ret = ret.join(
combined,
ret.col("userID").equalTo(combined.col("userID_right")),
"full_outer")
.withColumn("user_id",
coalesce(col("userID"), col("userID_right")))
.drop("userID", "userID_right")
.withColumnRenamed("user_id", "userID");
}
}
最终,当我在45次迭代之后尝试执行ret.show()
时,我的机器几乎就死了。
另一个更新: 因此,我想出了如何加快处理速度,将要连接的数据集进行了一个漫长而复杂的转换,它继承了默认的分区数200,显然,当您多次连接具有大量分区的表时,它几乎就死了,但是如果您可以将数据集重新分区为较小的大小(以我为例,则为8),则它的速度要快得多,并在3分钟内完成。干杯。 我认为大部分原因是由于我对RDD的运作方式缺乏深入的了解。
最终更新: 因此,基本上不要将50个或100个以上的小表连接在一起,我认为这不是火花的工作原理,而是可以将其转换为纯Java对象并在其中进行操作。
另一件事是,这种累积操作将使物理计划成倍增长,并且您可以尝试检查点来简化这种情况,但是,当您想要几百个相对较小的表时,它并不会更快一起加入。