大数据技术之Spark(三) SparkStreaming

第1章 SparkStreaming 概述

1.1 Spark Streaming 是什么?

  准实时,微批次的数据处理框架
  Spark 流使得构建可扩展的容错流应用程序变得更加容易。
在这里插入图片描述
Spark Streaming类似于Apache Storm,用于流式数据的处理。根据其官方文档介绍,Spark Streaming有高吞吐量和容错能力强等特点。Spark Streaming支持的数据输入源很多,例如:Kafka、Flume、Twitter、ZeroMQ和简单的TCP套接字等等。数据输入后可以用Spark的高度抽象原语如:
   map、reduce、join、window等进行运算。而结果也能保存在很多地方,如HDFS,数据库等。另外Spark Streaming也能和MLlib(机器学习)以及Graphx完美融合。
   操作系统层面上的“原语”(比如 write 之类的系统调用)对程序员来讲的确是不可分割的最小单位
  官方文档
在这里插入图片描述

  和 Spark 基于 RDD 的概念很相似,Spark Streaming 使用离散化流(discretized stream)作为抽象表示,叫作 DStream。DStream 是随时间推移而收到的数据的序列。在内部,每个时间区间收到的数据都作为 RDD 存在,而 DStream 是由这些 RDD 所组成的序列(因此得名“离散化”)。所以简单来讲,DStream 就是对 RDD 在实时数据处理场景的一种封装。

在这里插入图片描述
  DStream 可以从各种输入源创建,比如 Flume、Kafka 或者 HDFS。创建出来的DStream 支持两种操作,一种是转化操作(transformation),会生成一个新的DStream,另一种是输出操作(outputoperation),可以把数据写入外部系统中。DStream 提供了许多与 RDD 所支持的操作相类似的操作支持,还增加了与时间相关的新操作,比如滑动窗口。

1.2 为什么要学习Spark Streaming(特点)

下面都是将官方文档翻译
易用性
  通过高级操作符构建应用程序。
  Spark Streaming将Spark的语言集成API引入到流处理中,使您可以像编写批处理作业一样编写流作业。它支持Java、Scala和Python。

容错性
  有状态精确一次语义开箱即用。
  Spark Streaming可以立即恢复丢失的工作和操作员状态(例如滑动窗口),而不需要任何额外的代码。

易整合到 Spark 体系
  将流与批处理和交互查询相结合。
  通过在Spark上运行,Spark Streaming允许您重用相同的代码进行批处理,根据历史数据连接流,或对流状态运行特殊查询。构建强大的交互式应用程序,而不仅仅是分析。

1.3 Spark Streaming 架构

1.3.1 架构图

 ➢ 整体架构图
在这里插入图片描述
➢ SparkStreaming 架构图
在这里插入图片描述
  Spark Streaming从各种输入源中读取数据,并把数据分组为小的批次。新的批次按均匀的时间间隔创建出来。在每个时间区间开始的时候,一个新的批次就创建出来,在该区间内收到的数据都会被添加到这个批次中。在时间区间结束时,批次停止增长。时间区间的大小是由批次间隔这个参数决定的。批次间隔一般设在500毫秒到几秒之间,由应用开发者配置。每个输入批次都形成一个RDD,以 Spark作业的方式处理并生成其他的RDD。 处理的结果可以以批处理的方式传给外部系统。高层次的架构如图
在这里插入图片描述
Spark Streaming的编程抽象是离散化流,也就是DStream。它是一个 RDD 序列,每个RDD代表数据流中一个时间片内的数据。
在这里插入图片描述
在这里插入图片描述

1.3.2背压机制(即 Spark Streaming Backpressure):

   根据JobScheduler 反馈作业的执行信息来动态调整 Receiver 数据接收率。

第 2 章 Dstream 入门

2.1 WordCount 案例实操

➢ 需求:使用 netcat 工具向 9999 端口不断的发送数据,通过
SparkStreaming 读取端口数据并统计不同单词出现的次数

 代码如下:

