Spark Core入門1【Spark集羣安裝、高可用、任務執行流程、使用Scala/Java/Lambda編寫Spark WordCount】

一、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]")

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章