spark基础知识

1. RDD

ctrl+h 查看实现方法
RDD方法 => RDD算子: RDD根据数据处理方式的不同将算子整体上分为Value类型、双Value类型和Key-Value类型

  • Value型: map :分区内的数据执行是有序列,分区间是无序的.

本质:一个RDD就是一个弹性分布式对象集合,本质上是一个只读的分区记录集合,每个RDD可分成多个分区,每个分区就是一个数据集片段。

// 创建一个spark config
import org.apache.spark.{SparkConf, SparkContext}
val conf = new SparkConf().setAppName("spark").setMaster("local[*]")
val sc = new SparkContext(conf)

1.1 RDD的创建

  1. 采用textFile()方法从文件系统中加载数据创建RDD
// 例如:HDFS分布式系统文件:
val  lines = sc.textFile("word.txt") 
  1. 通过并行集合(数组)创建RDD
// 通过调用SparkContext的parallelize方法:
val array = Array(1,2,3,4,5)  // or List
val rdd = spark.parallelize(array)

1.2 持久化

背景:每次调用行动操作时,都会触发一次从头开始的计算

  1. 使用persist() 方法对一个rdd标记为持久化
  2. cache()等同于persist(MEMORY_ONLY)
  3. unpersist() 删除持久化的rdd
val list = List("hardoop","spark","Hive")
val rdd = sc.parallelize(list)
rdd.cache()
print(rdd.count())
print(rdd.collect().mkString(",")) // 不需要触发从头开始计算

1.3 分区

// 1. 创建rdd时,在调用textFile和parallelize方法的时候,手动指定分区个数即可
val rdd = sc.textFile(path,partitionNum)

// 2. 通过转换操作得到新的RDD时,直接调用repartition方法即可

1.4 RDD相关的操作

1.4.1 转换操作

// 1. map(func):将每个元素传递到函数func中,并将结果返回一个新的数据集

// 2.filter(func): 筛选满足函数func的元素,并返回一个新的数据集
val lines = sc.textFile("file:///user/local/spark/mycode/word.txt")
lines.filter(line => line.contains("spark")).count()

// 3. flatMap(func): 与map相似,但是每个输入元素都可以映射到0或多个输出结果

1.4.2 行动操作

// 1. count():返回数据集中的元素个数

// 2. collect(): 以数组的形式返回数据集中的所有元素

// 3. frist(): 返回数据集中的第一个元素

// 4. take(): 以数组的形式返回数据集中的前n个元素

// 5. reduce(func):通过函数func(输入两个参数,并返回一个值)聚合数据中的元素
lines.map(line => line.split(" ").size).reduce((a,b) => if (a>b) a else b) // 找出文本中单行文本所包含单词数最多的行

// 6. foreach(func):将数据集中的每个元素传递到函数func中运行

1.4.3 PairRDD(键值对)

  1. 创建
// 通过map函数实现:
val pairRDD = lines.flatMap(line => line.split(" ")).map(word => (word,1))
  1. 转换操作
// 1. groupByKey():应用于(k,v)键值对的数据集时,返回一个新的(k,iterable)形式的数据集
val words = Array("one","two","two","three","three","three")
val wordPairRDD = sc.parallelize(words).map(word => (word,1))
val wordCountWithGroup = wordPairsRDD.groupByKey().map(t=>(t._1,t._2.sum))
// 2. reduceByKey(func): 应用于(k,v)键值对的数据集时,返回一个新的(k,v)形式的数据集,其中的每个值是将每个key传递到函数func中进行聚合
val wordCountsWithReduce = wordPairsRDD.reduceByKey(_+_)

// 3. keys():只会把pair rdd中的key返回形成一个新的RDD
pairRDD.keys.foreach(println)
// 4. values(): 只会把pair rdd中的values返回形成一个新的RDD

// 5. sortByKey():返回一个根据键排序的RDD
pairRDD.reduceByKey(_+_).sortByKey(false).collect
// 6. sortBy()
pairRDD.reduceByKey(_+_).sortBy(_._2,false).collect
// 7. mapValues():对键值对RDD中的每个value都对应一个函数
pairRDD.mapValues(x=>x+1)
// 8. join: 内链接,对于给定的两个输入数据集(k,v1)和(k,v2)只有在两个数据集中都存在的key才会被输出,最终的得到一个新的(k,(v1,v2))类型的数据集。
val pairRDD1=sc.parallelize(Array(("spark",1),("spark",2),("hadoop",3),("hadoop",5)))
val pairRDD2=sc.parallelize(Array(("spark",fast)))
pairRDD1.join(pairRDD2).foreach(println)