object StreamWordCount {
 def main(args: Array[String]): Unit = {
 //1.初始化 Spark 配置信息环境变量
 val sparkConf = new SparkConf()
 .setMaster("local[*]").setAppName("StreamWordCount")
 //2.初始化 SparkStreamingContext 
 //需要2个变量 1.环境配置 ,2.采集(批量处理的周期)周期
 val ssc = new StreamingContext(sparkConf, Seconds(3))
 //3.通过监控端口创建 DStream,读进来的数据为一行行 
 //网络文本流
 val lineStreams = ssc.socketTextStream("linux1", 9999)
 //将每一行数据做切分,形成一个个单词
 val wordStreams = lineStreams.flatMap(_.split(" "))
 //将单词映射成元组(word,1)
 val wordAndOneStreams = wordStreams.map((_, 1))
 //将相同的单词次数做统计
 val wordAndCountStreams = wordAndOneStreams.reduceByKey(_+_)
 //打印
 wordAndCountStreams.print()
 //启动 SparkStreamingContext 启动采集器
 ssc.start()
 //等待采集器结束
 ssc.awaitTermination()
 }
}

  Discretized Stream 是 Spark Streaming 的基础抽象,代表持续性的数据流和经过各种 Spark 原语操作后的结果数据流。在内部实现上,DStream 是一系列连续的 RDD 来表示。每个 RDD 含有一段时间间隔内的数据。在这里插入图片描述
对数据的操作也是按照RDD为单位来进行的
在这里插入图片描述
计算过程由Spark engine来完成
在这里插入图片描述

第 3 章 DStream 创建

3.1 RDD 队列

3.1.1 用法及说明

  测试过程中,可以通过使用 ssc.queueStream(queueOfRDDs)来创建 DStream,每一个推送到这个队列中的 RDD,都会作为一个 DStream 处理。

3.1.2 案例实操

➢ 需求:循环创建几个 RDD,将 RDD 放入队列。通过 SparkStream 创建 Dstream,计算WordCount
 如下代码:

object RDDStream {
 def main(args: Array[String]) {
 //1.初始化 Spark 配置信息
 val conf = new SparkConf().setMaster("local[*]").setAppName("RDDStream")
 //2.初始化 SparkStreamingContext
 val ssc = new StreamingContext(conf, Seconds(4))
 //3.创建 RDD 队列
 val rddQueue = new mutable.Queue[RDD[Int]]()
 //4.创建 QueueInputDStream
 val inputStream = ssc.queueStream(rddQueue,oneAtATime = false)
 //5.处理队列中的 RDD 数据
 val mappedStream = inputStream.map((_,1))
 val reducedStream = mappedStream.reduceByKey(_ + _)
 //6.打印结果
 reducedStream.print()
 //7.启动任务
 ssc.start()
//8.循环创建并向 RDD 队列中放入 RDD
 for (i <- 1 to 5) {
 rddQueue += ssc.sparkContext.makeRDD(1 to 300, 10)
 Thread.sleep(2000)
 }
 ssc.awaitTermination()
 }
}

(2) 结果展示

-------------------------------------------
Time: 1539075280000 ms
-------------------------------------------
(4,60)
(0,60)
(6,60)
(8,60)
(2,60)
(1,60)
(3,60)
(7,60)
(9,60)
(5,60)
-------------------------------------------
Time: 1539075284000 ms
-------------------------------------------
(4,60)
(0,60)
(6,60)
(8,60)
(2,60)
(1,60)
(3,60)
(7,60)
(9,60)
(5,60)
-------------------------------------------
Time: 1539075288000 ms
-------------------------------------------

3.2 自定义数据源

3.2.1 用法及说明

  需要继承 Receiver(采集器),并实现 onStart、onStop 方法来自定义数据源采集。

3.2.2 案例实操

  需求:自定义数据源,实现监控某个端口号,获取该端口号内容。
