横扫Spark之 - 22个常见的转换算子

水善利万物而不争,处众人之所恶,故几于道💦

文章目录

      • 1. map()
      • 2. flatMap()
      • 3. filter()
      • 4. mapPartitions()
      • 5. mapPartitionsWithIndex()
      • 6. groupBy()
      • 7. distinct()
      • 8. coalesce()
      • 9. repartition()
      • 10. sortBy()
      • 11. intersection()
      • 12.union()
      • 13. subtract()
      • 14. zip()
      • 15. partitionBy()
      • 16. groupByKey()
      • 17. reduceByKey()
      • 18. aggregateByKey()()
      • 19. sortByKey()
      • 20. mapValues()
      • 21. join()
      • 22. cogroup()

1. map()

  用于对数据进行映射转换,返回一个新的RDD
  操作的是RDD中的每个元素
例:创建一个List集合的RDD,将其中的每个数字映射为二元元组,(“偶数”, 4)、(“奇数”, 1)这样的形式

  @Test
  def map(): Unit ={
    // 创建一个RDD,2个分区
    val rdd1 = sc.parallelize(List(1, 4, 6, 7),2)
		// 使用map()转换结构
    val rdd2 = rdd1.map(x => {
      if (x % 2 == 0)
        ("偶数", x)
      else ("奇数", x)
    })
		// 遍历RDD并打印
    rdd2.foreach(println)
  }

运行结果:
在这里插入图片描述

2. flatMap()

  转化+压平操作,先对RDD中的每个元素进行转换,然后将转换的结果(数组、列表等)进行压平,返回一个新的RDD
  操作的单位是RDD中的每个元素
例:将RDD中的元素进行切割,然后进行扁平化处理:

@Test
def flatMap(): Unit ={

  val rdd1 = sc.parallelize(List("spark,scala", "python,java", "hadoop,java"),3)

  val rdd2 = rdd1.flatMap(x=>{
    // 切割后的每个元素都是一个数组,然后将多个数组进行扁平化处理
    x.split(",")
  })
// 将扁平化后的结果数组,收集到Driver端,转成List然后打印(不转换为List也能打印,只不过打印的是地址值,没有重写toString方法)
  println(rdd2.collect().toList)
}

结果:
在这里插入图片描述

3. filter()

  过滤数据,参数是一个返回值是Boolean类型的函数,将返回为true的元素保留
  操作的单位是每一个元素
例:过滤出RDD中奇数元素

@Test
def filter(): Unit ={

  val rdd1 = sc.parallelize(List(1, 2, 3, 4, 7, 8))

  val rdd2: RDD[Int] = rdd1.filter(x => {
  // 过滤奇数
    x % 2!=0
  })

  println(rdd2.collect().toList)
}

结果:
在这里插入图片描述

4. mapPartitions()

  以分区为单位,执行map,它拿到的是一个分区内所有数据的迭代器对象(iterator类型的迭代器),你要遍历这个迭代器对象才能拿到这个分区里面的每个数据
  这个的应用场景一般是读取数据库操作的时候用,可以减少数据库连接的创建、销毁次数,提高效率
  普通的map是一个元素一个元素的操作,如果操作每个元素的时候都创建、销毁一次数据库连接,效率太差了,可以在每个分区创建一个连接,分区内的数据操作都用这一个连接,然后处理数据,并以批的形式执行操作这样效率比较高。
  为啥不能将数据库的连接抽取出来在map函数外面创建,map里面使用连接?因为函数体外的代码是在Driver执行的(Driver负责执行main方法),函数体内处理数据的逻辑是在Executor中task去执行的task和Driver不在一台机器上,如果task想用Driver上的对象,就要Driver把这个对象通过网络传给task,网络传递肯定要序列化,执行sql的PrepareStatement对象是根本没有继承序列化接口,无法序列化,所以就会报错

例:RDD里的是学生id,要求从数据库中查出学生姓名和家庭住址并打印 - (3,test3,陕西)
map写法:

    @Test
    def map(): Unit = {
    //  学生id
      val rdd1 = sc.parallelize(List(1, 3, 5, 77, 6, 34))
			// 对每个元素进行操作
      val rdd2 = rdd1.map(id=>{

        var connection: Connection = null
        var statement:PreparedStatement = null
        var name:String = null
        var address:String = null
        try{
	// 在map()函数体里面创建连接对象,因为map()是针对每个元素进行操作的,
  //	所以处理每个元素的时候都会进行连接的创建、销毁,效率低的要命
          connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123456")
          statement = connection.prepareStatement("select id,name,address from student where id=?")
          statement.setInt(1,id)
          val resultSet = statement.executeQuery()
          while (resultSet.next()) {
            name = resultSet.getString("name")
            address = resultSet.getString("address")
          }

        }catch {
          case e:Exception => e.printStackTrace()
        }finally {
          if (connection != null) {
            connection.close()
          }
          if (statement != null) {
            statement.close()
          }
        }

        (id,name,address)
      })

      println(rdd2.collect().toList)
    }

