Spark基礎

安裝

Spark下載地址:http://spark.apache.org/downloads.html, 解壓後即可使用。
在這裏插入圖片描述
創建測試文件並輸出內容:
在這裏插入圖片描述
輸入val lines=sc.textFile("/home/lucy/hellospark") 加載文件內容,輸入lines.count()進行統計行數:
在這裏插入圖片描述

Scala之HelloWorld

環境:idea + maven + scala

創建一個空的maven工程(可參照參考資料1),在src/main目錄下創建scala目錄,並設置爲Sources Root。然後添加Scala環境:
File->Project Structure->Libraries,新增Scala SDK庫(如果是多模塊的maven項目,則在需要的模塊中添加)。
在scala目錄下新建scala class文件,類型選擇Object:

object HelloWorld {
  def main(args: Array[String]): Unit = {
    println("hello world!")
  }
}

運行後即可輸出hello world。

第一個Spark程序

對官方提供的例子WordCount進行稍許修改,如下:

import org.apache.spark.{SparkConf, SparkContext}

object WordCount {
  def main(args: Array[String]): Unit = {
    /**
      * 創建Spark的配置對象SparkConf,設置Spark程序的運行時的配置信息
      * 例如說通過setMaster來設置程序要連接的Spark集羣的Master的URL
      * 如果設置爲local,則代表Spark程序本地運行
      */
    val conf = new SparkConf()
    conf.setAppName("MySimpleApp") // 設置應用名稱,在程序運行的監控界面可以看到名稱
    conf.setMaster("local") // 此時程序在本地運行,無需安裝集羣

    /**
      * SparkContext是Spark程序所有功能的唯一入口
      * 作用:初始化Spark應用程序運行所需要的核心組件,同時負責Spark程序往Master註冊程序
      * SparkContext是整個Spark應用程序中最爲重要的一個對象
      */
    val sc = new SparkContext(conf) // 創建SparkContext對象,通過傳入SparkConf實例來定製Spark運行的具體參數

    /**
      * 根據具體的數據來源(HDFS,HBase,Local FS,DB等),通過SparkContext來創建RDD
      * RDD的創建基本有三種方式,根據外部的數據來源,根據Scala集合,由其他的RDD操作產生
      * 數據會被RDD劃分爲一系列的Partitions,分配到每個Partition的數據屬於一個Task的處理範疇
      */

    // 讀取本地文件,並設置partition爲1
    var lines = sc.textFile("/home/文檔/test_data", 1)

    /**
      * 對初始化的RDD進行Transformation級別的處理,例如map,filter等高階函數等的編程。
      * 1.將每一行的字符串拆分成單個單詞
      * 2.在單詞拆分的基礎上對每個單詞的實例計數爲1,也就是word=>(word,1)
      * 3.在每個單詞實例計數爲1的基礎之上統計每個單詞在文件出現的次數
      */

    // 對每一行的字符串進行單詞的拆分並把所有行的拆分結果通過flat合併成一個大的單詞集合
    val words = lines.flatMap{
      line => line.split("  ") //words同樣是RDD類型
    }
    val pairs = words.map{
      word => (word, 1)
    }
    val wordCounts = pairs.reduceByKey(_+_) // 對相同的key,進行value的累加

    wordCounts.foreach(wordNumberPair => println(wordNumberPair._1 + " : " + wordNumberPair._2))
    sc.stop() // 注意一定要將SparkContext的對象停止,因爲SparkContext運行時會創建很多的對象
  }
}

事實上在本地運行這個sample可能會報錯。
第一個錯誤是: ClassNotFoundException: org.apache.spark.SparkConf
原因是依賴包org.apache.spark的作用域,去掉provided限制即可:

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

第二個錯誤是:

Exception in thread "main" java.lang.NoSuchMethodException: akka.remote.RemoteActorRefProvider

原因是:本地安裝的scala中帶的actor版本和spark中akka的actor版本有差異。解決辦法是在File->Project Structure->modules中調整scala的sdk順序,放到spark後即可,如下圖所示:
在這裏插入圖片描述

其他可能遇到的錯誤:tried to access method com.google.common.base.Stopwatch.()V from class org.apache.hadoop.mapred.FileInputFormat
解決思路:hadoop包版本問題

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>2.7.2</version>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.7.2</version>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-mapreduce-client-core</artifactId>
    <version>2.7.2</version>
</dependency>

Spark基礎函數用法

重要概念

RDD是Spark的計算模型,全稱爲彈性的分佈式數據集合(Resilient Distributed DataSet)。RDD的創建基本有三種方式:從外部存儲系統中引用一個數據集;並行化一個已存在的集合;由其他的RDD操作產生。