(1)自定义数据源

//自定义泛型 放在内存中存储
class CustomerReceiver(host: String, port: Int) extends 
Receiver[String](StorageLevel.MEMORY_ONLY) {
 //最初启动的时候,调用该方法,作用为:读数据并将数据发送给 Spark
 override def onStart(): Unit = {
 new Thread("Socket Receiver") {
	 override def run() {
 		receive()
	 }
 	}.start()
 }
 //读数据并将数据发送给 Spark
 def receive(): Unit = {
 //创建一个 Socket
 var socket: Socket = new Socket(host, port)
 //定义一个变量,用来接收端口传过来的数据
 var input: String = null
 //创建一个 BufferedReader 用于读取端口传来的数据
	 val reader = new BufferedReader(new InputStreamReader(socket.getInputStream, 
	StandardCharsets.UTF_8))
 //读取数据
 input = reader.readLine()
 //当 receiver 没有关闭并且输入数据不为空,则循环发送数据给 Spark
 while (!isStopped() && input != null) {
	 store(input)
	 input = reader.readLine()
	 }
	 //跳出循环则关闭资源
	 reader.close()
	 socket.close()
	 //重启任务
	 restart("restart")
	 }
 override def onStop(): Unit = {}
}

3.3 Kafka 数据源(面试、开发重点)

3.3.1 版本选型

  ReceiverAPI:需要一个专门的 Executor 去接收数据,然后发送给其他的 Executor 做计算。存在的问题,接收数据的 Executor 和计算的 Executor 速度会有所不同,特别在接收数据的 Executor速度大于计算的 Executor 速度,会导致计算数据的节点内存溢出。早期版本中提供此方式,当前版本不适用。
  DirectAPI:是由计算的 Executor 来主动消费 Kafka 的数据,速度由自身控制。

3.3.2 Kafka 0-10 Direct 模式

(1)需求:通过 SparkStreaming 从 Kafka 读取数据,并将读取过来的数据做简单计算,最终打印
到控制台。

  如下代码:

import org.apache.kafka.clients.consumer.{ConsumerConfig, ConsumerRecord}
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.{DStream, InputDStream}
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, 
LocationStrategies}
import org.apache.spark.streaming.{Seconds, StreamingContext}
object DirectAPI {
 def main(args: Array[String]): Unit = {
 //1.创建 SparkConf
 val sparkConf: SparkConf = new 
SparkConf().setAppName("ReceiverWordCount").setMaster("local[*]")
 //2.创建 StreamingContext
 val ssc = new StreamingContext(sparkConf, Seconds(3))
 //3.定义 Kafka 参数
 val kafkaPara: Map[String, Object] = Map[String, Object](
 ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG -> 
"linux1:9092,linux2:9092,linux3:9092",
 ConsumerConfig.GROUP_ID_CONFIG -> "atguigu",
 "key.deserializer" -> 
"org.apache.kafka.common.serialization.StringDeserializer",
 "value.deserializer" -> 
"org.apache.kafka.common.serialization.StringDeserializer"
 )
 //4.读取 Kafka 数据创建 DStream
 val kafkaDStream: InputDStream[ConsumerRecord[String, String]] = 
KafkaUtils.createDirectStream[String, String](ssc, //Kafka传过来的KV
 LocationStrategies.PreferConsistent,//采集的节点喝计算的节点怎么匹配
 ConsumerStrategies.Subscribe[String, String](Set("atguigu"), kafkaPara))
 //5.将每条消息的 KV 取出
 val valueDStream: DStream[String] = kafkaDStream.map(record => record.value())
 //6.计算 WordCount
 valueDStream.flatMap(_.split(" "))
 .map((_, 1))
 .reduceByKey(_ + _)
 .print()
 //7.开启任务
 ssc.start()
 ssc.awaitTermination()
 }
}

查看 Kafka 消费进度

bin/kafka-consumer-groups.sh --describe --bootstrap-server linux1:9092 --group atguigu

