最近公司要开发一个spark项目,学习下spark使用,由于公司原因必须使用java,以下代码全部基于java实现。
spark基础
- 基于内存实现,效率高于hadoop,内存不足的时候也会将中间结果写入磁盘,效率会降低。
- 操作容易,hadoop只提供了map和reduce两个操作,对于某些复杂任务,会写很多map和reduce,操作非常复杂,而且由于map阶段完全完成后才会进行reduce,效率会降低。而spark基于rdd实现,提供了更为丰富的操作,使用者可以借助这些操作更轻松的完成计算任务。
- 操作分为转换操作和行动操作,转化操作为懒执行,记录操作路径,在行动操作的时候执行,更方便spark做优化,中间结果存储。
- 基于hdfs实现,数据持久化存储基于hdfs,内存不足的时候也会借助磁盘完成计算。
spark惰性求值
前面提过,RDD 的转化操作都是惰性求值的。这意味着在被调用行动操作之前 Spark 不会 开始计算。这对新用户来说可能与直觉有些相违背之处,但是对于那些使用过诸如 Haskell 等函数式语言或者类似 LINQ 这样的数据处理框架的人来说,会有些似曾相识。
惰性求值意味着当我们对 RDD 调用转化操作(例如调用 map())时,操作不会立即执行。 相反,Spark 会在内部记录下所要求执行的操作的相关信息。我们不应该把 RDD 看作存 放着特定数据的数据集,而最好把每个 RDD 当作我们通过转化操作构建出来的、记录如 何计算数据的指令列表。把数据读取到 RDD 的操作也同样是惰性的。因此,当我们调用 sc.textFile() 时,数据并没有读取进来,而是在必要时才会读取。和转化操作一样的是, 读取数据的操作也有可能会多次执行。
这意味着,对开发者来说,执行的转化操作可以认为已经执行了,不必关心细节,可以用更小更细的操作来完成任务,更方便代码组织。对底层来说,在行动操作的时候,才会执行前面的所有转化操作,将计算聚合到一起,减少中间数据转存操作,也更方便做优化。
spark单词计数
import org.apache.spark.SparkConf;
import org.apache.spark.SparkContext;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import scala.Tuple2;
/**
* Created by huanhuanjin on 2017/9/6.
*/
public class SparkTest {
private static final Logger logger = LoggerFactory.getLogger(SparkTest.class);
public static void main(String[] args) {
SparkConf conf = new SparkConf();
SparkContext spark = new SparkContext(conf);
JavaSparkContext sc = new JavaSparkContext(spark);
List<String> list = new ArrayList<String>();
list.add("apple");
list.add("orange");
list.add("banana");
list.add("apple");
list.add("orange");
list.add("apple");
list.add("cherry");
JavaRDD<String> nums = sc.parallelize(list);
JavaPairRDD<String, Integer> pairs = nums.mapToPair(
new PairFunction<String, String, Integer>() {
public Tuple2<String, Integer> call(String word) throws Exception {
return new Tuple2<String, Integer>(word, 1);
}
}
);
JavaPairRDD<String, Integer> words = pairs.reduceByKey(
new Function2<Integer, Integer, Integer>() {
public Integer call(Integer integer, Integer integer2) throws Exception {
return integer + integer2;
}
}
);
List<Tuple2<String, Integer>> tuple2List = words.collect();
for (Tuple2<String, Integer> tuple2 : tuple2List) {
System.out.println(tuple2._1() + " : " + tuple2._2());
}
sc.stop();
}
}
spark排序实现
import org.apache.spark.SparkConf;
import org.apache.spark.SparkContext;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.function.PairFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import scala.Tuple2;
/**
* Created by huanhuanjin on 2017/9/6.
*/
public class SparkTest {
private static final Logger logger = LoggerFactory.getLogger(SparkTest.class);
public static void main(String[] args) {
SparkConf conf = new SparkConf();
SparkContext spark = new SparkContext(conf);
JavaSparkContext sc = new JavaSparkContext(spark);
List<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(6);
list.add(4);
list.add(1);
list.add(7);
list.add(5);
list.add(2);
//声明RDD
JavaRDD<Integer> nums = sc.parallelize(list);
//转为为PairRDD
JavaPairRDD<Integer, Integer> pairs = nums.mapToPair(
new PairFunction<Integer, Integer, Integer>() {
public Tuple2<Integer, Integer> call(Integer integer) throws Exception {
return new Tuple2<Integer, Integer>(integer, integer);
}
}
);
pairs = pairs.sortByKey();
List<Tuple2<Integer, Integer>> tuple2List = pairs.collect();
for (Tuple2<Integer, Integer> tuple2 : tuple2List) {
System.out.println(tuple2._1() + " : " + tuple2._2());
}
sc.stop();
}
}