mapPartitions写法:

  @Test
  def mapPartitions(): Unit = {

    val rdd1 = sc.parallelize(List(1, 3, 5, 77, 6, 34))
    // 每个分区进行操作
    val rdd2 = rdd1.mapPartitions(idIterator => {
			// 每个分区创建一个对象
      var connection: Connection = null
      var statement: PreparedStatement = null
      // 将查到的数据缓存起来
      val listBuffer: ListBuffer[(Int, String, String)] = ListBuffer[(Int, String, String)]()
      try {
				// 这个连接对象在每个分区只会创建一次
        connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456")
        statement = connection.prepareStatement("select id,name,address from student where id=?")
        println(connection)
        var name: String = null
        var address: String = null

        // idIterator.map(id=>{ 不能用map,因为用statement的时候连接已经被关闭了   
        // map()是转换算子,是延迟执行的,执行到这的时候还没有执行,而main方法已经把连接关闭了
        idIterator.foreach(id => {

          statement.setInt(1, id)
          val resultSet = statement.executeQuery()
          while (resultSet.next()) {
            name = resultSet.getString("name")
            address = resultSet.getString("address")
          }
          listBuffer += ((id, name, address))
        })

      } catch {
        case e: Exception => e.printStackTrace()
      } finally {
        if (connection != null) {
          connection.close()
        }
        if (statement != null) {
          statement.close()
        }
      }

      listBuffer.toIterator
    })

    println(rdd2.collect().toList)
  }

结果:
在这里插入图片描述

5. mapPartitionsWithIndex()

  和mapPartitions()类似,只不过它可以取到分区号
例:rdd1设置为2个分区,打印分区号和每个分区内的数据

  @Test
  def mapPartitionsWithIndex(): Unit = {

    val rdd1 = sc.parallelize(List(1, 3, 99, 56, 76, 7), 2)

    val rdd2 = rdd1.mapPartitionsWithIndex((index, iterator) => {
      println(s"分区号: ${index} === 区内数据:${iterator.toList}")
      iterator
    })

    // 这个为啥输出空,是因为iterator迭代器只能调用一次,用过后里面就没有数据了  前面println的时候已经toList()用过了,所以后面返回的iterator本来就是个空的....
    println(rdd2.collect().toList)
  }

结果:
在这里插入图片描述  这个为啥输出空,是因为iterator迭代器只能调用一次,用过后里面就没有数据了 前面println的时候已经toList()用过了,所以后面返回的iterator本来就是个空的…

6. groupBy()

  通过传入函数的参数进行分组,分组后的value还是完整的整个元素
例:按照三元元组中第三个元素进行分组

  @Test
  def groupBy(): Unit = {
    val rdd1 = sc.parallelize(List(("zhangsan", "man", "beijing"), ("lisi", "woman", "xian"), ("zhaoliu", "man", "xian")))

    val rdd2 = rdd1.groupBy(_._3)

    println(rdd2.collect().toList)
  }

结果:
在这里插入图片描述

7. distinct()

  对RDD中的元素进行去重,返回一个去重后的RDD,新的RDD默认的分区数与原RDD分区数相同,也可以指定新RDD的分区数
  去重也可以用groupBy实现,直接按照元素分组,然后把元组中的第一个元素取出来就是去重后的结果

  @Test
  def distinct(): Unit = {

    val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5, 3, 2, 1, 1))

        val rdd2 = rdd1.distinct()

/*
    val rdd3 = rdd1.groupBy(w => w)

    val rdd4 = rdd3.map(_._1)
*/

    println(rdd2.collect().toList)
  }

结果:
在这里插入图片描述

