我的数据集大约有2000万行,需要大约8 GB的RAM。我的工作有2位执行者,每个执行者10 GB RAM,每个执行者2个内核。由于进行了进一步的转换,数据应该一次全部缓存。
我需要基于4个字段来减少重复项(选择任何重复项)。两个选项:使用groupBy
以及使用repartition
和mapPartitions
。第二种方法允许您指定分区数量,因此在某些情况下可以提高执行速度,对吧?
您能否解释一下哪个选项具有更好的性能?这两个选项的RAM消耗是否相同?
使用groupBy
dataSet
.groupBy(col1, col2, col3, col4)
.agg(
last(col5),
...
last(col17)
);
使用repartition
和mapPartitions
dataSet.sqlContext().createDataFrame(
dataSet
.repartition(parallelism, seq(asList(col1, col2, col3, col4)))
.toJavaRDD()
.mapPartitions(DatasetOps::reduce),
SCHEMA
);
private static Iterator<Row> reduce(Iterator<Row> itr) {
Comparator<Row> comparator = (row1, row2) -> Comparator
.comparing((Row r) -> r.getAs(name(col1)))
.thenComparing((Row r) -> r.getAs(name(col2)))
.thenComparingInt((Row r) -> r.getAs(name(col3)))
.thenComparingInt((Row r) -> r.getAs(name(col4)))
.compare(row1, row2);
List<Row> list = StreamSupport
.stream(Spliterators.spliteratorUnknownSize(itr, Spliterator.ORDERED), false)
.collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparator)), ArrayList::new));
return list.iterator();
}
答案 0 :(得分:2)
第二种方法允许您指定分区数量,因此在某些情况下可以提高执行速度,对吧?
不是。两种方法都允许您指定分区数-在第一种情况下,通过spark.sql.shuffle.partitions
spark.conf.set("spark.sql.shuffle.partitions", parallelism)
但是,如果重复是常见的,则第二种方法本质上效率较低,因为它先洗牌,然后又减少,跳过了地图端的减少(换句话说,这是另一种按组排序)。如果重复的情况很少,但这不会有太大的不同。
另一方面,Dataset
已经提供了dropDuplicates
variants,它包含一组列,并且first
/ last
在这里没有特别的意义(请参见{{ 3}})。