第 4 章 DStream 转换

  DStream 上的操作与 RDD 的类似,分为 Transformations(转换)和 Output Operations(输出)两种,此外转换操作中还有一些比较特殊的原语,如:updateStateByKey()、transform()以及各种 Window 相关的原语。(看你保存不保存数据)保存则为有状态

4.1 无状态转化操作

  无状态转化操作就是把简单的 RDD 转化操作应用到每个批次上,也就是转化 DStream 中的每一个 RDD。部分无状态转化操作列在了下表中。注意,针对键值对的 DStream 转化操作(比如
reduceByKey())要添加 import StreamingContext._才能在 Scala 中使用。

- [ ] List item

  需要记住的是,尽管这些函数看起来像作用在整个流上一样,但事实上每个 DStream 在内部是由许多 RDD(批次)组成,且无状态转化操作是分别应用到每个 RDD 上的。
  例如:reduceByKey()会归约每个时间区间中的数据,但不会归约不同区间之间的数据。

4.1.1 Transform

  Transform 允许 DStream 上执行任意的 RDD-to-RDD 函数。即使这些函数并没有在 DStream的 API 中暴露出来,通过该函数可以方便的扩展 Spark API。该函数每一批次调度一次。其实也就是对 DStream 中的 RDD 应用转换。

object Transform {
 def main(args: Array[String]): Unit = {
 //创建 SparkConf
 val sparkConf: SparkConf = new 
SparkConf().setMaster("local[*]").setAppName("WordCount")
 //创建 StreamingContext
 val ssc = new StreamingContext(sparkConf, Seconds(3))
 //创建 DStream
 val lineDStream: ReceiverInputDStream[String] = ssc.socketTextStream("linux1", 
9999)
 //转换为 RDD 操作
 val wordAndCountDStream: DStream[(String, Int)] = lineDStream.transform(rdd => 
{
 val words: RDD[String] = rdd.flatMap(_.split(" "))
 val wordAndOne: RDD[(String, Int)] = words.map((_, 1))
 val value: RDD[(String, Int)] = wordAndOne.reduceByKey(_ + _)
 value
 })
 //打印
 wordAndCountDStream.print
 //启动
 ssc.start()
 ssc.awaitTermination()
 }
}

4.1.2 join

  两个流之间的 join 需要两个流的批次大小一致,这样才能做到同时触发计算。计算过程就是对当前批次的两个流中各自的 RDD 进行 join,与两个 RDD 的 join 效果相同。

import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
object JoinTest {
 def main(args: Array[String]): Unit = {
 //1.创建 SparkConf
 val sparkConf: SparkConf = new 
SparkConf().setMaster("local[*]").setAppName("JoinTest")
 //2.创建 StreamingContext
 val ssc = new StreamingContext(sparkConf, Seconds(5))
 //3.从端口获取数据创建流
 val lineDStream1: ReceiverInputDStream[String] = 
ssc.socketTextStream("linux1", 9999)
 val lineDStream2: ReceiverInputDStream[String] = 
ssc.socketTextStream("linux2", 8888)
 //4.将两个流转换为 KV 类型
 val wordToOneDStream: DStream[(String, Int)] = lineDStream1
 .flatMap(_.split(" ")).map((_, 1))
 val wordToADStream: DStream[(String, String)] = lineDStream2
 .flatMap(_.split(" ")).map((_, "a"))
 //5.流的 JOIN
 val joinDStream: DStream[(String, (Int, String))] = 
wordToOneDStream.join(wordToADStream)
 //6.打印
 joinDStream.print()
 //7.启动任务
 ssc.start()
 ssc.awaitTermination()
 }
}

4.2 有状态转化操作

4.2.1 UpdateStateByKey

  UpdateStateByKey 原语用于记录历史记录,有时,我们需要在 DStream 中跨批次维护状态(例如流计算中累加 wordcount)。针对这种情况,updateStateByKey()为我们提供了对一个状态变量的访问,用于键值对形式的 DStream。给定一个由(键,事件)对构成的 DStream,并传递一个指
