Apache Spark编程教程
Apache Spark JavaRDD和任务解决
好吧,我告诉我身边的每个人,如果你不知道map-reduce概念那么你就无法理解Apache Spark。为了证明这一点,让我们解决简单的任务。假设我们在城镇中有以下温度的文本文件:
Prague 35
Madrid 40
Berlin 20
Paris 15
Rome 25
位于Apache Hadoop HDFS文件系统,我们需要编写简单的JavaRDD Apache Spark程序来打印具有温度低于整个平均温度的城镇的行。
JavaRDD API和MapReduce有区别吗?
实际上它不是!要解决前面提到的任务,我们需要将问题分成以下几部分:
- 首先,我们需要编写JavaRDD程序来计算温度和平均值的总和。
- 然后我们要打印温度低于计算平均值的行。
MapReduce解决方案概念
如果我们使用Spring Data for Hadoop或为map-reduce程序指定的简单Apache Hadoop API,那么我们的解决方案将是:
- Map函数将创建键[K,V] ='reducer',town.temperature
- 减少功能将接收先前的键并将整个组的温度相加并计算平均温度。
- 链式地图减少任务将打印温度低于平均值的城镇的结果。
Apache Spark JavaRDD解决方案
(类似于mapreduce)
- 首先,我们需要通过将map函数应用于输入RDD集来获取所有行的JavaRDD温度集:
JavaRDD<String> parsedTemperatures = lines.map(new Function<String, String>() {
private static final long serialVersionUID = 1L;
public String call(String v1) throws Exception {
final String arr[] = SPACE.split(v1);
System.out.println("Reading temperature ["+arr[1]+"] from "+v1);
return arr[1];
}
});
- 然后我们需要将此RDD集转换为CONSTANT.row.temperature表单以将数据准备到reducer中:
JavaPairRDD<String, Integer> forGroup = parsedTemperatures.mapToPair(
new PairFunction<String,
String, Integer>() {
private static final long serialVersionUID = 1L;
public Tuple2<String, Integer> call(String t) throws Exception {
return new Tuple2<String, Integer>("reducer", Integer.parseInt(t));
}
});
- 有了这个数据集,我们就为减速器准备了数据,它将聚合所有温度
JavaPairRDD<String, Integer> counts = forGroup.reduceByKey(
new Function2<Integer, Integer, Integer>() {
private static final long serialVersionUID = 1L;
public Integer call(Integer v1, Integer v2) throws Exception {
System.out.println("Agregatting "+v1+" plus "+v2);
return v1 + v2;
}
});
(再次,像map-reduce概念)
要了解Spark减速器的工作原理,请查看日志:
Reading temperature [35] from Prague 35
Reading temperature [40] from Madrid 40
Agregatting 35 plus 40
Reading temperature [20] from Berlin 20
Agregatting 75 plus 20
Reading temperature [15] from Paris 15
Agregatting 95 plus 15
Reading temperature [25] from Rome 25
Agregatting 110 plus 25
Spark实际上并行运行前三个函数map,mapToPair和reduceByKey!DAG图形分析器组合Spark任务的好处之一!
解决方案的第二部分是打印温度低于平均温度的所有城镇:
Tuple2<String, Integer> sumTemperatures = counts.first();
final Integer sum = sumTemperatures._2;
final long count = parsedTemperatures.count();
final double avg = (double) sum / count;
System.out.println("Average temperature "+avg);
JavaRDD<String> result = lines.filter(new Function<String, Boolean>() {
private static final long serialVersionUID = 1L;
public Boolean call(String v1) throws Exception {
final String arr[] = SPACE.split(v1);
long temperature = Long.parseLong(arr[1]);
return temperature <= avg;
}
});
List<String> resultList = result.collect();
for (String item: resultList) {
System.out.println("Result item: "+item);
}
让我们解释一下这段代码:
- 通过counts.first()我们从reducer中读取所有温度的总和
- 我们使用count函数来获取JavaRDD输入集中所有行的计数。
- 我们使用JavaRDD过滤功能来过滤掉温度高于平均值的城镇。
- 我们使用JavaRDD collect函数来打印结果。
如果你运行这个程序,你应该得到如下结果:
16/03/03 21:02:26 INFO DAGScheduler: Job 1 finished: count at AvgTemperatureAnalyzer.java:85, took 0,094561 s
Average temperature 27.0
.
.
Result item: Berlin 20
Result item: Paris 15
Result item: Rome 25
16/03/03 21:02:26 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/metrics/json,null}
结论
从我的观点来看,Apache Spark更加友好的地图减少编程,即使概念是相同的。我打赌你明白我们需要通过JavaRDD输入进行多次迭代,但是使用map-reduce你需要弄清楚如何将前一个map reduce任务的结果传递给下一个,Apache Spark一个输入迭代以新的RDD设置,您可以在其中应用其他功能,从主节点驱动的所有内容......这不是很酷吗?