一、spark核心概念-入門篇

image.png

前言

本節(jié)科目主要做spark的相關入門知識

1.1、spark是什么?(what?)

spark是一個快速而通用的集群計算平臺,擴展了MapReduce的計算模型,能夠高效的支持更多計算模式,包含交互式查詢和流處理。在spark核心數據處理引擎之上,有用于SQL,流處理,機器學習,圖形計算等的庫(如下圖)。并且spark支持很多語言,包含Java,Python,Scala等(Scala更適配哦,spark本身由scala開發(fā))。

image.png

1.2、為什么使用spark(why)?

1.2.1、haddop生態(tài)系統(tǒng)臃腫

現階段hadoop生態(tài)系統(tǒng)存在的問題

  • 離線計算:MapReduce
  • hive:歷史數據分析
  • hbase:實時數據查詢
  • storm:流處理
    這就導致維護成本和學習成本很高。而spark彌補了這些。
  • spark streaming:流式計算
  • spark sql:即時查詢
  • MLib:機器學習
  • Graphx:圖處理
1.2.2、效率高

spark基于內存開發(fā)。

1.3、什么時候使用spark(when)?

  • 需要多次操作特定集合:基于內存計算的原理
  • 粗粒度更新狀態(tài)

1.4、怎么使用spark(how)?

我們通過一個簡單的wordCount的demo看下。

public class WordCount {
    public static void main(String[] args) {
        // 編寫Spark應用程序
        // 本地執(zhí)行,是可以執(zhí)行在eclipse中的main方法中,執(zhí)行的

        // 第一步:創(chuàng)建SparkConf對象,設置Spark應用的配置信息
        // 使用setMaster()可以設置Spark應用程序要連接的Spark集群的master節(jié)點的url
        // 但是如果設置為local則代表,在本地運行
        SparkConf conf = new SparkConf()
                .setAppName("WordCountLocal")
                .setMaster("local");

        // 第二步:創(chuàng)建JavaSparkContext對象
        // 在Spark中,SparkContext是Spark所有功能的一個入口,你無論是用java、scala,甚至是python編寫
        // 都必須要有一個SparkContext,它的主要作用,包括初始化Spark應用程序所需的一些核心組件,包括
        // 調度器(DAGSchedule、TaskScheduler),還會去到Spark Master節(jié)點上進行注冊,等等
        // 一句話,SparkContext,是Spark應用中,可以說是最最重要的一個對象
        // 但是呢,在Spark中,編寫不同類型的Spark應用程序,使用的SparkContext是不同的,如果使用scala,
        // 使用的就是原生的SparkContext對象
        // 但是如果使用Java,那么就是JavaSparkContext對象
        // 如果是開發(fā)Spark SQL程序,那么就是SQLContext、HiveContext
        // 如果是開發(fā)Spark Streaming程序,那么就是它獨有的SparkContext
        // 以此類推

        JavaSparkContext sc = new JavaSparkContext(conf);

        // 第三步:要針對輸入源(hdfs文件、本地文件,等等),創(chuàng)建一個初始的RDD
        // 輸入源中的數據會打散,分配到RDD的每個partition中,從而形成一個初始的分布式的數據集
        // 我們這里呢,因為是本地測試,所以呢,就是針對本地文件
        // SparkContext中,用于根據文件類型的輸入源創(chuàng)建RDD的方法,叫做textFile()方法
        // 在Java中,創(chuàng)建的普通RDD,都叫做JavaRDD
        // 在這里呢,RDD中,有元素這種概念,如果是hdfs或者本地文件呢,創(chuàng)建的RDD,每一個元素就相當于
        // 是文件里的一行

        JavaRDD<String> lines = sc.textFile("/Users/sunliangliang/Documents/personal/csv/000002.csv");

        // 第四步:對初始RDD進行transformation操作,也就是一些計算操作
        // 通常操作會通過創(chuàng)建function,并配合RDD的map、flatMap等算子來執(zhí)行
        // function,通常,如果比較簡單,則創(chuàng)建指定Function的匿名內部類
        // 但是如果function比較復雜,則會單獨創(chuàng)建一個類,作為實現這個function接口的類

        // 先將每一行拆分成單個的單詞
        // FlatMapFunction,有兩個泛型參數,分別代表了輸入和輸出類型
        // 我們這里呢,輸入肯定是String,因為是一行一行的文本,輸出,其實也是String,因為是每一行的文本
        // 這里先簡要介紹flatMap算子的作用,其實就是,將RDD的一個元素,給拆分成一個或多個元素

        JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {

            private static final long serialVersionUID = 1L;

            @Override
            public Iterator<String> call(String line) throws Exception {
                String word = new String(line.getBytes("UTF-8"));
                System.out.println("word = "+word);
                return Arrays.asList(word.split(",")).iterator();
            }

        });
        // 接著,需要將每一個單詞,映射為(單詞, 1)的這種格式
        // 因為只有這樣,后面才能根據單詞作為key,來進行每個單詞的出現次數的累加
        // mapToPair,其實就是將每個元素,映射為一個(v1,v2)這樣的Tuple2類型的元素
        // 如果大家還記得scala里面講的tuple,那么沒錯,這里的tuple2就是scala類型,包含了兩個值
        // mapToPair這個算子,要求的是與PairFunction配合使用,第一個泛型參數代表了輸入類型
        // 第二個和第三個泛型參數,代表的輸出的Tuple2的第一個值和第二個值的類型
        // JavaPairRDD的兩個泛型參數,分別代表了tuple元素的第一個值和第二個值的類型
        JavaPairRDD<String, Integer> pairs = words.mapToPair(

                new PairFunction<String, String, Integer>() {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public Tuple2<String, Integer> call(String word) throws Exception {
                        return new Tuple2<String, Integer>(word, 1);
                    }

                });