定如何根据新的事件更新每个键对应状态的函数,它可以构建出一个新的 DStream,其内部数
据为(键,状态) 对。
  updateStateByKey() 的结果会是一个新的 DStream,其内部的 RDD 序列是由每个时间区间对应的(键,状态)对组成的。
  updateStateByKey 操作使得我们可以在用新信息进行更新时保持任意的状态。为使用这个功能,需要做下面两步:
  1. 定义状态,状态可以是一个任意的数据类型。
  2. 定义状态更新函数,用此函数阐明如何使用之前的状态和来自输入流的新值对状态进行更新。
  使用 updateStateByKey 需要对检查点目录进行配置,会使用检查点来保存状态。
  更新版的 wordcount
 如下代码:

object WorldCount {
 def main(args: Array[String]) {
 // 定义更新状态方法,参数 values 为当前批次单词频度,state 为以往批次单词频度
 val updateFunc = (values: Seq[Int], state: Option[Int]) => {
 val currentCount = values.foldLeft(0)(_ + _)
 val previousCount = state.getOrElse(0)
 Some(currentCount + previousCount)
 }
 val conf = new 
SparkConf().setMaster("local[*]").setAppName("NetworkWordCount")
 val ssc = new StreamingContext(conf, Seconds(3))
 //有状态一定要检查点
 ssc.checkpoint("./ck")
 // Create a DStream that will connect to hostname:port, like hadoop102:9999
 val lines = ssc.socketTextStream("linux1", 9999)
 // Split each line into words
 val words = lines.flatMap(_.split(" "))
 //import org.apache.spark.streaming.StreamingContext._ // not necessary since 
Spark 1.3
 // Count each word in each batch
 val pairs = words.map(word => (word, 1))
 // 使用 updateStateByKey 来更新状态,统计从运行开始以来单词总的次数
 val stateDstream = pairs.updateStateByKey[Int](updateFunc)
 stateDstream.print()
 ssc.start() // Start the computation
 ssc.awaitTermination() // Wait for the computation to terminate
 //ssc.stop()
 }
}

(2) 启动程序并向 9999 端口发送数据

nc -lk 9999
Hello World
Hello Scala

(3) 结果展示

-------------------------------------------
Time: 1504685175000 ms
-------------------------------------------
-------------------------------------------
Time: 1504685181000 ms
-------------------------------------------
(shi,1)
(shui,1)
(ni,1)
-------------------------------------------
Time: 1504685187000 ms
-------------------------------------------
(shi,1)
(ma,1)
(hao,1)
(shui,1)

4.2.2 WindowOperations

  Window Operations 可以设置窗口的大小和滑动窗口的间隔来动态的获取当前 Steaming 的允许
状态。所有基于窗口的操作都需要两个参数,分别为窗口时长以及滑动步长。
 ➢ 窗口时长:计算内容的时间范围;
 ➢ 滑动步长:隔多久触发一次计算。
注意:这两者都必须为采集周期大小的整数倍。
WordCount 第三版:3 秒一个批次,窗口 12 秒,滑步 6 秒。

object WorldCount {
 def main(args: Array[String]) {
 val conf = new 
SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")
 val ssc = new StreamingContext(conf, Seconds(3))
 ssc.checkpoint("./ck")
 // Create a DStream that will connect to hostname:port, like localhost:9999
 val lines = ssc.socketTextStream("linux1", 9999)
 // Split each line into words
 val words = lines.flatMap(_.split(" "))
// Count each word in each batch
 val pairs = words.map(word => (word, 1))
 val wordCounts = pairs.reduceByKeyAndWindow((a:Int,b:Int) => (a + 
b),Seconds(12), Seconds(6))
 // Print the first ten elements of each RDD generated in this DStream to the 
console
 wordCounts.print()
 ssc.start() // Start the computation
 ssc.awaitTermination() // Wait for the computation to terminate
 }
}

