Spark学习笔记02:Spark下载与入门
一、Spark下载与入门
1、下载Spark
http://spark.apache.org/downloads.html
2、安装Spark
将安装包解压缩在/home/software目录下:
[root@hadoop spark-2.2.0-bin-hadoop2.7]# pwd
/home/software/spark-2.2.0-bin-hadoop2.7
本章我们所做的一切,Spark 都是在本地模式下运行,也就是非分布式模式,这样我们只需要用到一台机器。Spark 可以运行在许多种模式下,除了本地模式,还支持运行在Mesos 或YARN 上,也可以运行在Spark 发行版自带的独立调度器上。
在etc/profile配置环境变量:
3、Spark中Python和Scala的shell
(1)启动Python版的shell
(2)启动scala版的shell
在日志的输出中注意到了这样一行信息:Spark context Web UI available at http://192.168.159.100:4040。你可以由这个地址访问Spark 用户界面,查看关于任务和集群的各种信息。
4、在Linux上安装ipython
(1)上传到虚拟机hadoop的/home/software目录
(2)解压缩ipython安装包
[root@hadoop software]# tar -zxvf ipython-6.2.1.tar.gz
(3)进入解压缩之后的目录ipython-6.2.1
[root@hadoop software]# cd ipython-6.2.1
(4)执行setup.py脚本,安装ipython
[root@hadoop ipython-6.2.1]# python setup.py install
该操作将会在site-packages目录中安装ipyhon的库文件,并在scripts目录中创建一个ipython脚本。在unix系统中,该目录与python的二进制文件目录相同。如果系统中已经安装了python包,则ipython将会安装在/usr/bin目录下。
(5)启动ipython
5、操作RDD示例
在Spark 中,我们通过对分布式数据集的操作来表达我们的计算意图,这些计算会自动地在集群上并行进行。这样的数据集被称为弹性分布式数据集(resilient distributed dataset),简称RDD。RDD 是Spark 对分布式数据和计算的基本抽象。
任务1:统计文本文件test.txt行数
sc: Spark Context
(1)python版
>>> lines = sc.textFile('test.txt')
>>> lines.count()
3
>>> lines.first()
'hello hadoop hello spark'
(2)scala版
scala> val lines = sc.textFile("test.txt")
lines: org.apache.spark.rdd.RDD[String] = test.txt MapPartitionsRDD[1] at textFile at
scala> lines.count()
res0: Long = 3
scala> lines.first()
res1: String = hello hadoop hello spark
6、Spark核心概念
从上层来看,每个Spark 应用都由一个驱动器程序(driver program)来发起集群上的各种并行操作。驱动器程序包含应用的main 函数,并且定义了集群上的分布式数据集,还对这些分布式数据集应用了相关操作。在前面的例子里,实际的驱动器程序就是Spark shell本身,你只需要输入想要运行的操作就可以了。
驱动器程序通过一个SparkContext对象来访问Spark。这个对象代表对计算集群的一个连接。shell 启动时已经自动创建了一个SparkContext 对象,是一个叫作sc 的变量。
一旦有了SparkContext,你就可以用它来创建RDD,前面调用了sc.textFile() 来创建一个代表文件中各行文本的RDD。我们可以在这些行上进行各种操作,比如count()。要执行这些操作,驱动器程序一般要管理多个执行器(executor)节点。比如,如果我们在集群上运行count() 操作,那么不同的节点会统计文件的不同部分的行数。
任务2:筛选文本文件中满足条件的行。
(1)python版
>>> lines = sc.textFile("test.txt")
>>> scalaLines = lines.filter(lambda line: "scala" in line)
>>> scalaLines.count()
1
>>> scalaLines.first()
'i learn hadoop and scala'
>>> lines = sc.textFile('test.txt')
>>> iLines = lines.filter(lambda line: line.startswith('i'))
>>> iLines.count()
2
>>> iLines.first()
'i love you hadoop and spark'
(2)scala版
scala> val lines = sc.textFile("test.txt")
lines: org.apache.spark.rdd.RDD[String] = test.txt MapPartitionsRDD[3] at textFile at
scala> val scalaLines = lines.filter(line => line.contains("scala"))
scalaLines: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[4] at filter at
scala> scalaLines.count()
res0: Long = 1
scala> scalaLines.first()
res1: String = i learn hadoop and scala
scala> val lines = sc.textFile("test.txt")
lines: org.apache.spark.rdd.RDD[String] = test.txt MapPartitionsRDD[8] at textFile at
scala> val iLines = lines.filter(line => line.charAt(0) == 'i')
iLines: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[9] at filter at
scala> iLines.count()
res9: Long = 2
scala> iLines.first()
res10: String = i love you hadoop and spark
同样的任务,交给Java来做。
import java.util.ArrayList;
import java.util.List;
/**
* Created by howard on 2018/2/1.
*/
public class FilterLinesDemo {
public static void main(String[] args) throws Exception {
List lines = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader("test.txt"));
String nextLine = "";
while ((nextLine = br.readLine()) != null) {
lines.add(nextLine);
}
// 输出包含“scala”的行
System.out.println("输出包含“scala”的行:");
lines.stream().filter(line -> line.contains("scala")).forEach(System.out::println);
// 输出以“i”打头的行
System.out.println("输出以“i”打头的行:");
lines.stream().filter(line -> line.startsWith("i")).forEach(System.out::println);
}
}
大家可以看到,三种语言的lambda表达式的写法有些差异。
任务3:统计文件中单词个数。
(1)python版
>>> lines = sc.textFile('test.txt')
>>> words = lines.flatMap(lambda line: line.split(' '))
>>> maps = words.map(lambda word: (word, 1))
>>> counts = maps.reduceByKey(lambda x, y: x + y)
>>> counts.foreach(print)
('hello', 2)
('hadoop', 3)
('i', 2)
('spark', 2)
('love', 1)
('you', 1)
('scala', 1)
('and', 2)
('learn', 1)
(2)scala版
scala> val lines = sc.textFile("test.txt")
lines: org.apache.spark.rdd.RDD[String] = test.txt MapPartitionsRDD[1] at textFile at
scala> val words = lines.flatMap(_.split(" "))
words: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[2] at flatMap at
scala> val maps = words.map((_, 1))
maps: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[3] at map at
scala> val counts = maps.reduceByKey(_ + _)
counts: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[4] at reduceByKey at
scala> counts.foreach(println)
[Stage 0:> (0 + 0) / 2](spark,2)
(you,1)
(scala,1)
(hadoop,3)
(i,2)
(and,2)
(learn,1)
(love,1)
(hello,2)
二、构建Spark独立应用
1、Java版的单词计数应用
(1)创建Maven项目JavaSparkWordCount
(2)在pom.xml里添加对spark的依赖
4.0.0
net.hw.spark
JavaSparkWordCount
1.0-SNAPSHOT
org.apache.spark
spark-core_2.11
2.2.1
(4)创建输入目录与单词文件
(5)创建WordCount类
package net.hw.spark;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;
import java.io.File;
import java.util.Arrays;
import java.util.Iterator;
/**
* Created by howard on 2018/2/1.
*/
public class WordCount {
public static void main(String[] args) {
String inputPath = "input";
String outputPath = "result";
SparkConf conf = new SparkConf().setMaster("local").setAppName("wordcount");
JavaSparkContext sc = new JavaSparkContext(conf);
// 读取文件
JavaRDD input = sc.textFile(inputPath);
// 切分单词
JavaRDD words = input.flatMap(
new FlatMapFunction() {
public Iterator call(String x) {
return Arrays.asList(x.split(" ")).iterator();
}
});
// 转换成键值对并计数
JavaPairRDD counts = words.mapToPair(new PairFunction() {
@Override
public Tuple2 call(String x) throws Exception {
return new Tuple2<>(x, 1);
}
}).reduceByKey(new Function2() {
@Override
public Integer call(Integer x, Integer y) throws Exception {
return x + y;
}
});
// 输出统计结果
System.out.println(counts.collect());
// 删除输出目录
File dir = new File(outputPath);
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
file.delete();
}
}
dir.delete();
// 将统计结果写入结果文件
counts.saveAsTextFile(outputPath);
}
}
运行结果如下:
采用lambda表达式可以简化代码:
// 切分单词
JavaRDD words = input.flatMap(
x -> Arrays.asList(x.split(" ")).iterator());
// 转换成键值对并计数
JavaPairRDD counts = words.mapToPair(x -> new Tuple2<>(x, 1))
.reduceByKey((x, y) -> x + y);
2、Scala版的单词计数应用
(1)创建Scala项目ScalaSparkWordCount
(2)创建lib目录,将spark的jar包拷贝到该目录
说明:spark-2.2.0自带的scala版本是2.11.8,跟项目配置的scala-sdk版本必须一致,否则程序运行就会报错。
将所有jar包作为库添加到项目:
(3)创建输入目录与单词文件
(4)在src目录里创建log4j.properties
log4j.rootLogger=WARN, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spark.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
(5)创建WordCount对象
package net.hw.spark
import java.io.File
import org.apache.spark.{SparkConf, SparkContext}
/**
* Created by howard on 2018/2/2.
*/
object WordCount {
def main(args: Array[String]): Unit = {
val inputPath = "input"
val outputPath = "result"
val conf = new SparkConf().setMaster("local").setAppName("wordcount")
val sc = new SparkContext(conf)
// 读取文件
val input = sc.textFile(inputPath)
// 切分单词
val words = input.flatMap(_.split(" "))
// 转换成键值对并计数
val counts = words.map((_, 1)).reduceByKey { _ + _ }
// 输出统计结果
counts.foreach(println)
// 删除输出目录
val dir: File = new File(outputPath)
if (dir.exists()) {
for (file <- dir.listFiles()) {
file.delete()
}
}
dir.delete()
// 将统计结果写入结果文件
counts.saveAsTextFile(outputPath)
}
}
运行结果如下:
3、Python版的单词计数应用
(1)将spark安装目录下python里的pyspark目录拷贝到Python安装目录下Lib里的site-packages目录
(2)创建Python项目PythonSparkWordCount
(3)创建输入目录与单词文件
(4)创建word_count.py文件
import os
import shutil
from pyspark import SparkContext
inputpath = 'input'
outputpath = 'result'
sc = SparkContext('local', 'wordcount')
# 读取文件
input = sc.textFile(inputpath)
# 切分单词
words = input.flatMap(lambda line: line.split(' '))
# 转换成键值对并计数
counts = words.map(lambda word: (word, 1)).reduceByKey(lambda x, y: x + y)
# 输出结果
counts.foreach(print)
# 删除输出目录
if os.path.exists(outputpath):
shutil.rmtree(outputpath, True)
# 将统计结果写入结果文件
counts.saveAsTextFile(outputpath)
运行结果如下:
(5)下载并安装py4j
https://pypi.python.org/pypi/py4j/0.10.6
D:\Program Files\py4j-0.10.6>python setup.py install
Installed d:\program files\python\python36\lib\site-packages\py4j-0.10.6-py3.6.egg
Processing dependencies for py4j==0.10.6
Finished processing dependencies for py4j==0.10.6
此时运行程序,结果如下:
(6)配置环境变量SPARK_HOME
此时,运行程序,结果如下:
三、总结
在本章中,我们讲到了下载并在单机的本地模式下运行Spark,以及Spark 的使用方式,包括交互式方式和通过一个独立应用进行调用。另外我们还简单介绍了Spark 编程的核心概念:通过一个驱动器程序创建一个SparkContext 和一系列RDD,然后进行并行操作。