spark-shell交互式工具
- 启动Spark-Shell
./bin/spark-shell
./spark-shell --master
./bin/spark-shell --master local[2] //使用两个线程运行
./bin/spark-shell --master local[2] --jar test.jar //使用两个线程运行指定Jar包
./bin/spark-shell --master local --master spark://spark01:7077 //使用standalone模式
在spark-Shell(命令行)中,已经创建了一个名为sc的SparkContext对象
—master用来设置context将要连接并使用的资源主节点,master的值可以是Standalone模式的Spark集群地址,Mesos或Yarn集群的URL,或者是一个local地址
使用jar可以添加Jar包的路径,使用逗号乐意添加多个包
Spark_Shell的本质是在后台调用了spark-submit脚本来启动应用程序
- Spark-Shell操作
数据收集后,需要对数据进行一系列的处理,包括数据的抽取-转换-装载(Extract-Transform-Load,ETL),数据统计,数据挖掘,以及后续的数据呈现和为决策而提供的数据持久化
//加载HDFS文件和本地文件都是使用textFile(),区别是前缀进行标志(hdfs://或file:///)
从本地读取的文件返回MapPartitionsRDD。从hdfs中读取的文件先转换成HadoopRDD,然后隐式转换为MapPatitionRDD
MapPatitionRDD和HadoopRDD都是基于Spark的弹性分布式数据集RDD
//加载文件
val aa=sc.textFile("File:///home/aa/bb/WCDemo.txt")
或
val aa=sc.textFile("hdfs://spark01:9000/WCDemo.txt")
//包含指定关键字的行数
val result=aa.filter(line=>line.contains("spark"))
result.count
或
val result=aa.filter(line=>line.contains("spark")).count()
//获取有指定关键字的行的全部内容
val result=aa.filter(_.contains("spark")).collect()
//获取RDD文件的第一行
aa.first()
//获取RDD文件的行数
aa.count()
//找出文本中单词个数最多的那行的单词数
//首先将aa的每一行文本使用split进行切分,并统计切分后每行的单词数,然后执行reduce操作,用(a,b)=>if(a>b) a else b 进行比较,返回最大值
aa.map(line=>line.split("\t").size).reduce((a,b)=>if(a>b) a else b)
//词频统计
//结合flatMap,Map和reduceByKey来计算文件中每个单词的词频,并返回(String,Int)类型的键值对shuffleRDD,最后使用collection聚合单词计数结果
val wordCount=aa.flatMap(line=>line.split("\t")).map(word=>(word,1)).reduceByKey((x,y)=>x+y).collect()
//使用占位符(_)当每个参数在函数文本中最多出现一次的时候,可以使用_+_扩展成带两个参数的函数文本,多个下划线指带多个参数,而不是单个参数重复使用(第一个下划线代表第一个参数,第二个下划线代表第二个参数)
val wordCount=aa.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
//Spark默认是不进行排序的,可以使用sortByKey按照Key进行排序,false为降序,true为升序
//map(m=>(m._2,m._1)) 实现了Key和Value互换
val wordCount=aa.flatMap(_.split("\t")).map((_,1)).reduceByKey(_+_).map(m=>(m._1,m._2)).sortByKey(false).map(m=>(m._2,m._1)).collect()
//保存文件
wordCount.saveAsTextFile("hdfs://spark01:9000/out/WCDemoOUT.txt")
- RDD缓存
Spark支持将数据结构存进缓存种,当数据被反复访问时,是非常有用的
result.cache()
result.persist()
result.unpersist()
spark context与部署模式
//创建SparkConf,alt+enter,快速导包
val conf = new SparkConf().setAppName("WCDemo.txt").setMaster("local")
//创建sparkContext对象
val sc = new SparkContext(conf)
//从HDFS中读取数据
val lines=sc.textFile("hdfs://spark01/WCDemo.txt")
//分隔获取每个单词
val words=lines.flatMap(_.split("\t"))
//将每个单词设置1次
val psirs=WCDemo.map(word=>(word,1))
//统计每个单词出现的次数
val wordsCount=pairs.reduceByKey(_+_)
保存结果到HDFS
wordsCount.saveAsTextFile("hdfs://spark01/WCReduce")
输出
result.collect()
//通过foreach算子输出单词与次数
result.foreach(x=>println(x._1+" "+x._2))
- 案例——WordCount
/**
* 用Java开发Spark的WordCount
* @author Administrator
*/
public class WordCount {
public static void main(String[] args) {
//第一步:创建SparkConf对象
//set master()用于设置运行的Master的URL
//如果要是在本地运行,需要设置为local或local[N](N>2)
//如果程序需要打包在集群中运行,就不需要设置Master
SparkConf conf=new SparkConf().setAppName("WordCount").setMaster("local");
//第二步:创建JavaSparkContext对象
// SparkContext,即为Spatj上下文,它包含在Driver驱动程序中
//Spark程序的运行离不开SparkContext
// Scala开发Spark对应的是SparkContext
//Java开发Spark对应的是JavaSparkContext
// 创建SparkContext对象时,需要SparkConf对象作为参数
JavaSparkContext sc = new JavaSparkContext(conf);
//第三步:从HDFS中加载数据,生成JavaRDD<String>
//从hdfs等外部数据源创建程序中的第一个RDD,即为初始RDD
//创建初始RDD有两种方式
//第一种:通过HDFS等外部数据源中创建
//第二种:通过并行集合的方式创建
//val array=Array(1,2,3,4,5)
//val rdd=sc.parallelize(array)
JavaRDD<String> lines = sc.textFile("hdfs://tgmaster:9000/in/resws");
//第四步:分隔单词
//flatMap:flatten map,先map后flatten
//flatMap算子中,通常有一个String类型的参数,同时具有Iterable<T>集合类型的返回值
JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
private static final long serialVersionUID = 1L;
public Iterable<String> call(String line) throws Exception {
return Arrays.asList(line.split(" "));
}
});
//第五步:将分隔后的每个单词出现次数记录为1,形成键值对<单词,1>
//用java开发spark,如果需要通过映射的方式产生键值对,此时要到到mapToPair算子
//scala中只有map算子(没有mapToPair)
//mapToPair:使用映射,并产生键值对
//map:使用映射,不产生键值对
//mapToPair算子中有一个String类型的参数,返回值是Tuple2<String, Integer>
avaPairRDD<String, Integer> pairs = words.mapToPair(new PairFunction<String, String, Integer>() {
private static final long serialVersionUID = 1L;
public Tuple2<String, Integer> call(String word) throws Exception {
return new Tuple2<String, Integer>(word, 1);
}
});
//第六步:通过reduceByKey()算子统计每个单词出现的次数
//reduceByKey算子有两个Integer类型的参数,返回值是Integer
//运行过程是,现在本地按照Key值进行聚合,然后在全局范围内进行聚合
//性能比groupByKey强很多
avaPairRDD<String, Integer> result = pairs.reduceByKey(new Function2<Integer,Integer, Integer>() {
private static final long serialVersionUID = 1L;
public Integer call(Integer num1, Integer num2) throws Exception {
return num1+num2;
}
});
//第七步:通过foreach()算子输出最终结果
result.foreach(new VoidFunction<Tuple2<String,Integer>>() {
private static final long serialVersionUID = 1L;
public void call(Tuple2<String, Integer> info) throws Exception {
System.out.println(info._1+"出现了"+info._2);
}
});
}
}
//IDEA
import org.apache.spark.{SparkConf, SparkContext}
object wordcount {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("asd").setMaster("local")
val sc = new SparkContext(conf)
val lines= sc.textFile("hdfs://spark01:9000/WCDemo.txt")
val words=lines(_.split("\t"))
val pairs=words.map(word=>(word,1))
val wordsCount=pairs.reduceByKey(_+_)
wordsCount.saveAsTextFile("hdfs://spark01:9000/WCout.txt")
}
}
- spark部署模式
Local本地模式
//执行需要用到CPU的两个核
spark-shell --master local[2]
运行与本地
Standalone独立模式
1.spark自带的一种集群模式,自己管理集群资源,只要将hadoop的HDFS启动
2.master节点有master,slave节点有worker
3.启动./bin/spark-shell –master spark://master:7077
Yarn模式
1.spark自己不管理资源,向Yarn申请资源,所以保证Yarn必须启动起来
2.操作步骤
- 启动hadoop:在hadoop目录执行start-all.sh
- 到spark目录,./bin/spark-shell –master yarn-client(yarn-cluster)
- IDEA生成Jar包
1.File——>project Structure,弹出“project Structure”的设置对话框
2.选择左边的Artifacts,点击上方的“+”
3.选择Jar——>from moduls with dependencies
4.选择要启动的类,选择确定
5.应用之后选择菜单“build”——>“build Artifact”,选择build或Rebuild即可生成 - 上传jar包
- IDEA生成Jar包
./spark-submit \
--class Test.wordcount \ //包名.类
--master yarn--cluster \
/home/lyuc/Myspark.jar //地址
- Master URL格式及说明
RDD弹性分布式数据集
- RDD在抽象上来说是一种元素集合,包含了数据,可以被分为多个区,每个分区分布在集群的不同节点上,从而让HDFS的数据可以被操作,
- RDD通常通过Hadoop上的文件,即HDFS或Hive表来进行创建,也可以通过程序中的集合创建
- RDD最重要的特性是,提供容错性,可以自动从节点失败中恢复过来,如果某个节点上的RDD partition,因为节点故障,导致数据丢了,那么RDD会自动通过书籍来源重新计算该partition
- 数据默认放在内存中,在内存不足是,Spark会自动将RDD写入磁盘中
RDD定义
一个RDD包含5个核心属性
- 一个分区表,每个分区是RDD的一部分数据(数据块)
- 一个依赖列表,存储依赖的其他RDD
- 一个名为computer的计算函数,用于计算RDD多各分区的值
- 分区器(可选)用于键值类型的RDD,比如某个RDD是按散列来分区的
5.计算各分区器是优先的位置列表(可选)比如HDFS上的文件生成RDD时,RDD分区的位置优先选择数据所在的节点
创建RDD
- 并行化集合创建RDD
针对程序中的集合调用sparkcontext的parallelize()方法
Spark会将集合中的数据拷贝到集群上去, 形成一个分布式的数据集合, 也就是一个RDD。相当于集合中的一部分数据会到一个节点上, 而另一部分数据会到其他节点上, 然后就可以用并行的方式来操作这个分布式数据集合, 即RDD。
// 并行化集合创建RDD
val arr = Array(1,2,3,4,5)
//没有指定RDD分区,默认微程序所分配的资源的CPU核数
val rdd=sc.parallelize(arr)
val sum=rdd.reduce(_+_)
- 使用本地文件和HDFS创建RDD
spark支持使用任何hadoop支持的存储系统上的文件创建RDD,通过调用SparkContext()的textFile()方法。可以针对本地文件或HDFS文件创建RDD
*spark的textfile()方法致辞针对目录,压缩文件以及通配符进行RDD创建目录
*spark会默认为HDFS文件的每一个block创建一个partition,但是也可以通过textFile()的第二个参数手动设置分区数,只能比block多,不能少
//制定了lines中有两个分区
//设置了分区数只能比block多
val lines=sc.textFile("hdfs路径",2)
val wordCount=rdd.map(line=>line.length).reduce(_+_)
spark的textFile()还有一些特例方法来创建RDD
- SparkContext.wholeTextFile()
针对一个目录中的大量小文件,返回组成的pair,作为PairRDD,不是普通RDD,普通RDD中每个元素就是文件中的一行文本 - SparkContext.sequenceFilek,v
可以针对SequenceFile创建RDD,K和V泛型类型就是SequenceFile的key和value的类型。 K和V要求必须是
Hadoop的序列化类型, 比如IntWritable、 Text等。 - SparkContext.hadoopRDD()
对于Hadoop的自定义输入类型, 可以创建RDD。 该方法接收JobConf、 InputFormatClass、 Key和Value的Class。 - SparkContext.objectFile()
可以针对之前调用RDD.saveAsObjectFile()创建的对象序列化的文件, 反序列化文件中的数据, 并创建一个RDD。
- 通过Transformation(转化)类型的算子产生新的RDD
val result=lines.flatMap(_.split(" ")).map((_.1)).reduceBykey(_+_)
//result.collect,result.foreach(println _)行动类型算子
RDD操作
- 创建操作
-
转换操作(transformation)
在spark中关于transformation类型的算子,系统只是记录下了操作行为,但行为没有执行,当程序遇到一个Action型的算子时,会触发job的提交运行(lazy特性),此时Action之前的transformation类型算子会被执行
-
行动操作(action)
- 控制操作
缓存到内存,也称内存持久化