关于 Window 的操作还有如下方法:
(1)window(windowLength, slideInterval): 基于对源 DStream 窗化的批次进行计算返回一个
新的 Dstream;
(2)countByWindow(windowLength, slideInterval): 返回一个滑动窗口计数流中的元素个数;
(3)reduceByWindow(func, windowLength, slideInterval): 通过使用自定义函数整合滑动区间
流元素来创建一个新的单元素流;
(4)reduceByKeyAndWindow(func, windowLength, slideInterval, [numTasks]): 当在一个(K,V)
对的 DStream 上调用此函数,会返回一个新(K,V)对的 DStream,此处通过对滑动窗口中批次数
据使用 reduce 函数来整合每个 key 的 value 值。
(5)reduceByKeyAndWindow(func, invFunc, windowLength, slideInterval, [numTasks]): 这个函
数是上述函数的变化版本,每个窗口的 reduce 值都是通过用前一个窗的 reduce 值来递增计算。
通过 reduce 进入到滑动窗口数据并”反向 reduce”离开窗口的旧数据来实现这个操作。一个例子是随着窗口滑动对 keys 的“加”“减”计数。通过前边介绍可以想到,这个函数只适用于”可逆的 reduce 函数”,也就是这些 reduce 函数有相应的”反 reduce”函数(以参数 invFunc 形式传入)。如前述函数,reduce 任务的数量通过可选参数来配置。
在这里插入图片描述

val ipDStream = accessLogsDStream.map(logEntry => (logEntry.getIpAddress(), 1))
val ipCountDStream = ipDStream.reduceByKeyAndWindow(
 {(x, y) => x + y},
 {(x, y) => x - y},
 Seconds(30),
 Seconds(10))
 //加上新进入窗口的批次中的元素 //移除离开窗口的老批次中的元素 //窗口时长// 滑动步长

  countByWindow()和 countByValueAndWindow()作为对数据进行计数操作的简写。
  countByWindow()返回一个表示每个窗口中元素个数的 DStream,而 countByValueAndWindow()返回的 DStream 则包含窗口中每个值的个数。

val ipDStream = accessLogsDStream.map{entry => entry.getIpAddress()}
val ipAddressRequestCount = ipDStream.countByValueAndWindow(Seconds(30), 
Seconds(10)) 
val requestCount = accessLogsDStream.countByWindow(Seconds(30), Seconds(10))

第 5 章 DStream 输出

  输出操作指定了对流数据经转化操作得到的数据所要执行的操作(例如把结果推入外部数据库或输出到屏幕上)。与 RDD 中的惰性求值类似,如果一个 DStream 及其派生出的 DStream 都没有被执行输出操作,那么这些 DStream 就都不会被求值。如果 StreamingContext 中没有设定输出操作,整个context 就都不会启动。
输出操作如下:
 ➢ print():在运行流程序的驱动结点上打印 DStream 中每一批次数据的最开始 10 个元素。这
用于开发和调试。在 Python API 中,同样的操作叫 print()。
 ➢ saveAsTextFiles(prefix, [suffix]):以 text 文件形式存储这个 DStream 的内容。每一批次的存
储文件名基于参数中的 prefix 和 suffix。”prefix-Time_IN_MS[.suffix]”。
 ➢ saveAsObjectFiles(prefix, [suffix]):以 Java 对象序列化的方式将 Stream 中的数据保存为
SequenceFiles . 每一批次的存储文件名基于参数中的为"prefix-TIME_IN_MS[.suffix]“. Python中目前不可用。
 ➢ saveAsHadoopFiles(prefix, [suffix]):将 Stream 中的数据保存为 Hadoop files. 每一批次的存储文件名基于参数中的为"prefix-TIME_IN_MS[.suffix]”。Python API 中目前不可用。
 ➢ foreachRDD(func):这是最通用的输出操作,即将函数 func 用于产生于 stream 的每一个