一個完整的RDD運行任務被分爲兩部分:Transformation(轉換)和Action(執行)。
Transformation用於創建RDD,此部分提供了大量的操作方法,如map、filter、groupBy、join等,以便利用這些操作生成新的RDD。
Action是數據執行部分,通過count、reduce、collect等方法真正執行數據的計算部分。
RDD中所有的操作都是Lazy模式的,運行在編譯中不會立即計算最終結果,而是記住所有的操作步驟和方法,只有顯式地遇到啓動命令時才執行計算。

Transformation操作

filter
filter操作對RDD進行過濾,生成一個新的RDD,原RDD不會改變。

Union或++
union操作(或++操作)用於合併兩個RDD。

map
map操作將函數作用到RDD中的每個元素上,生成一個新的RDD返回。

下面有一個例子:

def main(args: Array[String]): Unit = {

  val sc = new SparkContext("local", "My Opts")
  // 根據集合產生RDD	
  val myfirstrdd = sc.parallelize(List("a", "b", "c"))
  val ardd = myfirstrdd.filter(_ != "a").map(x => {(x, 1)})
  // 設置持久化策略
  ardd.persist(StorageLevel.DISK_ONLY)

  // 保存
  ardd.saveAsTextFile("output")
}

執行main函數,將在當前工作目錄下生成output文件夾,含兩個文件part-00000和_SUCCESS(執行成功標識,內容爲空)。part-00000內容是:

(b,1)
(c,1)

flatMap
flatMap會先執行map操作,再將所有對象合併爲一個對象,返回值是一個Sequence。flatMap將輸入執行func操作時,對象必須是可迭代的。

下面看一個例子:

def main(args: Array[String]): Unit = {

  val sc = new SparkContext("local", "My Opts")

  val myfirstrdd = sc.parallelize(List("Hello world", "Hello master"))
  val ardd = myfirstrdd.filter(_ != null).map(
    line => {
      val data = line.split(" ")
      (data(0), data(1))
    }
  )

  val result = ardd.collect()
  println(result.toList)

  ardd.persist(StorageLevel.DISK_ONLY)
  // 保存
  ardd.saveAsTextFile("output")

}

輸出結果:List((Hello,world), (Hello,master)),生成的文件爲:

(Hello,world)
(Hello,master)

如果使用flatMap,則如下所示:

def main(args: Array[String]): Unit = {

  val sc = new SparkContext("local", "My Opts")

  val myfirstrdd = sc.parallelize(List("Hello world", "Hello master"))
  val ardd = myfirstrdd.filter(_ != null).flatMap(
    line => {
      line.split(" ")
    }
  )

  val result = ardd.collect()
  println(result.toList)
  ardd.persist(StorageLevel.DISK_ONLY)
  // 保存
  ardd.saveAsTextFile("output")
}

輸出結果:List(Hello, world, Hello, master),生成的文件爲:

Hello
world
Hello
master

Action操作

count
count操作求RDD大小。如上文的例子中經過map和flatMap轉換後的RDD,對其執行count(),結果分別是2和4。

countByValue
返回RDD每個元素的個數。對上文例子中經過flatMap轉換後的RDD執行countByValue():

val result = ardd.countByValue()
println(result)

結果是:

Map(Hello -> 2, master -> 1, world -> 1)

reduce
reduce操作用於結果合併計算。
仍然對上文中經過flatMap轉換後的RDD進行操作:

val result = ardd.reduce(
  (x, y) => {x + "," + y}
)
println(result)

結果爲:Hello,world,Hello,master

reduceByKey
reduceByKey根據key進行結果合併。
對於上文中經過flatMap轉換後的RDD繼續操作:

val secondRdd = ardd.map(line => {
  (line, 1)
}).reduceByKey((x, y) => x + y)

println(secondRdd.collect().toList)

結果爲:List((Hello,2), (master,1), (world,1))

程序打包與運行

開發完成之後,就可以將程序打成jar包並在spark中運行了。具體步驟是(IDE是idea):
(1) File->Project Structure->Artifacts,點擊+按鈕,添加JAR,如下圖所示:
在這裏插入圖片描述(2) 然後選擇主類(點擊文件夾圖標自動提供選擇項):
在這裏插入圖片描述
(3) 配置jar包生成路徑Output directory,點擊應用,OK。
(4) 選擇菜單欄的Build選擇,Build->Build Artifacts:
在這裏插入圖片描述
Build即可。最終生成的jar包位於第三步中配置的位置。

將jar包上傳到spark服務器的某個目錄,然後進入spark的bin目錄,通過spark-submit運行jar包:
在這裏插入圖片描述當然,對於maven工程,直接執行maven的package來生成jar包,更爲方便。

參考資料

[1] https://blog.csdn.net/a18852867035/article/details/82744433
[2] https://blog.csdn.net/a1610770854/article/details/51810124
[3] https://www.jianshu.com/p/c6f8b56d8467

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