0 、什么是spark
Apache Spark™是用于大规模数据处理的统一分析引擎。
它可以高效的支撑更多计算模式,包括交互式查询和流处理。
spark的一个主要特点是能够在内存中进行计算,及时依赖磁盘进行复杂的运算,Spark依然比MapReduce更加高效。
1、 初始化 Spark
Spark 程序必须做的第一件事情是创建一个 SparkContext 对象,它会告诉 Spark 如何访问集群。要创建一个 SparkContext,首先需要构建一个包含应用程序的信息的 SparkConf 对象。
每一个 JVM 只能激活一个 SparkContext 对象。在创新一个新的对象之前,必须调用 stop() 该方法停止活跃的 SparkContext。
SparkConf sparkConf = new SparkConf().setAppName(sparkName);
//这个 appName 参数是一个在集群 UI 上展示应用程序的名称。
JavaSparkContext sparkContext = new JavaSparkContext(sparkConf);
//创建一个java类型的SparkContext 对象
SparkSession sparkSession = SparkSession.builder().appName(sparkName).enableHiveSupport().getOrCreate();
//enableHiveSupport指Hive支持,包括与持久性Hive Metastore的连接,对Hive serdes的支持以及Hive用户定义的功能。
1.1 、Spark与JavaRdd转换
Dataset<Row> rowsPgm = sparkSession.sql(sqlstr);
//sqlstr为在hive中使用的SQL语句,与普通sql相似
2、JavaRdd相关
2.1 transform
map(func):对调用map的RDD数据集中的每个element都使用func,然后返回一个新的RDD,这个返回的数据集是分布式的数据集
filter(func) : 对调用filter的RDD数据集中的每个元素都使用func,然后返回一个包含使func为true的元素构成的RDD
flatMap(func):和map差不多,但是flatMap生成的是多个结果
mapPartitions(func):和map很像,但是map是每个element,而mapPartitions是每个partition
mapPartitionsWithSplit(func):和mapPartitions很像,但是func作用的是其中一个split上,所以func中应该有index
sample(withReplacement,faction,seed):抽样
union(otherDataset):返回一个新的dataset,包含源dataset和给定dataset的元素的集合
distinct([numTasks]):返回一个新的dataset,这个dataset含有的是源dataset中的distinct的element,即经过去重处理的dataset
groupByKey(numTasks):返回(K,Seq[V]),也就是Hadoop中reduce函数接受的key-valuelist
reduceByKey(func,[numTasks]):对元素为KV对的RDD中Key相同的元素的Value进行reduce,因此,Key相同的多个元素的值被reduce为一个值,然后与原RDD中的Key组成一个新的KV对
sortByKey([ascending],[numTasks]):按照key来进行排序,是升序还是降序,ascending是boolean类型
mapToPair(PairFunction<T,K2,V2> f):返回JavaPairRDD<K2,V2> ,此函数会对一个RDD中的每个元素调用f函数,其中原来RDD中的每一个元素都是T类型的,调用f函数后会进行一定的操作把每个元素都转换成一个<K2,V2>类型的对象
flatMapToPair(PairFlatMapFunction<T,K2,V2> f):此函数对对一个RDD中的每个元素(每个元素都是T类型的)调用f函数,通过f函数可以将每个元素转换为<K2,V2>类型的元素,然后比mapToPair方法多了一个flat操作,将所有的< K2,V2>类型的元素合并成为一个Iterable<Tuple2<K2, V2>>类型的对象。
2.2 action
reduce(func):说白了就是聚集,但是传入的函数是两个参数输入返回一个值,这个函数必须是满足交换律和结合律的
collect():一般在filter或者足够小的结果的时候,再用collect封装返回一个数组
count():返回的是dataset中的element的个数
first():返回的是dataset中的第一个元素
take(n):返回前n个elements
takeSample(withReplacement,num,seed):抽样返回一个dataset中的num个元素,随机种子seed
saveAsTextFile(path):把dataset写到一个text file中,或者hdfs,或者hdfs支持的文件系统中,spark把每条记录都转换为一行记录,然后写到file中
saveAsSequenceFile(path):只能用在key-value对上,然后生成SequenceFile写到本地或者hadoop文件系统
countByKey():返回的是key对应的个数的一个map,作用于一个RDD
foreach(func):对dataset中的每个元素都使用func
//DateSet的javaRDD(),将一个dateSet对象转化为一个JavaRdd对象
//map方法,将一个javaRdd对象通过逐条对应创建一个新的Rdd对象
JavaRDD<Record> recordRDD = rowsPgm.javaRDD().map(new Function<Row, Record>() {
@Override
public Record call(Row row) throws Exception {
Record record = new Record();
//row的getAs方法通过row的fieldName值寻找相应value,也可给定顺序取值
record.setChannelId(row.getAs("channel_id"));
record.setChannelName(row.getAs("channel_name"));
record.setPlayTime(row.getAs("play_time"));
···
//row的getXX类型方法,均为取得元素顺序序列位置元素
record.setBeginTime(null==row.getTimestamp(9)?null:row.getTimestamp(9).getTime());
return record;
}
});
//filter方法,将一个javaRdd的每个元素通过过滤,返回一个符合所有过滤条件的Rdd对象
JavaRDD<Record> filterRddPgm = recordRDDPgm.filter(new Function<Record, Boolean>() {
@Override
public Boolean call(Record record) throws Exception {
if (record.getPlayTime() < 60L) { //过滤观看时间小于一分钟
return false;
}
if (record.getPlayTime() > 6 * 3600) { //过滤观看时间大于六个小时
return false;
}
return true;
}
});
//lamda表达式形式将原RDD数据转为一个Tuple2对象
JavaPairRDD<String, Integer> resultRDD;
resultRDD = fromRDD.mapToPair(record -> {
String id = record.getId();
String targetName = record.getChannelId() + "_" + id;
return new Tuple2<>(targetName, 1);
});
//正常形式将原RDD数据转为一个Tuple2对象
settopChannelRDD.mapToPair(new PairFunction<Record, String, Integer>() {
@Override
public Tuple2<String, Integer> call(Record record) throws Exception {
String id = record.getId();
String targetName = record.getChannelId() + "_" +id;
return new Tuple2<>(targetName, 1);
}
});
//reduceByKey
resultRDD.reduceByKey(new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer integer, Integer integer2) throws Exception {
return integer+integer2;
//将相同key的元素value相加
}
});
//lambda表达式形式
resultRDD.reduceByKey((x, y) -> x + y).cache();
//cache方法:使用默认存储级别(MEMORY_ONLY)保留此RDD。对多次使用的RDD进行持久化。