spark學習筆記

qq_45732538發表於2020-11-01

spark介紹

在這裡插入圖片描述
MapReduce存在的缺陷:
在這裡插入圖片描述
在這裡插入圖片描述

Spark的模組組成

在這裡插入圖片描述
在這裡插入圖片描述

spark的使用模式

在這裡插入圖片描述
在這裡插入圖片描述

Spark最核心的資料抽象

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
注意:
scala>rdd.collect
收集rdd中的資料組成Array返回,此方法將會把分散式儲存的rdd中的資料集中到一臺機器中組建Array。
在生產環境下一定要慎用這個方法,容易記憶體溢位

RDD操作

在這裡插入圖片描述
每一個懶操作都會只生成一個rdd物件,但是資料沒有載入進來,只有執行了一個action操作,資料才會載入進來
在這裡插入圖片描述

Transformations

map(func)
案例展示:
map 將函式應用到rdd的每個元素中
val rdd = sc.makeRDD(List(1,3,5,7,9))
rdd.map(*10)
flatMap(func)
案例展示:
flatMap 扁平map處理
val rdd = sc.makeRDD(List(“hello world”,“hello count”,“world spark”),2)
rdd.map(
.split{" "})//Array(Array(hello, world), Array(hello, count), Array(world, spark))
rdd.flatMap(.split{" "})//Array[String] = Array(hello, world, hello, count, world, spark)
//Array[String] = Array(hello, world, hello, count, world, spark)
注:map和flatMap有何不同?
map: 對RDD每個元素轉換
flatMap: 對RDD每個元素轉換, 然後再扁平化(即去除集合)
所以,一般我們在讀取資料來源後,第一步執行的操作是flatMap
filter(func)
案例展示:
filter 用來從rdd中過濾掉不符合條件的資料
val rdd = sc.makeRDD(List(1,3,5,7,9));
rdd.filter(
<5);
union(otherDataset)
案例展示:
union 並集 – 也可以用++實現
val rdd1 = sc.makeRDD(List(1,3,5));
val rdd2 = sc.makeRDD(List(2,4,6,8));
val rdd = rdd1.union(rdd2);
val rdd = rdd1 ++ rdd2;
在這裡插入圖片描述
intersection(otherDataset)
案例展示:
intersection 交集
val rdd1 = sc.makeRDD(List(1,3,5,7));
val rdd2 = sc.makeRDD(List(5,7,9,11));
val rdd = rdd1.intersection(rdd2);
在這裡插入圖片描述
subtract
案例展示:
subtract 差集
val rdd1 = sc.makeRDD(List(1,3,5,7,9));
val rdd2 = sc.makeRDD(List(5,7,9,11,13));
val rdd = rdd1.subtract(rdd2);
distinct([numTasks]))
Return a new dataset that contains the distinct elements of the source dataset.
沒有引數,將RDD裡的元素進行去重操作
案例展示:
val rdd = sc.makeRDD(List(1,3,5,7,9,3,7,10,23,7));
rdd.distinct
groupByKey([numTasks])
案例展示:
scala>val rdd = sc.parallelize(List((“cat”,2), (“dog”,5),(“cat”,4),(“dog”,3),(“cat”,6),(“dog”,3),(“cat”,9),(“dog”,1)),2);
scala>rdd.groupByKey()
注:groupByKey對於資料格式是有要求的,即操作的元素必須是一個二元tuple,
tuple.1 是key, tuple.2是value
比如下面這種資料格式:
sc.parallelize(List(“dog”, “tiger”, “lion”, “cat”, “spider”, “eagle”), 2)就不符合要求
以及這種:
sc.parallelize(List((“cat”,2,1), (“dog”,5,1),(“cat”,4,1),(“dog”,3,2),(“cat”,6,2),(“dog”,3,4),(“cat”,9,4),(“dog”,1,4)),2);
reduceByKey(func, [numTasks])
案例展示:
scala>var rdd = sc.makeRDD( List( (“hello”,1),(“spark”,1),(“hello”,1),(“world”,1) ) )
rdd.reduceByKey(
+
);
注:reduceByKey操作的資料格式必須是一個二元tuple
sortByKey([ascending], [numTasks])
案例展示:
val d2 = sc.parallelize(Array((“cc”,32),(“bb”,32),(“cc”,22),(“aa”,18),(“bb”,6),(“dd”,16),(“ee”,104),(“cc”,1),(“ff”,13),(“gg”,68),(“bb”,44)))
d2.sortByKey(true).collect
在這裡插入圖片描述join(otherDataset, [numTasks])
案例展示:
val rdd1 = sc.makeRDD(List((“cat”,1),(“dog”,2)))
val rdd2 = sc.makeRDD(List((“cat”,3),(“dog”,4),(“tiger”,9)))
rdd1.join(rdd2);
cartesian(otherDataset)
案例展示:
cartesian 笛卡爾積
val rdd1 = sc.makeRDD(List(1,2,3))
val rdd2 = sc.makeRDD(List(“a”,“b”))
rdd1.cartesian(rdd2);
coalesce(numPartitions)
coalesce(n,true/false) 擴大或縮小分割槽
案例展示:
val rdd = sc.makeRDD(List(1,2,3,4,5),2)
rdd.coalesce(3,true);//如果是擴大分割槽 需要傳入一個true 表示要重新shuffle
rdd.coalesce(2);//如果是縮小分割槽 預設就是false 不需要明確的傳入