1.5 综合应用

  1. 题目:给定一组键值对("spark",2),("hadoop",4),("hadoop",6).("spark",6), 键值对的key表示图书名称,value表示某天图书的销量,请计算每个键对应的平均值,也就是计算每种图书的每天的平均销量。
val rdd = sc.parallelize(Array(("spark",2),("hadoop",4),("hadoop",6).("spark",6)))
rdd.mapValues(x=>(x,1)).reduceBykey((x,y)=>(x._1+y._1,x._2+y._2)).mapValues(x=>(x._1/x._2)).collect()

  1. 求TOP值
    两个文件中包含id、user_id、payment、product_id,求Top N个payment值
import org.apach.spark.{SparkConf,SparkContext}
object TopValues{
	def main(args,Array[String]):Unit={
		val = conf new SparkConf().setAppName("TopValues").setMaster('local')
		val sc =new SparkContext(conf)
		sc.setLogLevel("ERROR")
		val lines = sc.textFile("hdfs://localhost:9000/user/hadoop/spark/chaper",2)
		var num =0
		// 转化为pair格式,才能使用sortByKey
		val result lines.filter(line => (line.trim().length>0)&&(line.split(",").length==4)).map(_.split(",")(2)).map(x=>(x.toint,"")).sortByKey(false).map(x=>x._1).take(5).foreach(x=>{
		num=num+1
		println(num+"\t"+x)
		})
	}
}
  1. 求出多个文件中数值的最大最小值
import org.apach.spark.{SparkConf,SparkContext}
object MaxAndMin{
	def main(args,Array[String]):Unit={
		val = conf new SparkConf().setAppName("MaxAndMin").setMaster('local')
		val sc =new SparkContext(conf)
		sc.setLogLevel("ERROR")
		val lines = sc.textFile("hdfs://localhost:9000/user/hadoop/spark/chaper5",2)
		val result =lines.filter(_.trim().length>0).map(x=>{
		val max = Integer.MAX_VALUE
		val min = Integer.MIN_VALUE
		for (num <- x._2){
			if(num>max){
				max= num
			}if(num<min){
			min=num}	
		}
		(max,min)}).colect.foreach(x=>{
			println("max\t" + x._1)
			println("min\t" + x._2)
		})
		}
}
  1. 有多个输入文件,每个文件中每一行内容均为一个整数,排序之后输出两列,排序次位以及值。
import org.apach.spark.{SparkConf,SparkContext,SparkContext._}
object MySort{
	def main(args:Array[String]){
		val = conf new SparkConf().setAppName("MySort").setMaster('local')
		val sc =new SparkContext(conf)
		val data = sc.textFile('data',3)// 读取3个分区文件
		var index =0
		val result =data.filter(_.trim().length>0).map(n=>(n.trim.toInt,"")).sortByKey().map(t=>{
		index+=1
		(index,t._1)
		})
		result.saveAsTextfile("result")
	}
}
  1. 二次排序
    对于一个给定的文件,请对数据进行排序,首先根据第1列数据进行数据降序排列,如果第一列数据相等,则根据第2列数据降序排列。
package cn.edu.zhuht.spark
class SecondarySortKey(val first:Int, val second:Int) extends Ordered [SecondarySortKey] with Serializable{
	def compare(other:SecondarySortKey):Int={
		if(this.first - other.first!=0){
		this.first -other.first
		}else{
			this.second - other.second
		}
	}
}

package cn.edu.zhuht.spark
import org.apach.spark.{SparkConf,SparkContext}

object SecondarySortApp{
	def main(args:Array[String]){
		val conf =new SparkConf().setAppName("SecondarySortApp").setMaster("local")
		val sc = new SparkContext(conf)
		val lines =sc.textFile("file.txt")
		val pairWithSortKey =line.map(line=> (new SecondarySortKey(line.split(" ")(0).toInt,line.split(" ")(1).toInt),line))
		val sorted = pairWithSortKey.sortByKey(false)
		val sortedResult =sorted.map(sortedLine => sortedLine._2)
		sortedResult.collect().foreach(println)
	}
}

2. 数据读写

2.1 文本文件

