sparkStreaming

本文深入探讨Spark Streaming的核心概念,包括DStream、Receiver、Transformation和OutputOperation,同时提供IDEA环境下Spark Streaming的pom配置示例,并通过代码展示如何实现文件流的词频统计、带状态的更新函数UpdateStateByKey以及基于窗口的统计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

核心概念

DStream

Receiver

Transformation

Output Operation

IDEA搭建SparkStreaming环境的pom文件

带状态的算子:UpdateStateByKey

基于window的统计


核心概念

SparkStreaming可以简单的理解为 StreamingContext将数据按照时间分为很多小的RDD,然后再交给Spark处理这一个个的RDD。

DStream

对DStream做操作,其实质就是对一系列的RDD做相同的操作。 

Receiver

每一个inputDStream【除了文件流】 关联一个 Receiver对象【负责接受源头的数据并存储在spark的内存中】

注意:Receiver启动会占用一个线程,所以这时候不能使用master("local[1]")

Transformation

    map(func)、filter(func)、flatMap(func)、reductByKey(func, [numTasks])

    注意:流式计算中,reduce(func)、count()都是Transformation,统计出source DStream中的每个微批RDD的聚合结果和个数。

Output Operation

 

IDEA搭建SparkStreaming环境的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.kylin.sparkstreaming</groupId>
  <artifactId>sparkstreaming</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spark.version>2.2.3</spark.version>
    <scala.version>2.11</scala.version>
    <hadoop.version>2.7.6</hadoop.version>
    <hbase.version>1.4.8</hbase.version>
    <kafka.version>1.1.1</kafka.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-library</artifactId>
      <version>2.11.12</version>
    </dependency>
    <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-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-streaming_${scala.version}</artifactId>
      <version>${spark.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-client</artifactId>
      <version>2.7.6</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-client</artifactId>
      <version>${hbase.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-server</artifactId>
      <version>${hbase.version}</version>
    </dependency>
    <!-- 从此文档获取:http://spark.apache.org/docs/2.2.3/streaming-programming-guide.html -->
    <dependency>
      <groupId>org.apache.spark</groupId>
      <artifactId>spark-streaming-kafka-0-8_${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.kafka</groupId>
      <artifactId>kafka_2.11</artifactId>
      <version>${kafka.version}</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.41</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
  </dependencies>

  <!-- maven官方 http://repo1.maven.org/maven2/  或 http://repo2.maven.org/maven2/ (延迟低一些) -->
  <repositories>
    <repository>
      <id>central</id>
      <name>Maven Repository Switchboard</name>
      <layout>default</layout>
      <url>http://repo2.maven.org/maven2</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

  <build>
    <sourceDirectory>src/main/scala</sourceDirectory>
    <testSourceDirectory>src/test/scala</testSourceDirectory>

    <plugins>
      <plugin>
        <!--maven scala插件-->
        <groupId>org.scala-tools</groupId>
        <artifactId>maven-scala-plugin</artifactId>
        <version>2.15.2</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>testCompile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <!-- MAVEN 编译使用的JDK版本 -->
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

测试代码如下:

object FileWordCount {
  def main(args: Array[String]): Unit = {
    // 必须使用流的形式,才能读取到文件内容,如果windows下直接拷贝粘贴是不行的
    // cp 123.txt data/   而且对同一个文件修改也是不会再次被读取到的
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("file_word_count")
    val ssc = new StreamingContext(sparkConf, Seconds(5))
    val lines = ssc.textFileStream("file:///G:\\data\\")
    val result = lines.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
    result.print()

    ssc.start()
    ssc.awaitTermination()
  }
}

带状态的算子:UpdateStateByKey

需求:统计到目前为止累计出现的单词数量。

注意:

  1. updateStateByKey算子需要传入一个函数【输入:当前值、以前值 】
  2. 以前的状态必须存放在checkpoint指定的路径。
object StatefulFileWordCount {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("file_word_count")
    val ssc = new StreamingContext(sparkConf, Seconds(5))
    // 如果使用了带状态的算子,必须设置checkpoint存放以前的状态
    ssc.checkpoint(".")

    val lines = ssc.textFileStream("file:///G:/data")
    val result = lines.flatMap(_.split(" ")).map((_, 1))
    val state = result.updateStateByKey(updateFunction _) // 隐式转换
    state.print()

    ssc.start()
    ssc.awaitTermination()
  }

  def updateFunction(currentValues: Seq[Int], preValues: Option[Int]):Option[Int] = {
    val current = currentValues.sum
    val pre = preValues.getOrElse(0)
    Some(current + pre)
  }
}

进阶:将单词数量统计写入MySQL中

思路:使用 foreachRDD算子,

 

基于window的统计

window:进行一个时间段内的数据处理。   与 window length和sliding interval2个参数有关。

举例:每个10秒计算前10分钟的wordcount,此处sliding interval是10秒,window length是10分钟。

 

RDD和DStream进行join

通过 DStream的transform(rdd=>{  rdd.leftjoin(RDD) })

举例:黑名单过滤,一般黑名单存在数据库中,通过外部数据源可以得到一个静态的RDD,此处我们直接存到内存中,方便试验。blacksRDD通过map将里面的每个记录后面添加一个true,每次通过DStream中的rdd和blacksRDD进行左外连接,通过过滤出是false,即可过滤掉黑名单,只显示除了黑名单之外的人。

import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}

object TransformApp {
  // 测试是必须通过cp命令或mv命令才可以,往文件中追加内容是不行的
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("transform")
    val ssc = new StreamingContext(sparkConf, Seconds(5))
    // 构建黑名单 一般是从数据库得到 此处简化为存在内存中
    // blacksRDD : [<"zs" :true>, <"ls" :true>]
    val blacks = List("zs", "ls")
    val blacksRDD = ssc.sparkContext.parallelize(blacks).map(x => (x, true))

    val lines = ssc.textFileStream("file:///G:/data/test")
    // 每一行数据格式:20180502,zs,20 --> <zs: 20180502,zs,20>
    val clicklog = lines.map(x => (x.split(",")(1), x))
      .transform(rdd => {
        rdd.leftOuterJoin(blacksRDD)
          .filter(x => x._2._2.getOrElse(false) != true)
          .map(x => x._2._1)
      })
    clicklog.print()

    ssc.start()
    ssc.awaitTermination()
  }
}

Sparkstreaming整合SparkSQL

foreachRDD算子中func的入参是一个一个小的rdd,每个rdd即可转换为DataFrame

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值