Actions

reduce(func)
使用該函式(接受兩個引數並返回一個)聚合資料集的元素。函式應該是可交換的和結合的,這樣就可以正確地平行計算。
collect()
返回RDD所有元素,將rdd分散式儲存在叢集中不同分割槽的資料 獲取到一起組成一個陣列返回。要注意 這個方法將會把所有資料收集到一個機器內,容易造成記憶體的溢位 在生產環境下千萬慎用
count()
統計RDD裡元素個數
案例展示:
val rdd = sc.makeRDD(List(1,2,3,4,5),2)
rdd.count
first()
取出第一個元素
takeOrdered(n, [ordering])
takeOrdered(n) 先將rdd中的資料進行升序排序 然後取前n個
val rdd = sc.makeRDD(List(52,31,22,43,14,35))
rdd.takeOrdered(3)
top(n)
top(n) 先將rdd中的資料進行降序排序 然後取前n個
val rdd = sc.makeRDD(List(52,31,22,43,14,35))
rdd.top(3)
saveAsTextFile(path)
saveAsTextFile 按照文字方式儲存分割槽資料
val rdd = sc.makeRDD(List(1,2,3,4,5),2);
rdd.saveAsTextFile("/root/work/aaa")
countByKey()
僅在型別(K,V)的RDD上可用。返回(K,Int)對的hashmap及其每個鍵的計數。
foreach(func)
遍歷rdd

在這裡插入圖片描述在這裡插入圖片描述

單機狀態下使用eclipse操作spark

所需要的jar包地址:
https://gitee.com/light__pro/bigdata/tree/master/jars

package cn.tedu.wordcount
/**
 * 統計單詞個數案例
 */
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext

object Driver {
  def main(args: Array[String]): Unit = {
    //建立Spark的環境引數物件,必須設定兩個引數
    //setMaster:指定執行模。local表示本地單機模式
    //setAppName:指定應用程式id,使用者自定義
    
    val conf=new SparkConf().setMaster("local").setAppName("wordcount")
    //建立Spark的上下文物件,通過此物件操作Spark
    val sc=new SparkContext(conf)
    val data=sc.textFile("hdfs://hadoop01:9000/01.txt",2)
    val result=data.flatMap { x => x.split(" ") }
                    .map { x => (x,1) }
                    .reduceByKey{_+_}
                    
                    
    result.foreach{println}
    result.saveAsTextFile("hdfs://hadoop01:9000/wordcount")
    
  }
  
package cn.tedu.maxmin

import org.apache.spark.SparkContext
import org.apache.spark.SparkConf
/**
 * 處理MaxMin.txt,返回女性最小身高的前兩條資料
 * 
 * 過濾  排序  取值
 * 
 * */
object Driver02 {
   def main(args: Array[String]): Unit = {
    
    
    val conf=new SparkConf().setMaster("local").setAppName("wordcount")
    //建立Spark的上下文物件,通過此物件操作Spark
    val sc=new SparkContext(conf)
    val data=sc.textFile("d://data/MaxMin.txt",2)
    val ss=data.filter { x => x.split(" ") (1).equals("F")}.sortBy(x=>x.split(" ") (2).toInt).take(2)
    ss.foreach {   println }
}}
package cn.tedu.topk

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
/**
 * 處理top.txt,返回單詞頻次最高的前3項單詞資料
 *hello world bye world
	hello hadoop bye hadoop
	hello world java web
	hadoop scala java hive
 * */
object Driver {
  def main(args: Array[String]): Unit = {
    val conf=new SparkConf().setMaster("local").setAppName("wordcount")
    //建立Spark的上下文物件,通過此物件操作Spark
    val sc=new SparkContext(conf)
    val data=sc.textFile("d://data/topk.txt",2)
   val ss= data.flatMap { x => x.split(" ") }.map{x=>(x,1)}.reduceByKey{_+_}
   val aa=ss.take(3)
   aa.foreach(println)  
}
}

**課後作業:**找出一段資料的中位數和方差

package cn.tedu.homework

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext

/**
 * 1.處理median.txt,找出這一組資料的中位數。 正確結果是10
 * 
 * 比如一組資料:
 * 3 1 7 5 9
 * 
 * 1 3 5 7 9    中位數是5  中位數的位置:(n+1)/2=3
 * 1 3 5 7 9 11 中位數是(5+7)/2
 * 
 * 課後作業,只需要考慮元素個數是奇數個情況
 * 
 * 2.處理median.txt,計算出這組資料的方差。
 * 
 * 比如一組資料:
 * 1 2 3 4 5   avg=3
 * [(1-3)^2+(2-3)^2+(3-3)^2 ...]/5
 */
object Driver {
 
