我是Spark和scala的新手,正在研究一个简单的wordCount示例。
为此,我正在使用countByValue,如下所示:
val words = lines.flatMap(x => x.split("\\W+")).map(x => x.toLowerCase())
val wordCount = words.countByValue();
效果很好。
同样的事情也可以实现:
val words = lines.flatMap(x => x.split("\\W+")).map(x => x.toLowerCase())
val wordCounts = words.map(x => (x, 1)).reduceByKey((x, y) => x + y)
val sortedWords = wordCounts.map(x => (x._2, x._1)).sortByKey()
也可以。
现在,我的问题是何时使用哪种方法? 哪个优先于另一个?
答案 0 :(得分:2)
此处的示例-不是单词,而是数字:
val n = sc.parallelize(List(1,2,3,4,5,6,7,8,2,4,2,1,1,1,1,1))
val n2 = n.countByValue
返回本地地图:
n: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[4] at parallelize at command-3737881976236428:1
n2: scala.collection.Map[Int,Long] = Map(5 -> 1, 1 -> 6, 6 -> 1, 2 -> 3, 7 -> 1, 3 -> 1, 8 -> 1, 4 -> 2)
那是关键的区别。
如果您想要开箱即用的地图,那么这就是要走的路。
此外,重点是隐式化并且不能像reduceByKey中那样提供,也不能提供影响。
当数据大小较大时,reduceByKey具有首选项。该映射将全部加载到驱动程序内存中。
答案 1 :(得分:2)
至少在PySpark中,它们是不同的东西。
countByKey
通过reduce
实现,这意味着驱动程序将收集分区的部分结果并自行进行合并。如果结果很大,则驱动程序将不得不合并大量的大词典,这会使驱动程序发疯。
reduceByKey
将改编给不同执行者的密钥,并减少每个工作人员,因此,如果数据量较大,则更有利。
总而言之,当数据很大时,使用map
,reduceByKey
和collect
将使您的驱动程序更快乐。如果您的数据很小,countByKey
会引入较少的网络流量(少一级)。
答案 2 :(得分:1)
答案 3 :(得分:0)
除了上述所有答案外,这是我进一步发现的内容:
CountByValue返回不能以分布式方式使用的地图。
ReduceByKey返回一个rdd,可以进一步以分布式方式使用。