// 1. 本地文件系统的数据读取:
val  textFile = spark.textFile("file:///user/local/spark/mycode/writeback.txt")
// 2. 分布式文件系统HDFS:
val textfile = sc.textFile('word.txt') 
// 3. 写入数据:textFile.saveAsTextFile("file:///user/local/spark/mycode/word.txt")

2.2 JSON文件数据

// 1. 读取:rdd中的元素就是一个个json字符串
val  jsn = sc.textFile("file:///user/local/spark/mycode/people.json")
// 2. 解析:
jsn.map(s => JSON.parseFull(s))

2.3 3. HBase数据

定义:HBase是一个稀疏、多维度、排序的映射表,这张表的索引是行键、列簇、列限定符和时间戳

3. SparkSQL

数据类型:DataFrame

3.1创建

// 1. 使用SparkSession支持从不同的数据源加载数据,并把数据转换成DataFrame

val df=spark.read.josn(file_path) 
// 2. rdd.toDF()

3.2 常用操作

// 1. 打印模型信息:
df.printSchema()
// 2. 选择多列:
df.select(df("name"),df("age")+1).show
// 3. 条件过滤:
df.filter(df("age")>=20).show()
// 4.分组聚合:
df.groupBy("age").count().show()
// 5.排序操作:
df.sort(df("age").desc,df("name").asc).show()
// 6.重命名:
df.select(df("name").as("userName"),df("age")).show()

4. Spark Streaming

原理:是将实时输入数据流以时间片(秒级)为单位进行拆分。分成一段一段的DStream,每一段数据转换为Spark中的rdd

4.1 spark streaming程序的基本操作

  • 通过创建输入DStream来定义输入源
  • 通过对DStream应用转换操作和输出操作来定义流计算
  • 用streamingContext.start()来开始接收数据和处理流程
  • 通过streamingContext.awaitTermination()方法来等待处理结束
  • 可以通过streamingContext.stop() 来手动结束流计算进程

4.2 创建StreamingContext对象

如果要运行一个spark Streaming程序,就需要首先生成一个StreamingContext对象,他是spark streaming程序的主入口。

// 可以从sparkConf对象创建一个StreamningContext对象:

val ssc = new StreamingContext(sc,Seconds(1)) 

4.3 DStream转换操作

4.3.1 无状态转换操作

// 1. map、filter、reduce、flatMap、count、join、reduceByKey

//2. union、countByValue、transform(func)、cogroup

4.3.2 有状态转换操作

滑动窗口转换操作

// 1. window(): 基于源Dstream产生的窗口化的批数据,计算得到一个新的Dstream
// 2. countByWindow(): 返回流中元素的一个滑动窗口数
// 3. reduceByWindow():返回一个单元素流
// 4. reduceByKeyAndWindow():应用到一个(K,V)键值对组成的DStream上时,会返回一个有(K,V)键值对组成的新的DStream

updateStateByKey操作

5. SparkMLlib

5.1 简介

在这里插入图片描述
应用实例

// 引入包并构建数据集
import org.apache.spark.ml.feature._
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.{Pipeline,PipelineModel}
import org.apache.spark.ml.linalg.Vector
import org.apache.spark.sql.Row

val  training = spark.createDataFrame(Seq((0L,"a,b,c,spark",1.0),
(1L,"d,b",0.0),
(2L,"spark,d,h",1.0),
(3L,"hadoop,mapredcue",0.0)
)).toDF("id","text","label")
// 2. 定义Pipeline中的各个工作流阶段PipelineStage,包括转换器和评估器,具体的包含tokenizer,hashingTF和lr
// 转换器
val tokenizer = new Tokenizer().setInputCol("text").setOutputCol("word")
// 转换器
val hashingTF = new HashingTF().setNumFeatures(1000).setInputCol(tokenizer.getOututCol).setOutputCol("features")
// 评估器
val lr = new LogisticRegression().setMaxIter(10).setRegParam(0.01)


// 3. 按照具体的处理逻辑有序地组织PiplineStages,并创建一个pipeline
val pipeline =new Pipeline().setStages(Array(tokenizer,hashingTF,lr))

// 4. 运行fit,产生一个PipelineModel,即生成一个Transformer
val model = pipeline.fit(training)

// 5. 测试集测试,并使用pipelineModel的transform()方法
val test =spark.createDataFrame(Seq((4L,"spark,ih,k"),(5L,"l,m"),(6L,"spark,x,y"),(7L,"apache,ih,k"))).toDF("id","text")

