我有一个用例,我需要在给定类别中的每个项目上运行自定义算法,并且对于每个项目,从算法中找到前10个结果并将其存储。 我在这里发布了一个单独的问题,关于groupBy操作的性能含义: Spark SQL - group by after repartitioning
但是,假设我已经能够将列表中给定类别的所有项目分组。输出看起来像这样:
+---------------------------+------------------------------------------+
|category | ids |
+---------------------------+------------------------------------------+
|category-1 | [id1, id2...] |
|category-2 | [idx, idy...] |
+---------------------------+------------------------------------------+
让我们假设每个类别在id列表中可以包含数百万个项目。因此,可以有效地将其视为id列表中的笛卡尔乘积。
我要做的一件事情是做一个flatmap()并为每个category-idm-idn组合创建1行。这是该代码:
Dataset<Row> wpid_cartesian_product_by_category = ids_grouped_by_category.flatMap((FlatMapFunction<Row, Row>) row -> {
List<Row> category_all_ids_combination = new ArrayList<>();
String category = row.getString(0);
List<String> all_ids_for_category = row.getList(1);
for (int i = 0; i < all_ids_for_category.size(); i++){
String itemid1 = all_ids_for_category.get(i);
for (int j = 0; j < all_ids_for_category.size(); j++) {
if (i == j)
continue;
Row cartesian_product_row = RowFactory.create(category, id1, all_ids_for_category.get(j));
category_all_ids_combination.add(cartesian_product_row);
}
}
return category_all_ids_combination.iterator();
}, <encoder>);
有了这个,我已经能够获得一个新的数据集,例如:
+---------------+------------+------------+
|category |id_1 |id_2 |
+---------------+------------+------------+
|category-1 |id1 |id2 |
|category-1 |id1 |id3 |
|category-1 |id2 |id1 |
+---------------+------------+------------+
基本上,每个商品ID和每个类别的其他所有商品ID。虽然这可以工作,但确实会使数据膨胀。正如我最初提到的,我们每个类别可以有100万个项目,因此,在某些情况下,上述代码可能会为每个类别生成100万乘100万行,这确实使数据膨胀。 因此,想了解如何最佳地优化这类笛卡尔积方案。 是否会为每个id创建一个新列并以列格式(例如镶木地板)存储它们,然后逐列运行计算,这是一种更好的处理方式?