最近工作的时候写了一小段用python操作spark的代码,主要流程是先读取一个较大的数据表,然后根据部分字段分组,统计每组的行数。简而言之就是一个word count的工作。但是写的代码单机跑很慢,即使放到集群上在10个节点上跑也花了1小时。

  代码给老大一看就发现写的不行。一个关键问题就是用在分组的时候用了groupByKey, 然后再count。老大推荐我用reduceByKey。改完代码之后果然快了不少,20分钟就跑完了。毕竟老大!

  之后去搜了一下reduceByKey和groupByKey的区别,发现网上还有不少针对这两个方法使用的讨论,回答基本都是类似的,不推荐使用groupByKey, 尤其是数据量较大的情况下。举的例子也基本相同,都是下面这两张图。

  这两个方法都能对数据分组并做一些类似计数、求和之类操作。但是具体实现细节却是不同的。

pyspark sample 个数 pyspark groupby count_spark

  以单词计数问题为例。首先看reduceByKey,被搬移前在同一机器上数据已经由传入的函数预先处理了,比如单词计数时,在每个机器上已经做了一遍计数操作,得到的是(key, count)的形式,而不再是(key, 1),然后再传输。这样大大减少了需要传输的数据量。

pyspark sample 个数 pyspark groupby count_pyspark sample 个数_02

  再看groupByKey,直接搬移的是原始的键值对,即(key, value=1), 如果每个机器上存在很多的相同的key时,这个步骤比reduceByKey需要传输的数据量更大。

  另外,当数据最后被搬移到一个节点上时,由于groupByKey搬过来的数据量往往远远大于reduceByKey,当原始数据量较大的时候可能在单一节点的内存中放不下,这时候可能需要存到磁盘上,那就非常慢了。

  假如要从另外一个角度来看为什么reduceByKey可以先在每个机器上对数据预处理一下,而groupByKey不行,我觉得可以这么记。因为reduceByKey使用时还需要传入一个函数作为参数,比如add,所以会先add一下。而groupByKey是group完之后再选一些聚集函数,比如count,因而全部group完了之后再去count。
  嗯,大概可以这样理解吧。