由aggregateByKey看到spark的性能调优

工作一个月,重心都放在spark上,最近多处理K-V结构,对aggregate函数有了一些理解,首先,这是一个高效的函数。

首先要了解,spark的核心思想就是并行计算,对于Pari RDD(K-V数据结构),一个 key 的所有值不一定都在一个同一个 paritition 分区里,甚至是不一定在同一台机器里,但是它们必须共同被计算,那么在聚合的过程中,自然地能够想到是先本地聚合再发送数据做聚合快呢,还是直接将所有数据发送做聚合快呢?这种发送数据的方式在spark中叫做shuffle,是spark 重新分配数据的一种机制,使得这些数据可以跨不同的分区,最终在同一个reduce任务中进行聚合,是一个代价很高的操作,非常消耗内存。

aggregateByKey:

rdd.aggregateByKey(zeroValue, seqOp, combOp)  zeroValue 是需要返回的格式

seqOp操作会按照key聚合各分区中的元素,然后combOp操作把所有分区的聚合结果再次聚合,两个操作的初始值都是zeroValue. seqOp的操作是遍历分区中的所有元素(T),第一个T跟zeroValue做操作,结果再作为与第二个T做操作的zeroValue,直到遍历完整个分区。combOp操作是把各分区聚合的结果,再聚合。

重点理解:先把zeroValue放进x1,再把第一个value放进x2,然后执行函数体。再把结果当做zeroValue(是否能灵活使用的一个分界)

代码

val aggregatedData: RDD[Array[(String, Set[String])]] = dataSet
      .aggregateByKey(Array[(String, Set[String])]())( //把相同cate的数据放入一个Set
        (s1, s2) => { // 每个分区下,相同cate下的value执行函数体,放入同一个Set中
          s1 :+ s2
        },
        (c1, c2) => { // 不同分区上,相同cate下的两个Set合并
          c1 ++ c2
        }
      ).map(_._2)
      .cache()

其中dataSet是一个RDD[(String, (String, Set[String]))]

重要的事情说三遍,aggregateByKey算子会使用用户自定义的函数对每个节点本地的相同key进行预聚合,然后一个本地节点相同key会有一个聚合后的结果,不同集群上相同key的数据才会在网络中传输到某个节点(或一个Reduce Task?这里存疑),在这个节点再做最终的聚合,性能比groupByKey要好很多。因为groupByKey不对数据进行预聚合,直接将所有数据shuffle到一个节点。有了这个函数,就没再看groupByKey和reduceByKey了(目前来说0.0)

个人心得:在之后的学习过程,为了处理大数据,用好Spark,进一步提高效率,一定要多积累一些高效的方法,在学习过程中了解spark底层的处理逻辑。

你可能感兴趣的:(工具)