        // 接著,需要以單詞作為key,統(tǒng)計每個單詞出現的次數
        // 這里要使用reduceByKey這個算子,對每個key對應的value,都進行reduce操作
        // 比如JavaPairRDD中有幾個元素,分別為(hello, 1) (hello, 1) (hello, 1) (world, 1)
        // reduce操作,相當于是把第一個值和第二個值進行計算,然后再將結果與第三個值進行計算
        // 比如這里的hello,那么就相當于是,首先是1 + 1 = 2,然后再將2 + 1 = 3
        // 最后返回的JavaPairRDD中的元素,也是tuple,但是第一個值就是每個key,第二個值就是key的value
        // reduce之后的結果,相當于就是每個單詞出現的次數
        JavaPairRDD<String, Integer> wordCounts = pairs.reduceByKey(

                new Function2<Integer, Integer, Integer>() {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public Integer call(Integer v1, Integer v2) throws Exception {
                        return v1 + v2;
                    }

                });

        // 到這里為止,我們通過幾個Spark算子操作,已經統(tǒng)計出了單詞的次數
        // 但是,之前我們使用的flatMap、mapToPair、reduceByKey這種操作,都叫做transformation操作
        // 一個Spark應用中,光是有transformation操作,是不行的,是不會執(zhí)行的,必須要有一種叫做action
        // 接著,最后,可以使用一種叫做action操作的,比如說,foreach,來觸發(fā)程序的執(zhí)行

        wordCounts.foreach(new VoidFunction<Tuple2<String,Integer>>() {

            private static final long serialVersionUID = 1L;

            @Override
            public void call(Tuple2<String, Integer> wordCount) throws Exception {
                System.out.println(wordCount._1 + " 出現 " + wordCount._2 + " 次");
            }

        });

        sc.close();
    }
}

引入的pom如下

    <properties>
        <spark.version>2.1.0</spark.version>
        <scala.version>2.11</scala.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_${scala.version}</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming_${scala.version}</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_${scala.version}</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-hive_${scala.version}</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-mllib_${scala.version}</artifactId>
            <version>${spark.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.10</artifactId>
            <version>1.6.1</version>
        </dependency>
    </dependencies>

1.5、其他

  • 1.5.1、SparkContext:
    編寫spark程序用到的第一個類,該類是spark的主要入口點,若spark集群當做服務端,那么SparkContext就是客戶端的核心;它是用于連接spark集群、創(chuàng)建RDD、累加器、廣播變量的基礎。參考官網上的圖片。
image.png
  • 1.5.2、sparkcontext相關組件


    image.png
  • 1.5.3、創(chuàng)建sparkcontext

        SparkConf conf = new SparkConf()
                                        .setAppName("WordCountLocal")
                                        .setMaster("local");

        JavaSparkContext sc = new JavaSparkContext(conf);

注:如果不做特殊說明,后續(xù)文章中sc = JavaSparkContext對象。
參考出處

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。