8. coalesce()

  合并分区,不会走shuffle,分区数比原来的小才能生效,如果想要将分区变多,要开启第二个参数,它会走shuffle将分区变多
  

  @Test
  def coalesce(): Unit = {
		// 将算子分区数设置为6个分区
    val rdd1 = sc.parallelize(List(3, 454, 566, 7, 5657, 6734545, 4, 5), 6)
	// 将分区合并为4个
//    val rdd2 = rdd1.coalesce(4)
    val rdd2 = rdd1.coalesce(8,true)

    println(rdd2.collect().toList)

    Thread.sleep(900000000)

  }

结果:通过web页面查看,可以看到分区变为了8个
在这里插入图片描述

9. repartition()

  重分区,它可以增大或者减少分区数,它底层调用的就是coalesce() 只不过把是否shuffle恒设置为了true
  

  @Test
  def repartition(): Unit = {

    val rdd1 = sc.parallelize(List(2, 3, 4, 5, 6, 3, 3, 4, 5, 4), 4)

    val rdd2 = rdd1.repartition(6)

    println(s"rdd1分区数:${rdd1.getNumPartitions}\nrdd2分区数:${rdd2.getNumPartitions}")

  }

结果:
在这里插入图片描述

10. sortBy()

  排序,默认升序排序,他会走shuffle,它使用的分区器是RangePartitioner

  @Test
  def sortBy(): Unit = {

    val rdd1 = sc.parallelize(List(1, 4, 5, 6, 7, 4, 2, 2, 5, 7, 8), 6)
// 第二个参数默认是true,也就是升序排序,降序的话就false
    val rdd2 = rdd1.sortBy(x => x, false) 

    println(rdd2.collect().toList)
  }

结果:
在这里插入图片描述

11. intersection()

  交集,取两个RDD的相同元素,会有两次shuffle,因为要想取出交集,就要把相同的元素聚在一起才能知道有没有相同的元素,那就rdd1落盘,rdd2落盘,然后rdd3再把两个数据拉过来,所以有两次shuffle

  @Test
  def intersection(): Unit = {

    val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5), 6)
    val rdd2 = sc.parallelize(List(4, 5, 6, 7, 8), 4)

    val rdd3 = rdd1.intersection(rdd2)

    println(rdd3.collect().toList)

    Thread.sleep(10000000)
  }

结果:
在这里插入图片描述

12.union()

  并集,并集没有shuffle,他只是单纯的将两个RDD的数据放到一起,不关心有没有相同的数据。新RDD的分区数是原来两个RDD分区数之和

  @Test
  def union(): Unit = {

    val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5), 5)
    val rdd2 = sc.parallelize(List(4, 5, 6, 7, 8), 4)

    val rdd3 = rdd1.union(rdd2)

    println(rdd3.collect().toList)
    println(rdd3.getNumPartitions) // 并集的分区数是两个RDD集合的分区数之和

    Thread.sleep(10000000)
  }

结果:
在这里插入图片描述

13. subtract()

  差集合,它会产生shuffle,取方法调用者的分区数,因为衍生RDD的分区数取决于依赖的第一个RDD的分区数

  @Test
  def subtract(): Unit = {

    val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5), 3)
    val rdd2 = sc.parallelize(List(4, 5, 6, 7, 8), 4)

    val rdd3 = rdd1.subtract(rdd2)

    println(rdd3.collect().toList)
    println(rdd3.getNumPartitions) //取方法调用者的分区数,衍生RDD的分区数取决于依赖的第一个RDD的分区数

    Thread.sleep(10000000)
  }

结果:
在这里插入图片描述

14. zip()

  拉链,spark中的拉链要求两个RDD的分区数和数据条数都必须一样才能拉起来
  

  @Test
  def zip(): Unit = {

    val rdd1 = sc.parallelize(List("hello", "spark", "xian", "beijign"), 5)
    val rdd2 = sc.parallelize(List(1, 2, 3, 4), 5)

    val rdd3 = rdd1.zip(rdd2)

    println(rdd3.collect().toList)

  }

结果:
在这里插入图片描述

15. partitionBy()

  它的参数是一个分区器,按照给定的分区器重新分区。注意他这个要求操作的RDD必须是k-v键值对才能使用
  

  @Test
  def partitionBy(): Unit = {

    val rdd1 = sc.parallelize(List(1, 3, 4, 5, 6, 7, 9), 4)
    //    4个分区,集合长度为7            0: (0*7)/4 - (1*7)/4  =>  0-1   => 1
    //                                1: (1*7)/4 - (2*7)/4  =>  1-3   => 3 4
    //                                2: 3 - (3*7)/4        =>  3-5   => 5 6
    //                                3: 5 - (4*7)/4        =>  5-6   => 7 9
    //

    val rdd2 = rdd1.map(x => {
      (x, null)
    })

    val rdd3 = rdd2.partitionBy(new HashPartitioner(5))
    //                                                        1%5 = 1 1在1号分区
    //                                                        3%5 = 3
    //
    //                  0:  5
    //                  1: 1  6
    //                  2: 7
    //                  3: 3
    //                  4:  4  9
    //
    rdd3.mapPartitionsWithIndex((index, it) => {
      println(s"${index} ==  ${it.toList}")
      it
    }).collect()
  }

