Spark入门:实现WordCount的3种方式

大数据 Spark
当我们学习一门新的语言,HelloWorld通常是我们写的第一个程序。而WordCount基本上是我们学习MapReduce思想与编程的第一个程序,无论是Hadoop的MR或者是Spark的RDD操作学习。

[[170182]]

WordCount作为Spark的入门任务,可以很简单,也可以做到比较复杂。 本文从实现功能的角度提出了3种实现方式,至于性能影响,会在后文继续讨论。

注意: 本文使用的Spark版本还是1.6.1.如果读者您已经切换到2.0+版本,请参考GitHub spark的官方例子进行学习。 因为2.0版本的API与1.X 并不能完全兼容,特别是2.0开始使用了SparkSession的概念,而不是SparkContext!

***种方式:mapToPair + reduceByKey

这是官方提供的实现方式,应该也是网上能找到的最多的例子。

官网地址: http://spark.apache.org/examples.html

核心代码:

  1. JavaRDD<String> textFile = sc.textFile("hdfs://..."); 
  2.  
  3. JavaRDD<String> words = textFile.flatMap(new FlatMapFunction<String, String>() { 
  4.  
  5. public Iterable<String> call(String s) { return Arrays.asList(s.split(" ")); } 
  6.  
  7. }); 
  8.  
  9. JavaPairRDD<String, Integer> pairs = words.mapToPair(new PairFunction<String, String, Integer>() { 
  10.  
  11. public Tuple2<String, Integer> call(String s) { return new Tuple2<String, Integer>(s, 1); } 
  12.  
  13. }); 
  14.  
  15. JavaPairRDD<String, Integer> counts = pairs.reduceByKey(new Function2<IntegerIntegerInteger>() { 
  16.  
  17. public Integer call(Integer a, Integer b) { return a + b; } 
  18.  
  19. }); 
  20.  
  21. counts.saveAsTextFile("hdfs://..."); 

总结上面的步骤:

  1. flatmap : 将一整段文字映射成一个字符串数组
  2. mapToPair: 将word 映射成 (word, 1)
  3. reduceByKey: 按照key进行group and plus的操作, 得到最终结果
  4. collect: 这是Action,上面3个都是Transformation

第二种方式:使用countByValue代替mapToPair + reduceByKey

核心代码:

  1. JavaRDD<String> textFile = sc.textFile("hdfs://..."); 
  2.  
  3. JavaRDD<String> words = textFile.flatMap(new FlatMapFunction<String, String>() { 
  4.  
  5. public Iterable<String> call(String s) { return Arrays.asList(s.split(" ")); } 
  6.  
  7. }); 
  8.  
  9. Map<String, Long> counts = words.countByValue(); 

读文件、flatmap这两步都是完全一样的,但是后面直接一个countByValue就搞定了,并且还直接collect到本地了,是不是感觉这一种实现方式更简洁了呢?

至于性能,一般来说这种方式还不错,但是这种方式有一些缺点,参考StackOverFlow的描述:

网址: http://stackoverflow.com/questions/25318153/spark-rdd-aggregate-vs-rdd-reducebykey

countByValue would be the fastest way to do this, however its implementation uses hash maps and merges them so if you have a large amount of data this approach may not scale well (especially when you consider how many issues spark already has with memory). You may want to use the standard way of counting in map reduce which would be to map the line and 1 as pairs then reduceBykey like this:

简单的说,这种方式是使用hash的方式进行merge。 如果处理的数据量比较大的时候,效果可能不怎么好。

注意: 这种方式的性能笔者确实还没有亲自实践过!

第三种方式:AggregateByKey

AggregateByKey 这个方法,可以看做是reduceByKey的增强版,因为reduceByKey的输出类型与输入类型要求是完全一致的。比如wordcount 之中的输入是Tuple2<String, Integer> 输出也同样要求是Tuple2<String,Integer>. 但是AggregateByKey的输出类型可以是不一样的数据类型。 参考下面的代码:

  1. val keysWithValuesList = Array("foo=A""foo=A""foo=A""foo=A""foo=B""bar=C""bar=D""bar=D"
  2.  
  3. val data = sc.parallelize(keysWithValuesList) 
  4.  
  5. //Create key value pairs 
  6.  
  7. val kv = data.map(_.split("=")).map(v => (v(0), v(1))).cache() 
  8.  
  9. val initialCount = 0; 
  10.  
  11. val addToCounts = (n: Int, v: String) => n + 1 
  12.  
  13. val sumPartitionCounts = (p1: Int, p2: Int) => p1 + p2 
  14.  
  15. val countByKey = kv.aggregateByKey(initialCount)(addToCounts, sumPartitionCounts) 

输出:

  1. Aggregate By Key sum Results 
  2.  
  3. bar -> 3 
  4.  
  5. foo -> 5 

可以看到,输入是<String, String> 而输出变成了<String, Integer>

注意: 这种方法,并不是处理WordCount的***的选择,只是说明我们可以使用AggregateByKey这种方式来实现相同的功能

其实还有另外一种实现方式: 使用DataFrame。 但是这种方式需要前期的准备比较多,即如何将数据处理并喂给DataFrame。

一般来说,DataFrame的效率相比其他的RDD的实现方式要高不少,如果在前期准备工作上面难度不是太大的话,非常推荐使用DataFrame的方式。

责任编辑:武晓燕 来源: FlyML
相关推荐

2009-07-02 14:42:55

ExtJS Grid

2020-02-18 20:00:31

PostgreSQL数据库

2022-08-05 08:27:05

分布式系统线程并发

2019-01-31 08:15:38

物联网农业IoT

2015-05-04 10:20:25

2017-09-05 10:20:15

2020-02-10 15:50:18

Spring循环依赖Java

2010-03-12 17:52:35

Python输入方式

2021-07-19 05:48:30

springboot 拦截器项目

2010-08-13 13:25:53

Flex页面跳转

2014-12-31 17:42:47

LBSAndroid地图

2021-11-05 21:33:28

Redis数据高并发

2021-06-24 08:52:19

单点登录代码前端

2021-04-01 06:01:10

嵌入式开发应用程序开发技术

2018-04-02 14:29:18

Java多线程方式

2024-10-11 12:00:00

Python批量文件操作

2024-07-01 12:42:58

2023-12-04 09:31:13

CSS卡片

2021-12-08 10:47:35

RabbitMQ 实现延迟

2022-07-01 08:00:44

异步编程FutureTask
点赞
收藏

51CTO技术栈公众号