  def main(args: Array[String]): Unit = {
    val conf=new SparkConf().setMaster("local").setAppName("median")
    
    val sc=new SparkContext(conf)
    
    val data=sc.textFile("d://data/median.txt")
    
    //RDD[line:String]->flatMap:RDD[num:Int]->sortBy 升序排序
    val r1=data.flatMap { line => line.split(" ") }
               .map { num => num.toInt }
               .sortBy{num => num}
    
    //課後作業1:          
    //獲取中位數的位置           
    val pos=((r1.count()+1)/2).toInt  
    
    //方式1:RDD無法直接通過下標進行操作,所以如果要通過下標操作,需要先轉變為普通集合型別Array再操作
    //val result=r1.collect()(pos-1)
    
    //方式2:通過take方式來實現
    val result=r1.take(pos).last
    
    
    //課後作業2: 
    val avg=r1.sum/r1.count
    val variance=r1.map { num => (num-avg)*(num-avg) }.sum/r1.count
    
    
  }
}

史上最難spark題
輸出一組檔案的倒排索引

package cn.tedu.invert

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext

/**
 * 處理inverted目錄的所有檔案,通過spark最後要輸出一個簡易的倒排索引表,比如:
 * (hello,doc1,doc2)
 * (hadoop,doc1,doc3)
 * ......

 每一個檔案資料大概:
 hello hive
 hello hbase
 hello spark
 */
object Driver { 
  def main(args: Array[String]): Unit = {
    val conf =new SparkConf().setMaster("local").setAppName("invert")
    
    val sc=new SparkContext(conf)
    
    //將指定目錄下的所有檔案讀取到一個RDD中,每有一個檔案會形成一個二元元組。
    //返回的RDD[(filePath,fileText)]
    val data=sc.wholeTextFiles("d://data/inverted/*")
    
    
    //處理思路:
    //1.通過filePath獲取文件名
    //2.通過fileText獲取單詞。先\r\n 切出行,再按空格切單詞
    //3.按單詞分組,輸出要求的倒排表
    
    
    
    //第一步:RDD[(filePath,fileText)]->map:RDD[(fileName,fileText)]
    val r1=data.map{case(filePath,fileText)=>
      val fileName=filePath.split("/").last.dropRight(4)
      (fileName,fileText)
    
    }
    
    
    //第二步:RDD[(fileName,fileText)]->flatMap:RDD[(word,fileName)]
    val r2=r1.flatMap{case(fileName,fileText)=>
      fileText.split("\r\n").flatMap { line => line.split(" ") }
      .map { word =>(word,fileName)}
    }
    
    //第三步:按單詞分組,輸出倒排表。r2現在是一個陣列,陣列的元素是一個二元元組,二元元組第一個是單詞陣列,第//二個是對應的檔名稱
    val r3=r2.groupByKey.map { case(word,it) =>(word,it.toArray.distinct.mkString(",")) }
    
    r3.foreach{println}
    
    
  }
}

Spark的DAG概念

在這裡插入圖片描述在這裡插入圖片描述

RDD的依賴關係

藉助這些依賴關係,DAG可以認為這些RDD之間形成了Lineage(血統,血緣關係)。藉助Lineage,能保證一個RDD被計算前,它所依賴的parent RDD都已經完成了計算;同時也實現了RDD的容錯性,即如果一個RDD的部分或者全部的計算結果丟失了,那麼就需要重新計算這部分丟失的資料
在這裡插入圖片描述在這裡插入圖片描述子RDD的Partition是parent RDD的所有Partition Shuffle的結果。
在這裡插入圖片描述

stage的劃分

原始的RDD經過一系列轉換後(一個DAG),會在最後一個RDD上觸發一個動作,這個動作會生成一個Job。
所以可以這樣理解:一個DAG對應一個Spark的Job。
在這裡插入圖片描述在這裡插入圖片描述

spark基礎核心概念總結

在這裡插入圖片描述 對應關係:
一個DAG對應一個Spark的Job。
一個Action對應一個Job任務。
一個分割槽對應一個task。
一個Stage是一組Task的集合
一個應用程式對應一個sc,一個應用程式至少包含一個job

spark圖形化工具的使用

在這裡插入圖片描述在這裡插入圖片描述

Spark叢集搭建

在這裡插入圖片描述在這裡插入圖片描述啟動叢集:
進入Spark的bin目錄下,執行:
sh spark-shell --master spark://hadoop01:7077

提交應用程式到Spark叢集執行

在這裡插入圖片描述程式碼:

package cn.tedu.wordcount
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext

object Driver {
  def main(args: Array[String]): Unit = { 
    //spark://hadoop01:7077:設定執行模式Spark叢集模式,這種模式下不能直接啟動執行,
    //需要打成jar包上傳伺服器執行
    //eclipse打jar包的步驟:工程上右鍵->export->java->jar file->只勾選程式碼並指定路徑->finish即可
    val conf=new SparkConf().setMaster("spark://hadoop01:7077")
                            .setAppName("wordcount")
                            
    val sc=new SparkContext(conf)   
    
    //如果是Spark叢集模式執行,建議分割槽數量一般都是大於伺服器數量,可以確保每臺伺服器可以獲取分割槽資料進行處理
    val data=sc.textFile("hdfs://hadoop01:9000/01.txt", 3)
    
    val wordcount=data.flatMap {_.split(" ")}.map{(_,1)}.reduceByKey{_+_}
    
    wordcount.coalesce(1).saveAsTextFile("hdfs://hadoop01:9000/wordcount-result")
  }
}

在這裡插入圖片描述

Spark叢集架構說明

在這裡插入圖片描述在這裡插入圖片描述

SparkContext底層的任務排程流程

SparkContext底層有三個排程模組:
1.DAG排程模組
2.Task排程模組
3.Backend排程模組
在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述

Spark叢集架構細節補充

在這裡插入圖片描述在這裡插入圖片描述

擴充套件內容 VMS演算法

在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述關於相似度:使用協方差來描述
在這裡插入圖片描述可以通過協方差的正負來判斷是正相關、負相關、還是不相關
相關係數:
在這裡插入圖片描述向量間的夾角餘弦:
在這裡插入圖片描述

zz

相關文章