大数据学习之sparkstreaming

SparkStreaming

idea中初步实现

Spark core: SparkContext 核心数据结构:RDD

Spark sql: SparkSession 核心数据结构:DataFrame

Spark streaming: StreamingContext 核心数据结构:DStream(底层封装了RDD),遍历出其中的RDD即可进行sparkCore处理

Spark Streaming程序理论上是一旦启动,就不会停止,除非报错,人为停止,停电等其他突然场景导致程序终止

监控一个端口号中的数据,手动向端口号中打数据

master虚拟机上启动命令:nc -lk 12345

ps aux | grep ‘nc -lk 10086’ , 找出该进程的端口号,kill -9 xxxx 来终止进程

若使用指令开启端口,**退出时应选择 ctrl+c(退出并终止进程),**使用ctrl+z只能退出界面,不能关闭该端口

1、案例一:
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Duration, Durations, StreamingContext}object Demo1WordCount {def main(args: Array[String]): Unit = {val conf = new SparkConf()conf.setMaster("local[2]") // 给定核数conf.setAppName("spark Streaming 单词统计")val sparkContext = new SparkContext(conf)/*** 创建Spark Streaming的运行环境,和前两个模块是不一样的* Spark Streaming是依赖于Spark core的环境的* this(sparkContext: SparkContext, batchDuration: Duration)* Spark Streaming处理之前,是有一个接收数据的过程* batchDuration,表示接收多少时间段内的数据*/val streamingContext = new StreamingContext(sparkContext, Durations.seconds(5))/*** Spark Streaming程序理论上是一旦启动,就不会停止,除非报错,人为停止,停电等其他突然场景导致程序终止* 监控一个端口号中的数据,手动向端口号中打数据* master虚拟机上启动命令:nc -lk 12345*/val rids: ReceiverInputDStream[String] = streamingContext.socketTextStream("master", 12345)//hello worldval wordsDS: DStream[String] = rids.flatMap(_.split(" "))val kvDS: DStream[(String, Int)] = wordsDS.map((_, 1))val resDS: DStream[(String, Int)] = kvDS.reduceByKey(_ + _)//    val resDS: DStream[(String, Int)] = rids.flatMap(_.split(" "))
//      .map((_, 1))
//      .reduceByKey(_ + _)println("--------------------------------------")resDS.print()println("--------------------------------------")/*** sparkStreaming启动的方式和前两个模块启动方式不一样*/streamingContext.start()// 等待,根据上面设置的等待5秒钟(接收数据的时间)streamingContext.awaitTermination()// TODO:代表每个批次的开始和结束,并不是真的结束了streamingContext.stop()}
}

案例一的执行结果:

无法对依次输入的所有相同单词进行汇总

在这里插入图片描述
在这里插入图片描述

2、案例二:

实现对依次输入的所有相同单词进行汇总

需要使用有状态的算子来处理当前批次数据与历史数据的关系

updateStateByKey[S: ClassTag](updateFunc: (Seq[V], Option[S]) => Option[S]): DStream[(K, S)]

Seq: 序列,表示历史键对应的值组成的序列 (hello, seq:[1,1,1])

Option: 当前批次输入键对应的value值,如果历史中没有该键,这个值就是None, 如果历史中出现了这个键,这个值就是Some(值)

有状态算子使用注意事项:

1、有状态算子ByKey算子只适用于k-v类型的DStream

2、有状态算子使用的时候,需要提前设置checkpoint的路径,因为需要将历史批次的结果存储下来

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Durations, StreamingContext}object Demo2WordCount2 {def main(args: Array[String]): Unit = {/*** Spark core: SparkContext 核心数据结构:RDD* Spark sql: SparkSession 核心数据结构:DataFrame* Spark streaming: StreamingContext  核心数据结构:DStream(底层封装了RDD)*/val conf = new SparkConf()conf.setMaster("local[2]") // 给定核数conf.setAppName("spark Streaming 单词统计")val sparkContext = new SparkContext(conf)/*** 创建Spark Streaming的运行环境,和前两个模块是不一样的* Spark Streaming是依赖于Spark core的环境的* this(sparkContext: SparkContext, batchDuration: Duration)* Spark Streaming处理之前,是有一个接收数据的过程* batchDuration,表示接收多少时间段内的数据*/val streamingContext = new StreamingContext(sparkContext, Durations.seconds(5))//TODO :设置缓存,设置的是一个文件夹,用来存储缓存的数据streamingContext.checkpoint("spark/data/checkpoint2")/*** Spark Streaming程序理论上是一旦启动,就不会停止,除非报错,人为停止,停电等其他突然场景导致程序终止* 监控一个端口号中的数据,手动向端口号中打数据* master虚拟机上启动命令:nc -lk 12345*/val rids: ReceiverInputDStream[String] = streamingContext.socketTextStream("master", 12345)//hello worldval wordsDS: DStream[String] = rids.flatMap(_.split(" "))val kvDS: DStream[(String, Int)] = wordsDS.map((_, 1)) // (hello,1) (hello,1)  (hello,1)/*** 每5秒中resDS中的数据,是当前5s内的数据* reduceByKey,只会对当前5s批次中的数据求和*///    val resDS: DStream[(String, Int)] = kvDS.reduceByKey(_ + _)/*** 需要使用有状态的算子来处理当前批次数据与历史数据的关系** updateStateByKey[S: ClassTag](updateFunc: (Seq[V], Option[S]) => Option[S]): DStream[(K, S)]* Seq:  序列,表示历史键对应的值组成的序列 (hello, seq:[1,1,1])* Option: 当前批次输入键对应的value值,如果历史中没有该键,这个值就是None, 如果历史中出现了这个键,这个值就是Some(值)* 有状态算子使用注意事项:* 1、有状态算子ByKey算子只适用于k-v类型的DStream* 2、有状态算子使用的时候,需要提前设置checkpoint的路径,因为需要将历史批次的结果存储下来*/val resDS: DStream[(String, Int)] = kvDS.updateStateByKey((seq1: Seq[Int], opt1: Option[Int]) => {val sumValue: Int = seq1.sum/*** .getOrElse(0) 方法的作用是:如果Option容器包含的是Some(即值存在),则返回Some中包装的值;* 如果Option容器是None(即值不存在),则返回括号中指定的默认值,在这个例子中是0。*/val num: Int = opt1.getOrElse(0)Option(sumValue + num)})println("--------------------------------------")resDS.print()println("--------------------------------------")/*** sparkStreaming启动的方式和前两个模块启动方式不一样*/streamingContext.start()streamingContext.awaitTermination()streamingContext.stop()}
}

案例二执行结果:历史输入的相同的单词都会被统计

在这里插入图片描述
在这里插入图片描述

窗口类算子

1、如果只是为了计算当前批次接收的数据,直接调用reduceByKey

2、如果要将最新批次的数据与历史数据结合处理的话,需要调用有状态算子 updateStateByKey

3、如果要实现滑动窗口或者滚动窗口的话,需要使用窗口类算子reduceByKeyAndWindow

import org.apache.spark.sql.SparkSession
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Durations, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}object Demo3Window {def main(args: Array[String]): Unit = {/*** 创建spark streaming的环境* 旧版本创建的方式*///    val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("窗口案例")//    val context = new SparkContext(conf)//    val sc = new StreamingContext(context, Durations.seconds(5))/*** 新版本的创建方式*/val context: SparkContext = SparkSession.builder().master("local[2]").appName("窗口案例").config("spark.sql.shuffle.partitions", "1").getOrCreate().sparkContext/*** 正常每次接收3s内的数据* 注:这个时间为数据接收时间,目的是让时间与数据挂钩。* 因为无法对监控端的数据进行定量,所以通过对时间定量的方式来对数据定量。* 在逻辑上将数据想象为,一个个3s的时间间隔块,数据就存储在时间间隔块中。* 这样以来就可以使用窗口所设置的参数(时间),窗口大小、滑动大小来进行任务的处理与执行。*/val sc = new StreamingContext(context, Durations.seconds(5))//1000 ~ 65535(这些端口可用,但是有些特殊端口不可用,8088、8080、9870...)val infoDS: ReceiverInputDStream[String] = sc.socketTextStream("master", 10086)val wordsDS: DStream[String] = infoDS.flatMap(_.split(" "))val kvDS: DStream[(String, Int)] = wordsDS.map((_, 1))/*** 1、如果只是为了计算当前批次接收的数据,直接调用reduceByKey* 2、如果要将最新批次的数据与历史数据结合处理的话,需要调用有状态算子 updateStateByKey* 3、如果要实现滑动窗口或者滚动窗口的话,需要使用窗口类算子reduceByKeyAndWindow*//*** def reduceByKeyAndWindow(reduceFunc: (V, V) => V,windowDuration: Duration,slideDuration: Duration): DStream[(K, V)]* reduceFunc 编写处理相同的键对应的value值做处理* windowDuration  设置窗口的大小* slideDuration  设置滑动的大小* 每间隔slideDuration大小的时间计算一次数据,计算数据的范围是最近windowDuration大小时间的数据*/val resDS: DStream[(String, Int)] = kvDS.reduceByKeyAndWindow((v1: Int, v2: Int) => v1 + v2, Durations.seconds(10), Durations.seconds(5))/*** 当窗口大小与滑动大小一致的时候,那么就会从滑动窗口转变成滚动窗口的效果*/
//    val resDS: DStream[(String, Int)] = kvDS.reduceByKeyAndWindow((v1: Int, v2: Int) => v1 + v2, Durations.seconds(10), Durations.seconds(10))resDS.print()sc.start()sc.awaitTermination()sc.stop()}
}

DStreamToRDD

方式一:

foreachRDD:在DS中使用rdd的语法操作数据

缺点:该函数是没有返回值的,无法返回一个新的DStream

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, SparkSession}
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Durations, StreamingContext}object Demo4DStream2RDD {def main(args: Array[String]): Unit = {//使用DataFrame的语法val sparkSession: SparkSession = SparkSession.builder().master("local[2]").appName("rdd与DStream的关系").config("spark.sql.shuffle.partitions", "1").getOrCreate()import org.apache.spark.sql.functions._import sparkSession.implicits._//使用RDD的语法val sparkContext: SparkContext = sparkSession.sparkContext//使用DStream的语法val streamingContext = new StreamingContext(sparkContext, Durations.seconds(5))val infoDS: ReceiverInputDStream[String] = streamingContext.socketTextStream("master", 10086)//如果DS不是键值形式的话,可以单独调用window函数进行设置窗口的形式val new_infoDS: DStream[String] = infoDS.window(Durations.seconds(10), Durations.seconds(5))// hello world java hello java/*** foreachRDD:在DS中使用rdd的语法操作数据* 缺点:该函数是没有返回值的* 需求:我们在想使用DS中的RDD的同时,想要使用结束后,会得到一个新的DS*/new_infoDS.foreachRDD((rdd:RDD[String])=>{println("------------------------------")// sparkCore处理数据val resRDD: RDD[(String, Int)] = rdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)resRDD.foreach(println)// rdd和df之间可以转换
//       sparkSql处理数据val df1: DataFrame = rdd.toDF.select($"value" as "info")df1.createOrReplaceTempView("words")val resDF: DataFrame = sparkSession.sql("""|select|t1.wds as word,|count(1) as counts|from|(|select|explode(split(info,' ')) as  wds|from words) t1|group by t1.wds|""".stripMargin)resDF.show()})streamingContext.start()streamingContext.awaitTermination()streamingContext.stop()}
}
方式二:

面试题:foreachRDD与transform的区别

transform也可以循环遍历出DStream中封装的RDD,并且在计算后还会返回一个新的DStream对象

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Durations, StreamingContext}/*** 面试题:foreachRDD与transform的区别*/
object Demo5Transformat {def main(args: Array[String]): Unit = {//使用DataFrame的语法val sparkSession: SparkSession = SparkSession.builder().master("local[2]").appName("rdd与DStream的关系").config("spark.sql.shuffle.partitions", "1").getOrCreate()import org.apache.spark.sql.functions._import sparkSession.implicits._//使用RDD的语法val sparkContext: SparkContext = sparkSession.sparkContext//使用DStream的语法val streamingContext = new StreamingContext(sparkContext, Durations.seconds(5))val infoDS: ReceiverInputDStream[String] = streamingContext.socketTextStream("master", 10086)val resDS: DStream[(String, Int)] = infoDS.transform((rdd: RDD[String]) => {//直接对rdd进行处理,返回新的rdd//      val resRDD: RDD[(String, Int)] = rdd.flatMap(_.split(" "))//        .map((_, 1))//        .reduceByKey(_ + _)//      resRDD//将rdd转df,使用sql做分析//rdd和df之间可以转换val df1: DataFrame = rdd.toDF.select($"value" as "info")df1.createOrReplaceTempView("words")val resDF: DataFrame = sparkSession.sql("""|select|t1.wds as word,|count(1) as counts|from|(|select|explode(split(info,' ')) as  wds|from words) t1|group by t1.wds|""".stripMargin)val resRDD: RDD[(String, Int)] = resDF.rdd.map((row: Row) => (row.getAs[String](0), row.getAs[Int](1)))resRDD})resDS.print()streamingContext.start()streamingContext.awaitTermination()streamingContext.stop()}
}

将代码提交到yarn集群上运行

指令:spark-submit --master yarn --deploy-mode client --class com.shujia.streaming.Demo6YarnSubmit spark-1.0.jar

可以使用ctrl+c,退出并终止进程

杀死yarn上运行的进程(有时候直接退出不会终止进程):yarn application -kill application_1721466291251_0002

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
import org.apache.spark.streaming.{Durations, StreamingContext}
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}object Demo6YarnSubmit {def main(args: Array[String]): Unit = {//使用DataFrame的语法val sparkSession: SparkSession = SparkSession.builder()
//      .master("local[2]").appName("rdd与DStream的关系").config("spark.sql.shuffle.partitions", "1").getOrCreate()import org.apache.spark.sql.functions._import sparkSession.implicits._//使用RDD的语法val sparkContext: SparkContext = sparkSession.sparkContext//使用DStream的语法val streamingContext = new StreamingContext(sparkContext, Durations.seconds(5))val infoDS: ReceiverInputDStream[String] = streamingContext.socketTextStream("master", 10086)val resDS: DStream[(String, Int)] = infoDS.transform((rdd: RDD[String]) => {//直接对rdd进行处理,返回新的rdd//      val resRDD: RDD[(String, Int)] = rdd.flatMap(_.split(" "))//        .map((_, 1))//        .reduceByKey(_ + _)//      resRDD//将rdd转df,使用sql做分析//rdd和df之间可以转换val df1: DataFrame = rdd.toDF.select($"value" as "info")df1.createOrReplaceTempView("words")val resDF: DataFrame = sparkSession.sql("""|select|t1.wds as word,|count(1) as counts|from|(|select|explode(split(info,' ')) as  wds|from words) t1|group by t1.wds|""".stripMargin)val resRDD: RDD[(String, Int)] = resDF.rdd.map((row: Row) => (row.getAs[String](0), row.getAs[Int](1)))resRDD})resDS.print()streamingContext.start()streamingContext.awaitTermination()streamingContext.stop()}
}

读取一个端口中数据写入到本地

saveAsTextFiles

  • 将结果存储到磁盘中
  • 只能设置文件夹的名字和文件的后缀
  • 每一批次运行,都会产生新的小文件夹,文件夹中有结果数据文件
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
import org.apache.spark.streaming.{Durations, StreamingContext}
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}object Demo7SaveFile {def main(args: Array[String]): Unit = {//使用DataFrame的语法val sparkSession: SparkSession = SparkSession.builder().master("local[2]").appName("rdd与DStream的关系").config("spark.sql.shuffle.partitions", "1").getOrCreate()import org.apache.spark.sql.functions._import sparkSession.implicits._//使用RDD的语法val sparkContext: SparkContext = sparkSession.sparkContext//使用DStream的语法val streamingContext = new StreamingContext(sparkContext, Durations.seconds(5))val infoDS: ReceiverInputDStream[String] = streamingContext.socketTextStream("master", 10086)val resDS: DStream[(String, Int)] = infoDS.transform((rdd: RDD[String]) => {//直接对rdd进行处理,返回新的rdd//      val resRDD: RDD[(String, Int)] = rdd.flatMap(_.split(" "))//        .map((_, 1))//        .reduceByKey(_ + _)//      resRDD//将rdd转df,使用sql做分析//rdd和df之间可以转换val df1: DataFrame = rdd.toDF.select($"value" as "info")df1.createOrReplaceTempView("words")val resDF: DataFrame = sparkSession.sql("""|select|t1.wds as word,|count(1) as counts|from|(|select|explode(split(info,' ')) as  wds|from words) t1|group by t1.wds|""".stripMargin)val resRDD: RDD[(String, Int)] = resDF.rdd.map((row: Row) => (row.getAs[String](0), row.getAs[Int](1)))resRDD})//    resDS.print()/*** 将结果存储到磁盘中* 只能设置文件夹的名字和文件的后缀* 每一批次运行,都会产生新的小文件夹,文件夹中有结果数据文件*/resDS.saveAsTextFiles("spark/data/streamout/stream","txt")streamingContext.start()streamingContext.awaitTermination()streamingContext.stop()}
}

在这里插入图片描述

读取一个端口中的数据写入到MySQL中

在写入数据时,会涉及到数据库连接对象、预编译对象连续创建的问题

方案一:

数据库连接对象、预编译对象会连续创建

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession
import org.apache.spark.streaming.{Durations, StreamingContext}
import org.apache.spark.streaming.dstream.ReceiverInputDStreamimport java.sql.{Connection, DriverManager, PreparedStatement}
object Demo8DS2Mysql {def main(args: Array[String]): Unit = {//使用DataFrame的语法val sparkSession: SparkSession = SparkSession.builder().master("local[2]").appName("rdd与DStream的关系")/*** 这个配置是全局的,并且专门用于Spark SQL中的shuffle操作。它设置了在进行shuffle操作时,默认使用的分区数。* Shuffle操作通常发生在需要跨多个节点重新分发数据的场景中,比如join、groupBy等操作。*/.config("spark.sql.shuffle.partitions", "1").getOrCreate()import org.apache.spark.sql.functions._import sparkSession.implicits._//使用RDD的语法val sparkContext: SparkContext = sparkSession.sparkContext//使用DStream的语法val streamingContext = new StreamingContext(sparkContext, Durations.seconds(5))val infoDS: ReceiverInputDStream[String] = streamingContext.socketTextStream("master", 10086)infoDS.foreachRDD((rdd:RDD[String])=>{println("======================= 正在处理一批数据 ==========================")//处理rdd中每一条数据rdd.foreach((line:String)=>{//如果将创建连接的代码写在这里,这样的话,每条数据都会创建一次连接/*** 创建与数据库连接对象*///注册驱动Class.forName("com.mysql.jdbc.Driver")//创建数据库连接对象val conn: Connection = DriverManager.getConnection("jdbc:mysql://master:3306/bigdata30?useUnicode=true&characterEncoding=UTF-8&useSSL=false","root","123456")//创建预编译对象val statement: PreparedStatement = conn.prepareStatement("insert into students values(?,?,?,?,?)")val info: Array[String] = line.split(",")statement.setInt(1,info(0).toInt)statement.setString(2,info(1))statement.setInt(3,info(2).toInt)statement.setString(4,info(3))statement.setString(5,info(4))//执行sql语句statement.executeUpdate()//释放资源statement.close()conn.close()})})streamingContext.start()streamingContext.awaitTermination()streamingContext.stop()}
}

方案二:

设想中的改造

  • 我们将原本在rdd中创建连接的代码放到了ds遍历RDD中,发现PreparedStatement不能与task任务一起序列化到executor中的
  • 这样的写法是不可以的!!!
   infoDS.foreachRDD((rdd: RDD[String]) => {println("======================= 正在处理一批数据 ==========================")//如果将创建连接的代码写在这里,这样的话,每条数据都会创建一次连接/*** 创建与数据库连接对象*///注册驱动Class.forName("com.mysql.jdbc.Driver")//创建数据库连接对象val conn: Connection = DriverManager.getConnection("jdbc:mysql://master:3306/bigdata30?useUnicode=true&characterEncoding=UTF-8&useSSL=false","root","123456")//创建预编译对象val statement: PreparedStatement = conn.prepareStatement("insert into students values(?,?,?,?,?)")//处理rdd中每一条数据rdd.foreach((line: String) => {val info: Array[String] = line.split(",")statement.setInt(1, info(0).toInt)statement.setString(2, info(1))statement.setInt(3, info(2).toInt)statement.setString(4, info(3))statement.setString(5, info(4))//执行sql语句statement.executeUpdate()})//释放资源statement.close()conn.close()})

方案三:

rdd中有一个算子foreachPartition

  • rdd本质是由一系列分区构成的,如果我们可以将分区数设置为1,每个分区只创建一个连接即可
  • RDD中只有一个分区,只需在遍历该分区时创建一次数据库连接对象、预编译对象
infoDS.foreachRDD((rdd: RDD[String]) => {println("======================= 接收到 5s 一批次数据 ==========================")/*** 这个操作是针对特定的RDD(弹性分布式数据集)的,用于重新划分RDD的分区。* 它强制Spark对RDD中的元素进行重新分配,以符合指定的分区数。*/rdd.repartition(1)println(s" DS封装的RDD中的分区数为:${rdd.getNumPartitions} ")/*** foreachPartition,处理一个分区的数据* 将一个分区的数据,封装成了一个迭代器*/rdd.foreachPartition((itr: Iterator[String]) => {println("======================= 正在处理一个分区的数据 ==========================")//如果将创建连接的代码写在这里,这样的话,每条数据都会创建一次连接/*** 创建与数据库连接对象*///注册驱动Class.forName("com.mysql.jdbc.Driver")//创建数据库连接对象val conn: Connection = DriverManager.getConnection("jdbc:mysql://master:3306/bigdata_30?useUnicode=true&characterEncoding=UTF-8&useSSL=false","root","123456")//创建预编译对象val statement: PreparedStatement = conn.prepareStatement("insert into students2 values(?,?,?,?,?)")println("========================= 创建了一次连接 =========================")itr.foreach((line: String) => {val info: Array[String] = line.split(",")statement.setInt(1, info(0).toInt)statement.setString(2, info(1))statement.setInt(3, info(2).toInt)statement.setString(4, info(3))statement.setString(5, info(4))//执行sql语句statement.executeUpdate()})statement.close()conn.close()})
})

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ReadAgent,一款具有要点记忆的人工智能阅读代理

人工智能咨询培训老师叶梓 转载标明出处 现有的大模型(LLMs)在处理长文本时受限于固定的最大上下文长度,并且当输入文本越来越长时,性能往往会下降,即使在没有超出明确上下文窗口的情况下,LLMs 的性能也会随…

中文之美:荷·雅称

文章目录 引言I 荷雅称水宫仙子、六月花神水芝、水芸溪客、水旦芙蕖、菡萏朱华、红蕖风荷、静客II 与荷、莲相关的句子、诗词周敦颐李商隐李重元杨公远孟浩然刘光祖苏轼汪曾祺席慕蓉余光中引言 中文之美,美在诗词歌赋,美在绝句华章,也美在对事物名称的雅致表达。 中文对万物…

GPT-4o mini是什么?

今天,全网都知道 OpenAI 发现货了! GPT-4o mini 取代 GPT 3.5,从此坐上正主之位。 从官网信息来看,OpenAI 最新推出的 GPT-4o mini 重新定义了 AI 成本效益的标准,其性能优于前代模型 GPT-3.5 Turbo,且成本…

ruoyi-cloud-plus

1.X项目初始化 (dromara.org)参考文档! 可以直接参考以上链接!我只是整理我自己需要的部分,方便查看使用。 nacos 服务启动顺序 必须启动基础建设: mysql redis nacos可选启动基础建设: minio(影响文件上传) seata(影响分布式事务 默认开启…

Synopsys:Design Compiler的XG模式和DB模式

相关阅读 Synopsyshttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 很久之前,Design Compiler使用的是DB模式(包括一些其他工具,例如DFT Compiler, Physical Compiler和Power Compiler)&…

二叉树基础及实现(一)

目录: 一. 树的基本概念 二. 二叉树概念及特性 三. 二叉树的基本操作 一. 树的基本概念: 1 概念 : 树是一种非线性的数据结构,它是由n(n>0 )个有限结点组成一个具有层次关系的集合。 把它叫做树是因…

数据结构之初始二叉树(4)

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏:数据结构(Java版) 二叉树的基本操作 二叉树的相关刷题(上)通过上篇文章的学习,我们…

queue的模拟实现【C++】

文章目录 全部的实现代码放在了文章末尾什么是适配器模式?准备工作包含头文件定义命名空间类的成员变量 默认成员函数emptysizefrontbackpushpop全部代码 全部的实现代码放在了文章末尾 queue的模拟实现和stack一样,采用了C适配器模式 queue的适配器一…

Java生成四位纯数字并且确保唯一性

背景: 给了我一个需求,由于某些问题原因,需要给属性和数据添加一个code字段,这是给我发的消息 这两个要求其实是同一个需求,就是在创建对象的时候塞入一个unique的code嘛,听起来很简单吧,但是实…

GooglePlay 金融品类政策更新(7月17号)

距离上次政策大更新(4月5号)才过去了3个月,Google Play又迎来了一次大更新,不得不说Google Play的要求越来越高了。 我们来梳理一下这次GooglePlay针对金融品类更新了哪些政策: 1.要求提供金融产品和服务的开发者必须注册为组织…

Window环境下MySQL管理

1、MySQL服务启用和停止 图形化界面管理 使用键盘组合键(Win R)打开运行对话框,在对话框中输入services.msc并点击确定。 这里可以看到服务名称为MySQL84并处于正在运行的状态。 选中后右键可以进行暂停、停止、重启等操作。 命令提示符管理…

OpenCV 直方图概念,直方图均衡化原理详解

文章目录 直方图相关概念颜色灰度级作用应用场景 C 使用OpenCV绘制直方图单通道直方图关键代码分析:calcHist函数分析使用OpenCV API来绘制直方图 效果图: 彩色三通道直方图效果图: 直方图均衡化概念均衡化作用均衡化效果均衡化数学原理步骤数…

Linux中进程间通信--匿名管道和命名管道

本篇将会进入 Linux 进程中进程间通信,本篇简要的介绍了 Linux 中进程为什么需要通信,进程间通信的常用方式。然后详细的介绍了 Linux 进程间的管道通信方式,管道通信分为匿名管道和命名管道,本篇分别介绍了其实现的原理&#xff…

基于VMware(虚拟机) 创建 Ubunton24.04

目录 1.设置 root 密码 2. 防火墙设置 2.1 安装防火墙 2.2 开启和关闭防火墙 2.3 开放端口和服务规则 2.4 关闭端口和删除服务规则 2.5 查看防火墙状态 3. 换源 3.1 源文件位置 3.2 更新软件包 1. 设置网络 1. 在安装ubuntu时设置网络 2.在配置文件中修改 2.设置 r…

17_高级进程间通信 UNIX域套接字1

非命名的UNIX域套接字 第1个参数domain,表示协议族,只能为AF_LOCAL或者AF_UNIX; 第2个参数type,表示类型,只能为0。 第3个参数protocol,表示协议,可以是SOCK_STREAM或者SOCK_DGRAM。用SOCK_STR…

HTTP 缓存

缓存 web缓存是可以自动保存常见的文档副本的HTTP设备,当web请求抵达缓存时,如果本地有已经缓存的副本,就可以从本地存储设备而不是从原始服务器中提取这个文档。使用缓存有如下的优先。 缓存减少了冗余的数据传输缓存环节了网络瓶颈的问题…

MySQL学习之InnoDB引擎,索引

Mysql中的引擎 我们先来看一下MySql提供的有哪些引擎 mysql> show engines; 从上图我们可以查看出 MySQL 当前默认的存储引擎是InnoDB,并且在5.7版本所有的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。 查看MySQL当前默认的存储引…

算法力扣刷题记录 五十一【654.最大二叉树】

前言 二叉树篇,继续。 记录 五十一【654.最大二叉树】 一、题目阅读 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。…

套接字编程一(简单的UDP网络程序)

文章目录 一、 理解源IP地址和目的IP地址二、 认识端口号1. 理解 "端口号" 和 "进程ID"2. 理解源端口号和目的端口号 三、 认识协议1. 认识TCP协议2. 认识UDP协议 四、 网络字节序五、 socket编程接口1. socket 常见API2. sockaddr结构(1&#…

WebGIS的Web服务概述

WebGIS是互联网技术应用于GIS开发的产物,是现代GIS技术的重要组成部分,其中的Web服务是现代WebGIS的核心技术和重要标志,它集GIS、程序组件和互联网的优点于一身,深刻改变了GIS开发和应用的方式,绕过了本地数据转换和本…