一、Spark介紹
Spark是一種快速、通用、可擴展的大數據分析引擎,包含SparkSQL、Spark Streaming、GraphX、MLlib等子項目。
Spark是基於內存計算的大數據並行計算框架。Spark基於內存計算,提高了在大數據環境下數據處理的實時性,同時保證了高容錯性和高可伸縮性,允許用戶將Spark部署在大量廉價硬件之上,形成集羣。
Spark的優點:
1、快:與Hadoop的MapReduce相比,Spark基於內存的運算要快100倍以上,基於硬盤的運算也要快10倍以上。Spark實現了高效的DAG(有向無環圖)執行引擎,可以通過基於內存來高效處理數據流。
2、易用:Spark支持Java、Python和Scala的API,還支持超過80種高級算法,使用戶可以快速構建不同的應用。而且Spark支持交互式的Python和Scala的shell,可以非常方便地在這些shell中使用Spark集羣來驗證解決問題的方法。
3、通用:Spark可以用於批處理、交互式查詢(Spark SQL)、實時流處理(Spark Streaming)、機器學習(Spark MLlib)和圖計算(GraphX)。這些不同類型的處理都可以在同一個應用中無縫使用。Spark統一的解決方案非常具有吸引力,畢竟任何公司都想用統一的平臺去處理遇到的問題,減少開發和維護的人力成本和部署平臺的物力成本。
4、Spark可以非常方便地與其他的開源產品進行融合。比如,Spark可以使用Hadoop的YARN和Apache Mesos作爲它的資源管理和調度器,並且可以處理所有Hadoop支持的數據,包括HDFS、HBase和Cassandra等。這對於已經部署Hadoop集羣的用戶特別重要,因爲不需要做任何數據遷移就可以使用Spark的強大處理能力。Spark也可以不依賴於第三方的資源管理和調度器,它實現了Standalone作爲其內置的資源管理和調度框架,這樣進一步降低了Spark的使用門檻,使得所有人都可以非常容易地部署和使用Spark。此外,Spark還提供了在EC2上部署Standalone的Spark集羣的工具。
二、Spark集羣安裝
2.1 下載spark
(1)從spark官方下載spark安裝包
(2)上傳spark安裝包到Linux上
(3)解壓安裝包到指定位置
tar -zxvf spark-2.3.3-bin-hadoop2.7.tgz -C /root/apps/spark
2.2 配置spark
spark配置文件都在spark/conf下
進入到spark安裝目錄
cd /root/apps/spark
進入conf目錄並重命名並修改spark-env.sh.template文件
cd conf/
mv spark-env.sh.template spark-env.sh
vi spark-env.sh
在該配置文件中添加如下配置
export JAVA_HOME=/usr/local/jdk1.8
export SPARK_MASTER_IP=hdp-01
export SPARK_MASTER_PORT=7077
保存退出
重命名並修改slaves.template文件
mv slaves.template slaves
vi slaves
在該文件中添加子節點所在的位置(Worker節點,指定哪些機器需要作爲從節點啓動)
hdp-02
hdp-03
保存退出
將配置好的Spark拷貝到其他節點上
將spark拷貝到其他機器上hdp-02 、hdp-03的/root/apps目錄下
for i in {2,3}; do scp -r /root/apps/spark/ hdp-0$i:/root/apps; done
Spark集羣配置完畢,目前是1個Master,2個Worker,在hdp-01啓動spark集羣
/root/apps/spark/sbin/start-all.sh
啓動後執行jps命令,主節點(hdp-01)上有Master進程,其他子節點(hdp-02、hdp-03)上有Worker進行。
登錄Spark管理界面查看集羣狀態(主節點):http://hdp-01:8080/ 【檢驗】 注意7077是rpc通信端口,內部是Netty
到此爲止,Spark集羣安裝完畢,但是有一個很大的問題,那就是Master節點存在單點故障,要解決此問題,就要藉助zookeeper,並且啓動至少兩個Master節點來實現高可靠,配置方式比較簡單:
Spark集羣規劃:hdp-01,hdp-04是Master;hdp-02、hdp-03是Worker
安裝配置zk集羣,並啓動zk集羣
停止spark所有服務,修改配置文件spark-env.sh,在該配置文件中刪掉SPARK_MASTER_IP
並添加如下配置
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=hdp-01:2181,hdp-02:2181,hdp-03:2181 -Dspark.deploy.zookeeper.dir=/spark"
#除此之外還可以修改Worker的核數(線程數,不能超過實際物理機器的線程)、內存大小等配置
#配置文件上有示例,直接抄即可
export SPARK_WORKER_CORES=8
export SPARK_WORKER_MEMORY=2g
1.在hdp-01節點上修改slaves配置文件內容指定worker節點
2.在hdp-01上執行sbin/start-all.sh腳本,後在hdp-04上執行sbin/start-master.sh啓動第二個Master【意味着只在hdp-04啓動一個Master】如果連接http://hdo-04:8080,會發現Status顯示STANDBY狀態,且沒有Workers信息。
在Spark集羣啓動的時候,所有的Master和Worker都連接到Zookeeper集羣中。zk的作用如下:
1、zk集羣會選舉出一個Master作爲活躍(alive)的Master,另外一個Master處於Stand By狀態。
2、zk集羣還會保存活躍的Master信息
3、zk集羣還會保存所有Worker的資源信息和資源使用情況,如圖中hdp-01作爲活躍的Master,它能獲取所有的Worker(hdp-02、hdp-03)的使用情況,如果hdp-01掛掉,那麼會切換爲hdp-04作爲活躍的Master,它也應該能獲取獲取所有的Worker信息,那麼Worker的資源信息和資源使用情況就應該保存在zk中。【爲了故障切換】
2.3 總結:
1、先啓動zk集羣
2、啓動spark集羣,但只會啓動一個Master,另外一臺Master機器需要手動啓動
3、如果模擬hdp-01故障,那麼hdp-04會由STANDBY狀態切換爲MASTER狀態。當hdp-01修復後,hdp-01爲STANDBY狀態,hdp-04仍爲MASTER狀態。在故障切換的過程中,會短暫性終止spark服務。
三、執行Spark程序
3.1 入門案例——蒙特卡羅算法求Pi
實際上是通過數學採樣的方式計算Pi,採樣的次數越多,計算的Pi值越準確。
/root/apps/spark-2.3.3-bin-hadoop2.7/bin/spark-submit \
--master spark://hdp-01:7077,spark://hdp-02:7077 \
--class org.apache.spark.examples.SparkPi \
--executor-memory 2048mb \
--total-executor-cores 24 \
/root/apps/spark-2.3.3-bin-hadoop2.7/examples/jars/spark-examples_2.11-2.3.3.jar \
10000
/**
解析:
第一行是指通過spark提交任務的客戶端spark-submit
第二行是指定master所在的機器 底層是rpc通信協議 spark://主機名或ip地址:7077 7077是rpc通信端口,而8080是http外部訪問端口,需要區分開來。提交任務可以指定多個master地址,目的是爲了提交任務高可用
第三行是指執行哪一個類 全路徑類名,官方自帶的蒙特卡羅求Pi樣例(底層是通過反射執行)
第四、五行是指執行的內存大小,cpu核數(實際上這裏的核數是執行的線程數)
第六行是指該樣例所在的jar包位置 2.11爲scala版本 2.3.3爲spark版本
第六行是指採樣的次數,採樣次數越多,求Pi越精確
*/
最終求的:Pi is roughly 3.141852462837049 採樣次數可以設置更高試試
此時登錄http://hdp-01:8080中,即spark後臺管理界面,查看到新增了一個已完成任務。
Completed Applications
Application ID | Name | Cores | Memory per Executor | Submitted Time | User | State | Duration |
---|---|---|---|---|---|---|---|
app-20190427200200-0004 | Spark Pi | 16 | 2.0 GB | 2019/04/27 20:02:00 | root | FINISHED | 2.8 min |
在執行過程中,有一些細節需要說一下:
假設我現在的集羣架構是這樣:
hdp-01爲Master(alive)、hdp-02也爲Master(stand by)
hdp-03、hdp-04、hdp-05爲Worker , 假設我在機器hdp-05中提交了蒙特卡羅求Pi任務
在執行任務的過程中,給集羣中的所有機器輸入jps,查看後臺java任務都有哪些?
(1)在hdp-05中,存在CoarseGrainedExecutorBackend(執行任務真正執行的地方)、SparkSubmit(提交任務到Spark集羣,和Master通信、調度任務等功能)、Worker等。
(2)在hdp-03、hdp-04【即Worker機器】中都多了CoarseGrainedExecutorBackend進程,但無SparkSubmit進程。
(3)在任務執行完成後再jps,發現SparkSubmit和CoarseGrainedExecutorBackend都消失了,原因是被釋放了,節約資源。
總結:CoarseGrainedExecutorBackend(簡稱Executor)在Worker執行任務時候啓動進程,SparkSubmit在提交任務的機器執行進程,在任務執行完畢後,Executor和SparkSubmit都被釋放。
3.2 Spark shell
spark-shell是Spark自帶的交互式Shell程序,方便用戶進行交互式編程,用戶可以在該命令行下用scala編寫spark程序。
上面的方式沒有指定master的地址,即用的是spark的local模式運行【模擬spark集羣運行的過程】
/root/apps/spark-2.3.3-bin-hadoop2.7/bin/spark-shell
只有書寫master地址,才能與master建立連接,才能向master申請資源,才能將任務提交到集羣
/root/apps/spark-2.3.3-bin-hadoop2.7/bin/spark-shell \
--master spark://hdp-01:7077 \
--executor-memory 2g \
--total-executor-cores 2
參數說明:
--master spark://hdp-01:7077 指定Master的地址,如果需要指定多個Master地址,只需要使用逗號分割即可
--executor-memory 2g 指定每個worker可用內存爲2G,如果不指定內存,默認運行內存1024mb
--total-executor-cores 2 指定整個集羣使用的cup核數爲2個
在spark-shell運行後,執行jps命令,發現提交任務的機器存在CoarseGrainedExecutorBackend和SparkSubmit,而其他worker寄去存在CoarseGrainedExecutorBackend,Master機器的進程和執行spark-shell之前沒有明顯變化。說明spark-shell在執行後,即使任務未提交到spark集羣中,進程也依舊在後臺保持執行。【實際上就是創建SparkContext】
指定了Master地址,那麼就會將任務提交到集羣中,開始時sparksubmit(客戶端)要連接Master,並向Master申請計算資源(內存和核數等),Master進行資源調度(就是讓哪些Worker啓動Executor)。在準備工作時,這些進程都準備好了【實際上該過程底層就是創建SparkContext的過程】
注意:
如果啓動spark shell時沒有指定master地址,但是也可以正常啓動spark shell和執行spark shell中的程序,其實是啓動了spark的local模式,該模式僅在本機啓動一個進程,沒有與集羣建立聯繫。
Spark Shell中已經默認將SparkContext類初始化爲對象sc。用戶代碼如果需要用到,則直接應用sc即可
WordCount代碼:【本地文件系統】
scala> sc.textFile("/root/w.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
注意:需要具備的條件是:所有Worker機器上都需要有/root/w.txt,否則將會報錯。真正執行計算的不是Master,也不是Worker,而是進程CoarseGrainedExecutorBackend。上述的方式是從本地文件系統讀取數據的WordCount計算,真實環境應該是基於HDFS分佈式文件系統讀取文件。Spark先與namenode通信,找到數據存在哪些datanode中,最後從具體的datanode中讀取數據。如果當前的機器或者集羣的其他機器,其本地文件系統沒有數據文件也沒關係,基於HDFS分佈式文件系統,集羣上的每個節點都可以通過網絡從HDFS中讀取數據進行計算。
WordCount代碼:【HDFS分佈式文件系統】
scala> sc.textFile("hdfs://hdp-01:9000/wordcount").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
res1: Array[(String, Int)] = Array((scala,1), (hello,3), (java,1), (spark,2), (hi,2), (dianxin,2))
排序:
scala> sc.textFile("hdfs://hdp-01:9000/wordcount").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).sortBy(_._2).collect
res2: Array[(String, Int)] = Array((scala,1), (java,1), (spark,2), (hi,2), (dianxin,2), (hello,3))
scala> sc.textFile("hdfs://hdp-01:9000/wordcount").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).sortBy(_._2,false).collect
res3: Array[(String, Int)] = Array((hello,3), (spark,2), (hi,2), (dianxin,2), (scala,1), (java,1))
四、Scala和Java執行WordCount對比
4.1 Scala執行WordCount
1、導入pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itcats</groupId>
<artifactId>spark-wordcount</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<scala.version>2.11.8</scala.version>
<spark.version>2.2.0</spark.version>
<hadoop.version>2.6.5</hadoop.version>
<encoding>UTF-8</encoding>
</properties>
<dependencies>
<!-- 導入scala的依賴 -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<!-- 導入spark的依賴 -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<!-- 指定hadoop-client API的版本 -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<!-- 編譯scala的插件 -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<!-- 編譯java的插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 打jar插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2、WordCount Scala代碼
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object ScalaWordCount {
def main(args: Array[String]): Unit = {
//1.創建SparkConfig配置對象,配置Spark應用程序的名字
val conf: SparkConf = new SparkConf()
conf.setAppName("scalaWordCount")
//2.創建Spark執行入口————SparkContext Driver和Master通信就是通過SparkContext進行通信
val sc = new SparkContext(conf)
//3.指定以後從哪讀取數據創建RDD(彈性分佈式數據集)
val lines: RDD[String] = sc.textFile(args(0)) //返回的結果是讀取的一行行文件數據集
//4.切分壓平
val words: RDD[String] = lines.flatMap(_.split(" "))
//5.將單詞和1組合在一起變成元組
val wordWithOne: RDD[(String, Int)] = words.map((_,1))
//6.按照key進行聚合
val reduced: RDD[(String, Int)] = wordWithOne.reduceByKey(_ + _)
//7.排序
val sortReduced = reduced.sortBy(_._2, false) //_爲元組(key,出現次數),按出現次數降序排列
//8.將結果存入HDFS中
sortReduced.saveAsTextFile(args(1))
//9.釋放資源sc
sc.stop()
}
}
3、使用Maven命令打包
4、上傳至服務器且確保HDFS處於運行狀態,執行命令
[root@hdp-01 bin]# ./spark-submit --master spark://hdp-01:7077 --class cn.itcats.spark.ScalaWordCount /root/spark-wordcount-1.0-SNAPSHOT.jar hdfs://hdp-01:9000/wordcount hdfs://hdp-01:9000/wordcount_res
需要注意的是:args(1),即結果存入HDFS中的文件路徑不應該爲HDFS中已存在的路徑,否則將會拋出異常
Exception in thread "main" org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://hdp-01:9000/wordcount already exists
5、查看執行結果
[root@hdp-01 bin]# hadoop fs -ls /wordcount_res
Found 3 items
-rw-r--r-- 3 root supergroup 0 2019-04-28 21:42 /wordcount_res/_SUCCESS
-rw-r--r-- 3 root supergroup 10 2019-04-28 21:42 /wordcount_res/part-00000
-rw-r--r-- 3 root supergroup 48 2019-04-28 21:42 /wordcount_res/part-00001
實際上Spark讀寫HDFS中的數據是基於Hadoop中的HDFSClient,即基於HDFS的API讀取數據。
6、數據結果實際上被寫入多個文件中,全局有序
[root@hdp-01 bin]# hadoop fs -cat /wordcount_res/part-00000
(hello,3)
[root@hdp-01 bin]# hadoop fs -cat /wordcount_res/part-00001
(spark,2)
(hi,2)
(dianxin,2)
(scala,1)
(java,1)
在MapRecue中,有多少個ReduceTask決定了有多少個結果文件,可以通過指定ReduceTask數量來決定最後結果文件的數量。在我們上文在寫Spark程序的時候我並沒有指定以後生成多少個結果文件?那麼爲什麼最終是三個結果文件呢?
4.2 Java執行WordCount
1、導入pom.xml依賴,可以直接使用4.1中的pom依賴文件
2、WordCount Java代碼
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.util.Arrays;
import java.util.Iterator;
public class JavaWordCount {
public static void main(String[] args) {
//1.創建SparkContext對象
SparkConf sparkConf = new SparkConf().setAppName("javaWordCount");
JavaSparkContext sc = new JavaSparkContext(sparkConf);
//2.指定以後從哪讀數據
JavaRDD<String> lines = sc.textFile(args[0]);
//3.讀取的數據爲一行行的RDD數據集 切分壓平 輸入爲String類型 輸出也爲String類型
JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
@Override
public Iterator<String> call(String lines) throws Exception {
//lines.split(" ")返回類型爲數組類型,需要返回Iterator類型
return Arrays.asList(lines.split(" ")).iterator();
}
});
//4.將words組裝爲元組類型 傳入String的words 返回元組 需要調用mapToPair
JavaPairRDD<String, Integer> wordWithOne = words.mapToPair(new PairFunction<String, String, Integer>() {
@Override
public Tuple2<String, Integer> call(String word) throws Exception {
return new Tuple2<String, Integer>(word, 1);
}
});
//5.將key相同的元素聚合在一起
JavaPairRDD<String, Integer> reduced = wordWithOne.reduceByKey(new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer v1, Integer v2) throws Exception {
return v1 + v2;
}
});
//6.對結果進行排序 發現只有sortByKey 所以應該將Tuple中的鍵值對換位置,調用mapToPair方法
JavaPairRDD<Integer, String> swaped = reduced.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
@Override
public Tuple2<Integer, String> call(Tuple2<String, Integer> tuple) throws Exception {
//return new Tuple2<Integer, String>(tuple._2, tuple._1);
return tuple.swap();
}
});
//排序後的結果 (次數, Key)
JavaPairRDD<Integer, String> sorted = swaped.sortByKey(false);
//再換回 (Key, 次數的順序)
JavaPairRDD<String, Integer> res = sorted.mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
@Override
public Tuple2<String, Integer> call(Tuple2<Integer, String> tuple2) throws Exception {
return tuple2.swap();
}
});
//7.將結果保存到HDFS中
res.saveAsTextFile(args[1]);
//8.關閉sparkContext資源
sc.stop();
}
}
3、使用Maven命令打包
4、上傳至服務器且確保HDFS處於運行狀態,執行命令,同4.1中的操作。需要注意的是修改主函數全包名引用
[root@hdp-01 bin]# ./spark-submit --master spark://hdp-01:7077 --class cn.itcats.spark.JavaWordCount /root/spark-wordcount-1.0-SNAPSHOT.jar hdfs://hdp-01:9000/wordcount hdfs://hdp-01:9000/wordcount_res
5、查看執行結果
[root@hdp-01 bin]# hadoop fs -ls /wordcount_res
Found 3 items
-rw-r--r-- 3 root supergroup 0 2019-04-28 21:42 /wordcount_res/_SUCCESS
-rw-r--r-- 3 root supergroup 10 2019-04-28 21:42 /wordcount_res/part-00000
-rw-r--r-- 3 root supergroup 48 2019-04-28 21:42 /wordcount_res/part-00001
實際上Spark讀寫HDFS中的數據是基於Hadoop中的HDFSClient,即基於HDFS的API讀取數據。
6、數據結果實際上被寫入多個文件中,全局有序
[root@hdp-01 bin]# hadoop fs -cat /wordcount_res/part-00000
(hello,3)
[root@hdp-01 bin]# hadoop fs -cat /wordcount_res/part-00001
(spark,2)
(hi,2)
(dianxin,2)
(scala,1)
(java,1)
4.2 Lambda表達式執行WordCount
編寫Lambda表達式代碼
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 scala.Tuple2;
import java.util.Arrays;
public class LambdaWordCount {
public static void main(String[] args) {
//1.創建SparkContext對象
SparkConf sparkConf = new SparkConf().setAppName("lambdaWordCount");
JavaSparkContext sc = new JavaSparkContext(sparkConf);
//2.指定以後從哪讀數據
JavaRDD<String> lines = sc.textFile(args[0]);
//3.讀取的數據爲一行行的RDD數據集 切分壓平
JavaRDD<String> words = lines.flatMap(x -> Arrays.asList(x.split(" ")).iterator());
//4.將words組裝爲元組類型 w爲words中的每個單詞
JavaPairRDD<String, Integer> wordWithOne = words.mapToPair(x -> new Tuple2<String, Integer>(x, 1));
//5.根據Key進行聚合
JavaPairRDD<String, Integer> reduced = wordWithOne.reduceByKey((m, n) -> m + n);
//6.調整順序 (次數,Key)
JavaPairRDD<Integer, String> swaped1 = reduced.mapToPair(x -> x.swap());
//7.排序
JavaPairRDD<Integer, String> sorted = swaped1.sortByKey(false);
//7.調整順序 (Key,次數)
JavaPairRDD<Integer, String> swaped2 = reduced.mapToPair(x -> x.swap());
//8.將結果保存到HDFS中
swaped2.saveAsTextFile(args[1]);
//9.關閉資源
sc.stop();
}
}
4.3 本地調試代碼
代碼上只有一行改動:
//1.創建SparkConfig配置對象,配置Spark應用程序的名字
//2.local爲本地單線程執行 local[4]爲本地4線程執行 local[*]本地多少線程就多少線程執行
val conf: SparkConf = new SparkConf().setAppName("sparkWordCount").setMaster("local[4]")