Spark组通过vs分区加上mapPartitions

时间:2019-01-16 12:07:01

标签: apache-spark apache-spark-sql apache-spark-dataset

我的数据集大约有2000万行,需要大约8 GB的RAM。我的工作有2位执行者,每个执行者10 GB RAM,每个执行者2个内核。由于进行了进一步的转换,数据应该一次全部缓存。

我需要基于4个字段来减少重复项(选择任何重复项)。两个选项:使用groupBy以及使用repartitionmapPartitions。第二种方法允许您指定分区数量,因此在某些情况下可以提高执行速度,对吧?

您能否解释一下哪个选项具有更好的性能?这两个选项的RAM消耗是否相同?

使用groupBy

dataSet
    .groupBy(col1, col2, col3, col4)
    .agg(
        last(col5),
        ...
        last(col17)
    );

使用repartitionmapPartitions

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();
}

1 个答案:

答案 0 :(得分:2)

  

第二种方法允许您指定分区数量,因此在某些情况下可以提高执行速度,对吧?

不是。两种方法都允许您指定分区数-在第一种情况下,通过spark.sql.shuffle.partitions

spark.conf.set("spark.sql.shuffle.partitions", parallelism)

但是,如果重复是常见的,则第二种方法本质上效率较低,因为它先洗牌,然后又减少,跳过了地图端的减少(换句话说,这是另一种按组排序)。如果重复的情况很少,但这不会有太大的不同。

另一方面,Dataset已经提供了dropDuplicates variants,它包含一组列,并且first / last在这里没有特别的意义(请参见{{ 3}})。