结果:
在这里插入图片描述

16. groupByKey()

  根据key分组,返回的新的RDD是KV键值对,value是所有key相同的value值。会走shuffle
  

  @Test
  def groupByKey(): Unit = {

    val rdd1 = sc.parallelize(List(("spark", 200), ("spark", 10), ("hadoop", 700), ("scala", 50), ("flink", 90000)), 3)

    val rdd2 = rdd1.groupByKey(2)

//    println(rdd2.getNumPartitions)

    rdd2.mapPartitionsWithIndex((index, it) => {
      println(s"groupByKey:  ${index} == ${it.toList}")
      it
    }).collect()

    // groupBy实现groupByKey的功能
    val rdd3 = rdd1.groupBy(x => x._1)
    val rdd4 = rdd3.map(y => (y._1, y._2.map(z => z._2)))
    rdd4.mapPartitionsWithIndex((index,it)=>{
      println(s"groupBy:  ${index} == ${it.toList}")
      it
    }).collect()

  }

结果:
在这里插入图片描述

17. reduceByKey()

  参数是一个函数参数,函数有两个参数,分别表示当前value的聚合结果和待聚合的value值
  

  @Test
  def reduceByKey(): Unit ={
//       wc.txt
//       hello bigdata
//       spark flink
//       hbase hadoop spark flink

    val rdd1 = sc.textFile("datas/wc.txt")

    val rdd2 = rdd1.flatMap(line => line.split(" "))

    val rdd3 = rdd2.map((_, 1))

    // reduceByKey()的函数的两个参数的含义是当前value的聚合结果和待聚合的value
    val rdd4 = rdd3.reduceByKey((agg, cur) => agg + cur)

    println(rdd4.collect().toList)

  }

结果:
在这里插入图片描述

18. aggregateByKey()()

  聚合规约,他和ReduceByKey的区别是这个他的combiner逻辑和reduce的逻辑可以不一样,ReduceByKey的combiner逻辑和reduce逻辑一样
  分区内combiner的逻辑和分区间reduce的逻辑不一样

  aggregateByKey(a)(b,c)  柯里化形式
  第一个参数列表a是默认值
       第二个参数列表有两个参数:
              b参数是combiner逻辑,他有两个参数,第一个参数是上次聚合的结果,第一次聚合时候的初始值=默认值
                                            第二个参数是当前分组中等待聚合的value的值!!!
              c参数是最终reduce的逻辑,他也有两个参数,第一个参数是该组上一次的聚合结果,第一次聚合的值=第一个value的值
                                                第二个参数是当前分组中待聚合的value值
  @Test
  def aggregateByKey(): Unit ={

    val rdd1 = sc.textFile("datas/stu_score.txt")

    val rdd2 = rdd1.map(line => {
      val arr = line.split(" ")
      val name = arr(1)
      val score = arr(2).toInt
      (name, score)
    })
    //    默认值是(0,0)表示课程成绩为0 ,次数为0次
    val rdd3 = rdd2.aggregateByKey((0, 0))(
      // combiner的逻辑,agg是上次combiner的结果,刚开始的时候等于刚才设置的默认值;curValue是当前分组中等待聚合的value的值也就是score成绩
      (agg, curValue) => {
        // 将成绩和当前待聚合的成绩累加,次数标记+1
        (agg._1 + curValue, agg._2 + 1)
      },
      // 这里就是reduce的逻辑,也就是combiner聚合后的结果最终的reduce
      // agg是以前预聚合的结果,cur是当前的结果  ,需要进行成绩的累加和次数的累加
      (agg, cur) => {
        (agg._1 + cur._1, agg._2 + cur._2)
      })

    val rdd4 = rdd3.map(x => {
      (x._1, x._2._1 / x._2._2)
    })

    println(rdd4.collect().toList)
  }

结果:
在这里插入图片描述

