如何使用Spark 2.3.1中的映射和归约功能执行分组和计数

时间:2018-08-14 21:03:49

标签: java apache-spark mapreduce dataset

我是一只新火花,我正在尝试使用以下火花函数进行分组并计数:

 Dataset<Row> result =  dataset
       .groupBy("column1", "column2")
       .count();

但是我读过here,因为没有分组器,所以使用group by不是一个好主意,这反过来会影响spark作业的运行时效率。 相反,应该使用reduceByKey函数进行聚合操作。

因此我尝试使用reduceByKey函数,但不适用于dataset。相反,数据集使用reduce(ReduceFunction<Row> func)

由于我找不到使用reduce函数进行分组和计数的示例,因此我尝试将其转换为JavaRDD并使用了reduceByKey

//map each row to 1 and then group them by key 
JavaPairRDD<String[], Integer> mapOnes;
            try {
                 mapOnes = dailySummary.javaRDD().mapToPair(
                        new PairFunction<Row, String[], Integer>() {
                            @Override
                            public Tuple2<String[], Integer> call(Row t) throws Exception {
                                return new Tuple2<String[], Integer>(new String[]{t.getAs("column1"), t.getAs("column2")}, 1);
                            }   
                });
            }catch(Exception e) {
                log.error("exception in mapping ones: "+e);
                throw new Exception();
            }


        JavaPairRDD<String[], Integer> rowCount;
        try {
            rowCount = mapOnes.reduceByKey(
                new Function2<Integer, Integer, Integer>() {

                    @Override
                    public Integer call(Integer v1, Integer v2) throws Exception {
                        return v1+v2;
                    }
                });
        }catch(Exception e) {
            log.error("exception in reduce by key: "+e);
            throw new Exception();
        }

但这也为org.apache.spark.SparkException: Task not serializable函数提供了mapToPair例外。

有人可以建议使用数据集的reducemap函数对分组和计数进行计数的更好方法。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您添加的链接中的groupBy指的是RDD。在RDD语义中,groupBy基本上会根据密钥对所有数据进行混洗,即它将与密钥相关的所有值都放在一个位置。

这就是为什么建议使用reduceByKey的原因,因为reduceByKey首先在每个分区上执行reduce操作,并且仅对减少的值进行混洗,这意味着流量减少了很多(并且防止了将所有内容都移到一个分区时出现内存不足的问题)。

在数据集中,groupBy的行为有所不同。它不提供数据集作为返回的对象,而是给出KeyValueGroupedDataset对象。当您依靠此对象(或更通用的agg)时,它基本上定义了一个reducer,其作用与reduceByKey非常相似。

这意味着不需要单独的reduceByKey方法(数据集groupby实际上是reduceByKey的一种形式)。

与原始groupBy(...)。count(...)粘在一起

答案 1 :(得分:0)

基于包含2列的数据集,一列带有县名,另一列是美国的州。

所需的输出:

reduce()
Autauga County, Alabama, Baldwin County, Alabama, Barbour County, Alabama, Bibb County, Alabama, Blount County, Alabama, Bullock County, Alabama, Butler County, Alabama, Calhoun County, Alabama, Chambers County, Alabama, Cherokee County, Alabama, Chilton County,
…

用法:

System.out.println("reduce()");
String listOfCountyStateDs = countyStateDs
    .reduce(
        new CountyStateConcatenatorUsingReduce());
System.out.println(listOfCountyStateDs);

实施:

 private final class CountyStateConcatenatorUsingReduce
      implements ReduceFunction<String> {
    private static final long serialVersionUID = 12859L;

    @Override
    public String call(String v1, String v2) throws Exception {
      return v1 + ", " + v2;
    }
  }

但是,您将必须编写自己的逻辑,这可能很耗时,并且无论如何您都希望使用groupBy ...