RDD。其中参数传入的函数 func 应该实现将每一个 RDD 中数据推送到外部系统,如将RDD 存入文件或者通过网络将其写入数据库。
  通用的输出操作 foreachRDD(),它用来对 DStream 中的 RDD 运行任意计算。这和 transform() 有些类似,都可以让我们访问任意 RDD。在 foreachRDD()中,可以重用我们在 Spark 中实现的所有行动操作。比如,常见的用例之一是把数据写到诸如 MySQL 的外部数据库中。
注意:
 1) 连接不能写在 driver 层面(序列化)
 2) 如果写在 foreach 则每个 RDD 中的每一条数据都创建,得不偿失;
 3) 增加 foreachPartition,在分区创建(获取)。
  

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
上百节课详细讲解,需要的小伙伴自行百度网盘下载,链接见附件,永久有效。 课程介绍: 讲解一个真实的、复杂的大型企业级大数据项目,是Spark的大型项目实战课程。 通过本套课程的学习,可以积累大量Spark项目经验,迈入Spark高级开发行列。 课程特色: 1、项目中全面覆盖了Spark Core、Spark SQL和Spark Streaming个技术框架几乎全部的初级和高级的技术点和知识点, 让学员学以致用,通过一套课程,即掌握如何将Spark所有的技术点和知识点应用在真实的项目中,来实现业务需求! 2、项目中的4个功能横块,全郃是实际企业项目中提取出来的,并进行技术整合和改良过的功能模块.全都是企业级的复杂和真实的需求,业务模块非常之复杂,绝对不是市面上的Dem级别的大数据项目能够想比拟的,学习过后,真正帮助学员增加实际 企业级项目的实战经验。 3、项目中通过实际的功能模块和业务场景,以及讲师曾经开发过的处理十亿、甚至百亿以上数据级别的SparK作业的经验积累,贯穿讲解了大量的高级复杂的性能调优技术和知识、troubleshooting解决线上报错和故障的经验、高端的全方位数据倾斜处理和解决方案.真正帮助学员掌握高精尖的Spark技术! 4、项目中采用完全还原企业大数据项目开发场景的方式来讲解,每一个业务模块的讲解都包括了需求分析、方案设计、数据设计、编码实现、功能测试、性能调优等环节,真实还原企业级大数据项目开发场景。 模块简介: 1、用户访问session分析,该模块主要是对用户访问session进行统计分析.包括session的聚合指标计算、 按时间比例随机抽取session、获取每天点击、下单和购买排名前10的品类、并获取top10品类的点击量排名前10的session.该模块可以让产品经理、数据分析师以及企业管理层形象地看到各种条件下的具体用户行为以及统计指标.从而对公司的产品设计以及业务发展战略做出调整.主要使用Spark Core实现. 2、页面单跳转化率统计,该模块主要是计算关键页面之间的单步跳转转化率,涉及到页面切片算法以及页面流匹配算法.该模块可以让产品经理、数据分析师以及企业管理层看到各个关键页面之间的转化率.从而对网页布局,进行更好的优化设计。主要使用Spark Core实现. 3、热门商品离线统计,该模块主要实现每天统计出各个区域的top3热门商品.然后使用Oozie进行离线统计任务的定时调度,使用Zeppeline进行数据可视化的报表展示.该模块可以让企业管理层看到公司售卖的 商品的整体情况,从而对公司的商品相关的战略进行调螫.主要使用Spark SQL实现。 4、广告流量实时统计.该模块负责实时统计公司的广告流量.包括广告展现流量和广告点击流量,实现动态黑名单机制以及黑名单过滤,实现滑动窗口内的各城市的广告展现流立和广告点击流直的统计,实现 每个区域诲个广告的点击流置实时统计,实现每个区域top3点击量的广告的统计,主要使用Spark Streaming实现.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Red-P

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值