19. sortByKey()

  通过key排序,默认升序,这个可以用sortBy代替

  @Test
  def sortByKey(): Unit ={

    val rdd1 = sc.parallelize(List(6, 12, 4, 6, 8, 2, 4, 89, 1))

    val rdd2 = rdd1.map((_, null))

    val rdd3 = rdd2.sortByKey(false)

    val rdd4 = rdd2.sortBy(_._1, false)

    println(rdd3.collect().toList)
    println(rdd4.collect().toList)
    
  }

结果:
在这里插入图片描述

20. mapValues()

  对value进行操作,这个也比较局限,可以用map代替

  @Test
  def mapValues(): Unit ={

    val rdd1 = sc.parallelize(List("xian" -> 10, "beijing" -> 40, "shanghai" -> 60, "qcln" -> 100))

    val rdd2 = rdd1.mapValues(_ / 10)

    val rdd2_1 = rdd1.map(x => {
      (x._1, x._2 / 10)
    })

    println(rdd2.collect().toList)
    println(rdd2_1.collect().toList)

  }

结果:
在这里插入图片描述

21. join()

  join连接,也分为内连接,左外,右外,全外

  @Test
  def join(): Unit ={

    val rdd1 = sc.parallelize(List(("aa",11),("bb",12),("aa",13),("cc",14)))
    val rdd2 = sc.parallelize(List(("aa",1.1),("cc",2.2),("dd",3.3),("cc",4.4)))

    // todo inner join = 左表和右表能够连接的数据
    val rdd3 = rdd1.join(rdd2)
    println(rdd3.collect().toList)


    // todo left join = 左表和右表能够连接的数据 + 左表不能连接的数据
    val rdd4 = rdd1.leftOuterJoin(rdd2)
    println(rdd4.collect().toList)

    // todo right join = 左表和右表能够连接的数据 + 右表不能连接的数据
    val rdd5 = rdd1.rightOuterJoin(rdd2)
    println(rdd5.collect().toList)

    // todo full join = 左表和右表能够连接的数据 + 左表和右表不能连接的数据
    val rdd6 = rdd1.fullOuterJoin(rdd2)
    println(rdd6.collect().toList)

  }