model.transform(test).select("id","text","probability","prediction").collect().foreach{case Row(id:Long, text:String,prob:Vector,prediction:Double)=>println(s"($id,$text)--> prob=$prob, prediction =$prediction")}


5.2 特征处理

5.2.1 文本特征处理

  • 分词
    MLlib提供了Tokenization方法对文本进行分词,RegexTokenizer基于正则表达式匹配提供了更高级的分词。默认使用多个空格(\s+)作为分隔符。可以通过参数pattern指定分隔符。
import org.apach.spark.ml.feature.{RegexTokenizer,Tokenizer}
val sentenceDataFrame = spark.createDataFrame(seq(
	(0,'Hi i heard about spark'),
	(1,'I wish java could user case calsses')
)).toDF("label","sentence")

val tokenizer =new Tokenizer().serInputCol("sentence").setOutputCol("words")
val regexTokenizer = new RegexTokenizer()
	.setInputCol('sentence')
	.setOutputCol("words")
	.setPattern("\\W")
	.serGaps(false)

val tokenized = tokenizer.transform(sentenceDataFrame)
tokenized.select("word","label").take(2).foreach(println)


val regexTokenized = regexTokenizer.transform(sentenceDataFrame)
regexTokenized.select("word","label").take(2).foreach(println)

去除停用词

import org.apache.spark.ml.feature.StopWordsRemover

val remover = new StopWordsRemover()
	.setInputCol("raw")
	.setOutputCol("filtered")

val dataSet =spark.createDataFrame(seq(
	(0,seq("I","saw","the","red","baloon")),
	(1,seq("Mary","had","a","little","lamb"))
)).toDF("id","raw")
remover.transform(dataSet).show()

词稀疏编码

import org.apache.spark.ml.feature.StringIndexer

val df =spark.createDataFrame(
	seq((0,"a"),(1,"b"),(2,"c"),(3,"a"),(4,"a"),(5,"c"))
).toDF("id","catagory")

val indexer =new StringIndexer()
	.setInputCol("category")
	.setOutputCol("categoryIndex")
val indexed =indexer.fit(df).transform(df)
indexed.show()

文本处理还有Ngram、TF-IDF、word2vec 等高级方法。

5.2.2 数值特征处理

特征归一化
Mllib提供了3种归一化方法:StandardScaler、MinMaxScaler和MaxAbsScaler

import org.apache.spark.SparkContext._
import org.apache.spark.mllib.feature.StandarScaler
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.util.MLUtils

val data = MLUtils.loadLibSVMFile(sc,"data/MLlib/sample_libsvm_data.txt")
val scaler1 = new StandarScaler().fit(data.map(x=> x.features))
val scaler2 = new StandarScaler(withMean = true,withStd = true).fit(data.map(x=> x.features))
// scaler2 和 scaler3 相同的模型,并且会产生相同的转换
val scaler3 = new StandarScalerModel(scaler2.std, scaler2.mean)
// data1是单位方差
val data1 = data.map(x=> (x.label,scaler1.transform(x.features)))
//如果不将这些特征转换成密度向量,那么零均值转换就会增加,稀疏向量例外
// data2 是单位方差和零均值
val data2 = data.map(x =>(x.label,scaler2.transform(Vectors.dense(x.features.toArray))))

正则化

import org.apache.spark.SparkContext._
import org.apache.spark.mllib.feature.Normalizer
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.util.MLUtils

val data = MLUtils.loadLibSVMFile(sc,"data/MLlib/sample_libsvm_data.txt")
// 默认计算2范数
val normalizer1 = new Normalizer()
val normalizer2 = new Normalizer(p = Double.PositiveInfinity)    // p
// data1中每个样本将使用L2范数进行标准化
val data1 =data.map(x => (x.label,normalizer1.transform(x.features)))
// data2中每个样本将使用无穷范数进行标准化
val data2 =data.map(x => (x.label,normalizer2.transform(x.features)))

二值化

import org.apache.spark.ml.feature.Binarizer
val data = Array((0,0.1),(1,0.8),(2,0.2))
val dataFrame = spark.createDataFrame(data).toDF("label","feature")

val binarizer: Binarizer = new Binarizer()
	.serInputCol("feature")
	.setOutputCol('binarized_feature')
	.setThreshold(0.5)

val binarizerdDataFrame =  binarizer.transform(dataFrame)
val binarizerdFeatures = binarizerdDataFrame.select("binarized_feature")
binarizerdFeatures.collect().foreach(println)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值