22. cogroup()

  这个相当于先对rdd1进行groupByKey然后与rdd2进行full outer join

  @Test
  def cogroup(): Unit ={

    val rdd1 = sc.parallelize(List(("aa",11),("bb",12),("aa",13),("cc",14)))
    val rdd2 = sc.parallelize(List(("aa",1.1),("cc",2.2),("dd",3.3),("cc",4.4)))

    val rdd3 = rdd1.cogroup(rdd2)
    println(rdd3.collect().toList)
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/380799.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

5G技术对物联网的影响

随着数字化转型的加速,5G技术作为通信领域的一次重大革新,正在对物联网(IoT)产生深远的影响。对于刚入行的朋友们来说,理解5G技术及其对物联网应用的意义,是把握行业发展趋势的关键。 让我们简单了解什么是…

使用python-numpy实现一个简单神经网络

目录 前言 导入numpy并初始化数据和激活函数 初始化学习率和模型参数 迭代更新模型参数(权重) 小彩蛋 前言 这篇文章,小编带大家使用python-numpy实现一个简单的三层神经网络,不使用pytorch等深度学习框架,来理解…

探索设计模式的魅力:代理模式揭秘-软件世界的“幕后黑手”

设计模式专栏:http://t.csdnimg.cn/U54zu 目录 引言 一、魔法世界 1.1 定义与核心思想 1.2 静态代理 1.3 动态代理 1.4 虚拟代理 1.5 代理模式结构图 1.6 实例展示如何工作(场景案例) 不使用模式实现 有何问题 使用模式重构示例 二、…

【Rust日报】2024-02-08 Loungy:使用 Rust 和 GPUI 开发的 MacOS 启动器

Mira Screenshare:基于 Rust 和 WebRTC 的高性能屏幕分享工具 一群大学生宣布推出了他们的期末项目:Mira Screenshare,一个开源、高性能的屏幕共享工具,由 Rust 和 WebRTC 构建。此项目支持 4k 60 FPS 和 110ms 端到端延迟的屏幕…

CS50x 2024 - Lecture 2 - Arrays

00:00:00 - Introduction 00:01:01 - Story Time 00:06:03 - Compiling make本身并不是编译器,实际上是一个自动运行编译器的程序,如c语言的clang clang -o hello hello.csrc/ $ clang -o hello hello_world.c /usr/bin/ld: /tmp/hello_world-67f51…

Oracle 面试题 | 19.精选Oracle高频面试题

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

你的立身之本是什么?

去年发生的一切,大到疫情、政治经济形势、行业的萎靡和震荡,小到身边的跳槽、裁员、公司倒闭……似乎都在告诉我们: 当冲击到来的时候,它是不会提前跟你打招呼的。 接下来的10年,我们所面临的不确定性,比起…

Linux 软件管理(YUM RPM)

1 YUM yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器。基于RPM包管理,能够从指定的服务器自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次…

fps cf游戏,一键断网辅助工具

一键断网瞬移 工具特色:一改常规断网操作(断网开启,所有人都卡住,使得还原后找不到人的问题 ),不影响任何人移动,开启断网跟着别人一起走,其他人无任何异常卡顿。 工具功能&…

Linux应用程序几种参数传递方式

大家好,今天给大家介绍Linux应用程序几种参数传递方式,文章末尾附有分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!可进群免费领取。 在Linux中,应用程序可以通过多种方式接收参数。以下…

文心一言 VS 讯飞星火 VS chatgpt (198)-- 算法导论14.3 6题

六、用go语言,说明如何来维护一个支持操作MIN-GAP的一些数的动态集Q,使得该操作能给出Q中两个最接近的数之间的差值。例如,Q(1,5,9,15,18,22),则MIN-GAP返回18-153&#…

【EAI 011】SayCan: Grounding Language in Robotic Affordances

论文标题:Do As I Can, Not As I Say: Grounding Language in Robotic Affordances 论文作者:Michael Ahn, Anthony Brohan, Noah Brown, Yevgen Chebotar, Omar Cortes, Byron David, Chelsea Finn, Chuyuan Fu, Keerthana Gopalakrishnan, Karol Hausm…

【正式】今年第一篇CSDN(纯技术教学)

一、文件上传简介 文件上传漏洞是指用户上传了一个可执行的脚本文件(木马、病毒、恶意脚本、webshell等),并通过此脚本文件获得了执行服务器端命令的能力。上传点一般出现在头像、导入数据、上传压缩包等地方,由于程序对用户上传…

C语言笔试题之求出二叉树的最大深度(递归解决)

实例要求: 1、给定一个二叉树 root ,返回其最大深度;2、二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数; 案例展示: 实例分析: 1、判断根节点是否为空;2、分别递归处理左…

物联网数据隐私保护技术

在物联网(IoT)的世界中,无数的设备通过互联网连接在一起,不断地收集、传输和处理数据。这些数据有助于提高生产效率、优化用户体验并创造新的服务模式。然而,随着数据量的剧增,数据隐私保护成为了一个不能忽…

【java苍穹外卖项目实战二】苍穹外卖环境搭建

文章目录 1、前端环境搭建2、后端环境搭建1、项目结构搭建2、Git版本控制3、数据库创建 开发环境搭建主要包含前端环境和后端环境两部分。 前端的页面我们只需要导入资料中的nginx, 前端页面的代码我们只需要能看懂即可。 1、前端环境搭建 前端运行环境的nginx&am…

《MySQL 简易速速上手小册》第7章:MySQL监控和日志分析(2024 最新版)

文章目录 7.1 配置和使用 MySQL 监控工具7.1.1 基础知识7.1.2 重点案例:使用 Python 和 Prometheus 监控 MySQL 性能7.1.3 拓展案例 1:自动化 MySQL 慢查询日志分析7.1.4 拓展案例 2:实时警报系统 7.2 解读 MySQL 日志文件7.2.1 基础知识7.2.…

【Spring】Bean 的实例化方式

Spring 为 Bean 提供了多种实例化方式,通常包括4种方式 也就是说在 Spring 中为 Bean 对象的创建准备了多种方案,目的是:更加灵活 第一种:通过构造方法实例化 第二种:通过简单工厂模式实例化 第三种:通过…

【第二届 Runway短视频创作大赛】——截至日期2024年03月01日

短视频创作大赛 关于AI Film Festival竞赛概况参加资格报名期间报名方法 提交要求奖品附录 关于AI Film Festival 2022年成立的AIFF是一个融合了最新AI技术于电影制作中的艺术和艺术家节日,让我们得以一窥新创意时代的风采。从众多参赛作品中…

求职|基于Springboot的校园求职招聘系统设计与实现(源码+数据库+文档)

校园求职招聘系统目录 目录 基于Springboot的校园求职招聘系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、企业信息管理 3、公告类型管理 4、公告信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选…