【Spark】Spark编程体验,RDD转换算子、执行算子操作(六)

news2024/11/28 16:35:01

Spark编程体验

项目依赖管理

<dependencies>
    <dependency>
        <groupId>org.scala-lang</groupId>
        <artifactId>scala-library</artifactId>
        <version>2.12.10</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_2.12</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-sql_2.12</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.23</version>
    </dependency>

    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-hive_2.12</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming_2.12</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming-kafka-0-10_2.12</artifactId>
        <version>3.2.1</version>
    </dependency>
</dependencies>

<build>
    <finalName>chapter1.WordCount</finalName>
    <plugins>
        <plugin>
            <groupId>net.alchim31.maven</groupId>
            <artifactId>scala-maven-plugin</artifactId>
            <version>3.4.6</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>testCompile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

项目编码

spark入门程序wordcount:

package com.fesco.bigdata.spark
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
 * scala版本的wordcount
 */
object ScalaWordCountApp {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName(s"${ScalaWordCountApp.getClass.getSimpleName}")
.setMaster("local[*]")
val sc = new SparkContext(conf)
//加载数据
val file: RDD[String] = sc.textFile("file:/E:/data/spark/hello.txt")
   //按照分隔符进行切分
val words:RDD[String] = lines.flatMap(line => line.split("\\s+"))
//每个单词记为1次
val pairs:RDD[(String, Int)] = words.map(word => (word, 1))
//聚合数据
val ret:RDD[(String, Int)] = pairs.reduceByKey(myReduceFunc)
//export data to external system
ret.foreach(println)
}
sc.stop()
}
def myReduceFunc(v1: Int, v2: Int): Int = {
v1 + v2
}
}

Master URL说明
首先在编程过程中,至少需要给spark程序传递一个参数master-url,通过sparkConf.setMaster来完成。改参数,代表的是spark作业的执行方式,或者指定的spark程序的cluster-manager的类型。
表-1 模式选择
在这里插入图片描述

spark程序的其他提交方式

加载hdfs中的文件:

object RemoteSparkWordCountOps {
def main(args: Array[String]): Unit = {
    //创建程序入口
    val conf = new SparkConf().setAppName("wc").setMaster("local[*]")
    val sc = new SparkContext(conf)
    //设置日志级别
    sc.setLogLevel("WARN")
    //加载数据
    val file = sc.textFile("hdfs://hadoop101:8020//wordcount//words.txt")
    //切分
    val spliFile: RDD[String] = file.flatMap(_.split(" "))
    //每个单词记为1次
    val wordAndOne: RDD[(String, Int)] = spliFile.map((_, 1))
    //聚合
    val wordAndCount: RDD[(String, Int)] = wordAndOne.reduceByKey(_ + _)
    //打印输出
    wordAndCount.foreach(println)
    //释放资源
    sc.stop()
}
}

提交spark程序到集群中

首先需要将spark-core模块进行打包,其次上传到集群中,才可以进行提交作业到spark或者yarn集群中运行。
1)Client:

bin/spark-submit \
--class chapter1.WordCount \
--master spark://hadoop101:7077 \
/root/word.jar \
hdfs://hadoop101:8020/wordcount/words.txt

2)Cluster:

bin/spark-submit \
--class chapter1.WordCount \
--master spark://hadoop101:7077 \
/root/word.jar \
hdfs://hadoop101:8020/wordcount/words.txt \
hdfs://hadoop101:8020/wordcount/output1

Spark RDD操作

Spark执行流程
在上一讲中,我们知道了什么是Spark,什么是RDD、Spark的核心构成组件,以及Spark案例程序。在这一讲中,我们将继续需要Spark作业的执行过程,以及编程模型RDD的各种花式操作,首先来学习Spark作业执行流程。
WordCount执行流程
Wordcount执行流程如图-1所示。
在这里插入图片描述

图-1 wordcount执行流程
在上图中我们可以看到rdd(partition)和rdd之间是有依赖关系的,大致分为两种:窄依赖(Narrow Dependency)和宽依赖(Wide/Shuffle Dependency)。
1)窄依赖:rdd中partition中的数据,只依赖于父rdd中的一个分区,把这种依赖关系,称之为窄依赖,常见的窄依赖操作有:flatMap、map、filter、union、coalesce等等。
2)宽依赖:与窄依赖对应的,partition中的数据,依赖于父rdd中所有的partition,把这种依赖关系称之为宽依赖,常见的宽依赖操作:distinct、reduceByKey、groupByKey、repartition等等。
总而言之,rdd和rdd是有依赖关系的,我们把rdd和rdd之间关系构成的一个图或者依赖的链条,称之为rdd的lineage(血统),是保障spark容错的一个重要支撑。
Spark作业提交流程
下面我们一同来看spark作业提交流程,流程如图-2所示:
在这里插入图片描述

图-2 spark作业提交流程
RDD的基本操作
RDD概述
在较高的层次上,每个Spark应用程序都由一个驱动程序组成,该驱动程序运行用户的主功能并在集群上执行各种并行操作。Spark提供的主要抽象是一个弹性分布式数据集(RDD),它是一个跨集群节点划分的元素集合,可以并行操作。RDD是从Hadoop文件系统(或任何其他支持Hadoop的文件系统)中的一个文件或驱动程序中现有的Scala集合开始创建的,并对其进行转换。用户还可以要求Spark将RDD持久化在内存中,这样就可以跨并行操作高效地重用RDD。最后,RDD会自动从节点故障中恢复。
RDD分类
需要知道RDD操作算子的分类,基本上分为两类:transformation和action,当然更加细致的分,可以分为输入算子,转换算子,缓存算子,行动算子,整个RDD原生数据空间如图-3所示。

在这里插入图片描述
图-3 RDD原生数据空间
1)输入:在Spark程序运行中,数据从外部数据空间(如分布式存储:textFile读取HDFS等,parallelize方法输入Scala集合或数据)输入Spark,数据进入Spark运行时数据空间,转化为Spark中的数据块,通过BlockManager进行管理。
2)运行:在Spark数据输入形成RDD后便可以通过转换算子,如filter等,对数据进行操作并将RDD转化为新的RDD,通过Action算子,触发Spark提交作业。 如果数据需要复用,可以通过Cache算子,将数据缓存到内存。
3)输出:程序运行结束数据会输出Spark运行时空间,存储到分布式存储中(如saveAsTextFile输出到HDFS),或Scala数据或集合中(collect输出到Scala集合,count返回Scala int型数据)。
RDD初始化
RDD的初始化,原生api提供的2种创建方式,一种就是读取文件textFile,还有一种就是加载一个scala集合parallelize。当然,也可以通过transformation算子来创建的RDD。
RDD算子使用
transformation转换操作
map算子
rdd.map(p: A => B):RDD,对rdd集合中的每一个元素,都作用一次该func函数,之后返回值为生成元素构成的一个新的RDD。

val sc = new SparkContext(conf)
//map 原集合*7
val list = 1 to 7
//构建一个rdd
val listRDD:RDD[Int] = sc.parallelize(list)
//listRDD.map((num:Int) => num * 7)
//listRDD.map(num => num * 7)
val ret = listRDD.map(_ * 7)
ret.foreach(println)

flatMap算子
rdd.flatMap(p: A => 集合):RDD ==>rdd集合中的每一个元素,都要作用func函数,返回0到多个新的元素,这些新的元素共同构成一个新的RDD。

def  flatMapOps(sc:SparkContext): Unit = {
val list = List(
"jia jing kan kan kan",
"gao di di  di di",
"zhan yuan qi qi"
)
val listRDD = sc.parallelize(list)
listRDD.flatMap(line => line.split("\\s+"))
.foreach(println)
}

mapPartitions算子
mapPartitions(p: Iterator[A] =>Iterator[B]),上面的map操作,一次处理一条记录;而mapPartitions一次性处理一个partition分区中的数据。
注意:虽说mapPartitions的执行性能要高于map,但是其一次性将一个分区的数据加载到执行内存空间,如果该分区数据集比较大,存在OOM的风险。

//创建RDD并指定分区数
val array = 1 to 10
val listRDD:RDD[Int] = sc.parallelize(array,2)	
//通过-将分区之间的数据连接
val result: RDD[String] = rdd.mapPartitions(x=>Iterator(x.mkString("-")))
//打印输出
println(result.collect().toBuffer)
mapPartitionsWithIndex算子
mapPartitionsWithIndex((index,p:Iterator[A]=>Iterator[B])),该操作比mapPartitions多了一个index,代表就是后面p所对应的分区编号:rdd的分区编号,命名规范,如果有N个分区,分区编号就从0...N-1。
val rdd: RDD[Int] = sc.parallelize(1 to 16,4)
//查看每个分区当中都保存了哪些数据
val result: RDD[String] = rdd.mapPartitionsWithIndex((index,item)=>Iterator(index+":"+item.mkString(",")))
//打印输出
result.foreach(println)

sample算子
1)sample(withReplacement, fraction, seed):随机抽样算子,sample主要工作就是为了来研究数据本身,去代替全量研究会出现类似数据倾斜(dataSkew)等问题,无法进行全量研究,只能用样本去评估整体。
2)withReplacement:Boolean:有放回的抽样和无放回的抽样。
3)fraction:Double:样本空间占整体数据量的比例,大小在[0,1]。
4)seed:Long:是一个随机数的种子,有默认值,通常不需要传参。
需要说明一点的是,这个抽样是一个不准确的抽样,抽取的结果数可能在准确的结果上下浮动。

def sampleOps(sc: SparkContext): Unit = {
val list = sc.parallelize(1 to 100000)
val sampled1 = list.sample(true, 0.01)
println("sampled1 count: " + sampled1.count())
val sampled2 = list.sample(false, 0.01)
println("sampled2 count: " + sampled2.count())
}

union算子
rdd1.union(rdd2)相当于sql中的union all,进行两个rdd数据间的联合,需要说明一点是,该union是一个窄依赖操作,rdd1如果有N个分区,rdd2有M个分区,那么union之后的分区个数就为N+M。

val rdd1 = sc.parallelize(1 to 5,3)
//查看每个分区当中都保存了哪些数据
rdd1.mapPartitionsWithIndex((index,item)=>Iterator(index+":"+item.mkString(","))).foreach(println)
val rdd2: RDD[Int] = sc.parallelize(5 to 7,2)
//查看每个分区当中都保存了哪些数据
rdd2.mapPartitionsWithIndex((index,item)=>Iterator(index+":"+item.mkString(","))).foreach(println)
//union整合
val result: RDD[Int] = rdd1.union(rdd2)
//获取数据
println(result.collect().toBuffer)
//查看每个分区当中都保存了哪些数据
result.mapPartitionsWithIndex((index,item)=>Iterator(index+":"+item.mkString(","))).foreach(println)
//获取分区数
println(result.getNumPartitions)

join算子
1)rdd1.join(rdd2) 相当于sql中的join连接操作
A(id) a, B(aid) b
select * from A a join B b on a.id = b.aid
2)交叉连接: across join
select * from A a across join B ====>这回产生笛卡尔积。
3)内连接: inner join,提取左右两张表中的交集
select * from A a inner join B on a.id = b.aid 或者
select * from A a, B b where a.id = b.aid
4)外连接:outer join
5)左外连接:left outer join 返回左表所有,右表匹配返回,匹配不上返回null
select * from A a left outer join B on a.id = b.aid
6)右外连接:right outer join 刚好是左外连接的相反
select * from A a left outer join B on a.id = b.aid
7)全连接:full join
8)全外连接:full outer join = left outer join + right outer join
前提:要先进行join,rdd的类型必须是K-V。
对join操作可以归纳为如图-4所示。
在这里插入图片描述

图-4 sql 各种join连接图

def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setAppName("demo").setMaster("local[*]")
val sc = new SparkContext(conf)
sc.setLogLevel("WARN")
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1,"a"),(2,"b"),(3,"c")))
val rdd2: RDD[(Int, Int)] = sc.parallelize(Array((1,4),(2,5),(5,6)))
//join操作
val result: RDD[(Int, (String, Int))] = rdd1.join(rdd2)
//打印输出
println(result.collect().toBuffer)
//leftOutJoin操作
val result1: RDD[(Int, (String, Option[Int]))] = rdd1.leftOuterJoin(rdd2)
//打印输出
println(result1.collect().toBuffer)
//rightOuterJoin
val result2: RDD[(Int, (Option[String], Int))] = rdd1.rightOuterJoin(rdd2)
//打印输出
println(result2.collect().toBuffer)
//fullOuterJoin
val result3: RDD[(Int, (Option[String], Option[Int]))] = rdd1.fullOuterJoin(rdd2)
//打印输出
println(result3.collect().toBuffer)
}

coalesce算子
1)coalesce(numPartition, shuffle=false):分区合并的意思。
2)numPartition:分区后的分区个数。
3)shuffle:此次重分区是否开启shuffle,决定当前的操作是宽(true)依赖还是窄(false)依赖。

def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setAppName("wc").setMaster("local[*]")
val sc = new SparkContext(conf)
sc.setLogLevel("WARN")
val rdd = sc.parallelize(1 to 16,4)
//获取分区数
println(rdd.getNumPartitions)
//查看每个分区当中保存了哪些数据
rdd.mapPartitionsWithIndex((index,item)=>Iterator(index+":"+item.mkString(","))).foreach(println)
//缩减分区
val rdd1: RDD[Int] = rdd.coalesce(3)
//获取分区数
println(rdd1.getNumPartitions)
//查看每个分区当中保存的数据变化
rdd1.mapPartitionsWithIndex((index,item)=>Iterator(index+":"+item.mkString(","))).foreach(println)
//释放资源
sc.stop()
}

repartition(numPartitions)算子
根据分区数,从新通过网络随机洗牌所有数据。

def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setAppName("wc").setMaster("local[*]")
val sc = new SparkContext(conf)
//设置控制台日志级别
sc.setLogLevel("WARN")
val rdd = sc.parallelize(1 to 16,4)
//获取分区数
println(rdd.getNumPartitions)
//查看每个分区当中保存了哪些数据
rdd.mapPartitionsWithIndex((index,item)=>Iterator(index+":"+item.mkString(","))).foreach(println)
//缩减分区
val rdd1: RDD[Int] = rdd.repartition(3)
//获取分区数
println(rdd1.getNumPartitions)
//查看每个分区当中保存的数据变化
rdd1.mapPartitionsWithIndex((index,item)=>Iterator(index+":"+item.mkString(","))).foreach(println)
//释放资源
sc.stop()
}

sortBy(func,[ascending], [numTasks])算子
用func先对数据进行处理,按照处理后的数据比较结果排序。

def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setAppName("demo").setMaster("local[*]")
val sc = new SparkContext(conf)
//设置控制台日志输出级别
sc.setLogLevel("WARN")
//加载数据
val rdd= sc.parallelize(List(("a",4),("c",2),("b",1)))
//默认是升序排序,指定false,转为倒叙输出
val rdd1: RDD[(String, Int)] = rdd.sortBy(_._2,false)
//收集结果,返回数组输出
println(rdd1.collect().toBuffer)
}

sortByKey([ascending],[numTasks])算子
在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD。

def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setAppName("demo").setMaster("local[*]")
val sc = new SparkContext(conf)
//设置控制台日志输出级别
sc.setLogLevel("WARN")
//加载数据
val rdd = sc.parallelize(Array((3,"aa"),(6,"cc"),(2,"bb"),(1,"dd")))
//默认按照key进行升序输出,加false,转为倒叙输出
val result: RDD[(Int, String)] = rdd.sortByKey(false)
//收集结果,返回数组输出
println(result.collect().toBuffer)
}

groupByKey算子
groupByKey(numPartition):[K, Iterable[V]]
按照key来进行分组,numPartition指的是分组之后的分区个数。
这是一个宽依赖操作,但是需要注意一点的是,groupByKey相比较reduceByKey而言,没有本地预聚合操作,显然其效率并没有reduceByKey效率高,在使用的时候如果可以,尽量使用reduceByKey等去代替groupByKey。

def groupByOps(sc: SparkContext): Unit = {
case class Student(id: Int, name:String, province: String)
val stuRDD = sc.parallelize(List(
Student(1, "张三", "安徽"),
Student(2, "李梦", "山东"),
Student(3, "王五", "甘肃"),
Student(4, "周七", "甘肃"),
Student(5, "Lucy", "黑吉辽"),
Student(10086, "魏八", "黑吉辽")
))
//val province2Infos: RDD[(String, Iterable[Student]] = stuRDD.groupBy(stu => stu.province)
val province2Infos: RDD[(String, Iterable[Student])] = stuRDD.map(stu => (stu.province, stu)).groupByKey()

province2Infos.foreach{case (province, stus) => {
println(s"省份:${province}, 学生信息:${stus.mkString(", ")}, 人数:${stus.size}")
}}
}
}

reduceByKey算子
reduceByKey((A1, A2) => A3)
前提不是对全量的数据集进行reduce操作,而是对每一个key所对应的所有的value进行reduce操作。

def reduceByKeyOps(sc: SparkContext): Unit = {
case class Student(id: Int, name:String, province: String)
val stuRDD = sc.parallelize(List(
Student(1, "张三", "安徽"),
Student(2, "李梦", "山东"),
Student(3, "王五", "甘肃"),
Student(4, "周七", "甘肃"),
Student(5, "Lucy", "黑吉辽"),
Student(10086, "魏八", "黑吉辽")
))
val ret = stuRDD.map(stu => (stu.province, 1)).reduceByKey((v1, v2) => v1 + v2)
ret.foreach{case (province, count) => {
println(s"province: ${province}, count: ${count}")
}}
}

foldByKey算子
foldByKey(zeroValue)((A1, A2) => A3),其作用和reduceByKey一样,唯一的区别就是zeroValue初始化值不一样,相当于在scala集合操作中的reduce和fold的区别。

def foldByKeyOps(sc: SparkContext): Unit = {
case class Student(id: Int, name:String, province: String)
val stuRDD = sc.parallelize(List(
Student(1, "张三", "安徽"),
Student(3, "王五", "甘肃"),
Student(5, "Lucy", "黑吉辽"),
Student(2, "李梦", "山东"),
Student(4, "周七", "甘肃"),
Student(10086, "魏八", "黑吉辽")
), 2).mapPartitionsWithIndex((index, partition) => {
val list = partition.toList
println(s"-->stuRDD的分区编号为<${index}>中的数据为:${list.mkString("[", ", ", "]")}")
list.toIterator
})
val ret = stuRDD.map(stu => (stu.province, 1)).foldByKey(0)((v1, v2) => v1 + v2)
ret.foreach{case (province, count) => {
println(s"province: ${province}, count: ${count}")
}}
}

aggregateByKey算子
combineByKey和aggregateByKey的区别就相当于reduceByKey和foldByKey。

def abk2rbk(sc: SparkContext): Unit = {
val array = sc.parallelize(Array(
"hello you",
"hello me",
"hello you",
"hello you",
"hello me",
"hello you"
), 2)
val pairs = array.flatMap(_.split("\\s+")).map((_, 1))
val ret = pairs.aggregateByKey(0)(_+_, _+_)
ret.foreach{case (key, count) => {
println(s"key: ${key}, count: ${count}")
}}
}

action行动算子操作
1)foreach算子:foreach主要功能,就是用来遍历RDD中的每一条纪录,其实现就是将map或者flatMap中的返回值变为Unit即可,即foreach(A => Unit)。
在上述transformation操作学习过程中,多次使用到了foreach算子,所以这里就跳过学习了。
2)count算子:统计该rdd中元素的个数。
val count = rdd.count()
println(“rdd的count个数为:” + count)
3)collect算子:字面意思就是收集,拉取的意思,该算子的含义就是将分布在集群中的各个partition中的数据拉回到driver中,进行统一的处理;但是这个算子有很大的风险存在,第一,driver内存压力很大,第二数据在网络中大规模的传输,效率很低;所以一般不建议使用,如果非要用,请先执行filter。

val arr = rdd.filter(_._2 > 2).collect()
arr.foreach(println)

4)take&first:返回该rdd中的前N个元素,如果该rdd的数据是有序的,那么take(n)就是TopN;而first是take(n)中比较特殊的一个take(1)。

val arr:Array[(String, Int)] = rdd.take(2)
arr.foreach(println)

val ret:(String, Int) = rdd.first()
println(ret)

5)takeOrdered(n):返回前几个的排序。

val arr:Array[(String, Int)] = rdd.takeOrdered(2)
arr.foreach(println)

6)reduce算子:需要清楚的是,reduce是一个action操作,reduceByKey是一个transformation。reduce对一个rdd执行聚合操作,并返回结果,结果是一个值。

//例子1
val rdd: RDD[Int] = sc.parallelize(1 to 5,2)
//聚合
val result: Int = rdd.reduce(_+_)
//打印输出
println(result)
//例子2
val rdd2 = sc.makeRDD(Array(("a",1),("a",3),("c",3),("d",5)))
//聚合
val result1= rdd2.reduce((x,y)=>(x._1 + y._1,x._2 + y._2))
//打印输出
println(result1)
需要注意一点的是,聚合前后的数据类型保持一致。
7)countByKey算子:统计key出现的次数。
val rdd = sc.parallelize(List((1,3),(1,2),(1,4),(2,3),(3,6),(3,8)),3)
//统计相同key出现的次数
val result: collection.Map[Int, Long] = rdd.countByKey()
//打印输出
println(result)

8)saveAsXxx算子:

//saveAsTextFile
rdd.saveAsTextFile("file:/E:/data/out/")
//saveAsNewAPIHadoopFile
val path = "file:/E:/data/out1"
rr.saveAsNewAPIHadoopFile(path,
classOf[Text],
classOf[IntWritable],
classOf[TextOutputFormat[Text, IntWritable]])
9)foreachPartition算子:foreach写入写入数据库,但是极其不友好。
def saveInfoMySQL2(rdd: RDD[(String, Int)]): Unit = {
rdd.foreach{case (word, count) => {
Class.forName("com.mysql.jdbc.Driver")
val url = "jdbc:mysql://localhost:3306/test"
val connection = DriverManager.getConnection(url, "mark", "sorry")
val sql =
"""
|insert into wordcounts(word, `count`) Values(?, ?)
|""".stripMargin
val ps = connection.prepareStatement(sql)
ps.setString(1, word)
ps.setInt(2, count)
ps.execute()
ps.close()
connection.close()
}}
}
val rdd: RDD[(String, Int)] = sc.parallelize(List(("hadoop",2)))
save(rdd)

高效写入数据库:

def saveInfoMySQLByForeachPartition(rdd: RDD[(String, Int)]): Unit = {
rdd.foreachPartition(partition => {
//这是在partition内部,属于该partition的本地
Class.forName("com.mysql.jdbc.Driver")
val url = "jdbc:mysql://localhost:3306/test"
val connection = DriverManager.getConnection(url, "mark", "sorry")
val sql =
"""
|insert into wordcounts(word, `count`) Values(?, ?)
|""".stripMargin
val ps = connection.prepareStatement(sql)
partition.foreach{case (word, count) => {
ps.setString(1, word)
ps.setInt(2, count)
ps.execute()
}}
ps.close()
connection.close()
})
}

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

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

相关文章

通过 Java 操作 redis -- zset 有序集合基本命令

目录 使用命令 zadd&#xff0c;zrange 使用命令 zcard 使用命令 zrem 使用命令 zscore 使用命令 zrank 关于 redis zset 有序集合类型的相关命令推荐看Redis - Zset 有序集合 要想通过 Java 操作 redis&#xff0c;首先要连接上 redis 服务器&#xff0c;推荐看通过 Jav…

武汉凯迪正大—超声波探伤仪的主要功能

武汉凯迪正大超声波探伤仪的主要功能 高精度定量、定位&#xff0c;满足了较近和较远距离探伤的要求&#xff1b; 近场盲区小&#xff0c;满足了小管径、薄壁管探伤的要求&#xff1b; 自动校准&#xff1a;一键式自动校准&#xff0c;操作非常便捷&#xff0c;自动测试探头的…

基于springboot实现贸易行业crm系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现贸易行业crm系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于springboot的贸易行业crm系统的开发全过程。通过分析基于springboot的贸易行业crm系统管理的不足&#xff0c;创建…

element ui的无法关掉的提示弹框

使用element的$alert组件的属性把X去掉和确定按钮和取消按钮去掉&#xff1b; import { MessageBox } from element-ui; MessageBox.alert(AI功能已到期或暂未开启, 友情提示, {showClose: false,showCancelButton: false,showConfirmButton: false }); 如果在router的路由守…

华为ensp中BFD和OSPF联动(原理及配置命令)

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年5月6日20点26分 BFD通常指的是双向转发检测。BFD是一个旨在快速检测通信链路故障的网络协议&#xff0c;提供了低开销、短延迟的链路故障检测机制。它主要用于监测两个…

PCIe协议之-TLP路由基础

✨前言&#xff1a; 在PCI Express (PCIe) 技术中&#xff0c;数据包的路由方式对于确保信息能够高效、准确地传送至目标设备至关重要。PCIe定义了几种路由方式&#xff0c;主要有以下几种。 &#x1f31f;地址路由&#xff08;Address Based Routing&#xff09; 这是最基本…

hypertherm海宝EDGE控制器显示屏工控机维修

海宝工控机维修V3.0/4.0/5.0&#xff1b;hypertherm数控切割机系统MICRO EDGE系统显示屏维修&#xff1b; 美国hypertherm公司mirco edge数控系统技术标准如下&#xff1a; 1&#xff09; p4处理器 2&#xff09; 512mb内存 3&#xff09; 80g硬盘&#xff0c;1.44m内置软驱…

【连连国际注册/登录安全分析报告】

连连国际注册/登录安全分析报告 前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨…

解决VSCode中Debug和运行路径不一致

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 当尝试调试程序时&#xff0c;程序的运行路径与预期不符。这通常会导致程序无法正确读取文件或访问资源&#xff0c;从而影响调试过程。为了解决这个问题&#xff0c;可以在launch.json文件中配置CWD参数&#xff0c…

C语言学习初级阶段

文章目录 一、运算符与表达式1.1、运算符分类1.2、关系运算符与关系表达式2.1、逻辑运算符与逻辑表达式2.2、赋值运算符2.3、求字节运算符 二、选择、循环2.1、选择if-else讲解.2.1.1、关系表达式与逻辑表达式 2.2、while、for、continue、break讲解2.2.1、while循环2.2.2、for…

「PKUSC2018 星际穿越」Solution

题目传送门 [PKUSC2018] 星际穿越 简述题意 给定一张 n n n 个点的无向图和 q q q 次询问&#xff0c;每一个点 i i i 与 ∀ j ∈ [ l i , i − 1 ] \forall j \in [l_i , i -1] ∀j∈[li​,i−1] 都存在一条长度为 1 1 1 的无向边&#xff0c;每次询问给定 l i , r i…

DRF的三大认证

【 零 】一些注意事项 【1】如何使用视图类 #1 APIView -如果后续&#xff0c;写个接口&#xff0c;不需要用序列化类&#xff0c;不跟数据库打交道-发送短信接口&#xff0c;发送邮件接口#2 GenericAPIView-如果后续&#xff0c;写个接口&#xff0c;要做序列化或跟数据库打交…

数据结构复习指导之线索二叉树

文章目录 二叉树 考纲内容 复习提示 1.线索二叉树 1.1线索二叉树的基本概念 1.2中序线索二叉树的构造 1.3中序线索二叉树的遍历 1.4先序线索二叉树和后序线索二叉树 知识回顾 二叉树 考纲内容 &#xff08;一&#xff09;树的基本概念 &#xff08;二&#xff09;二叉…

酷柚易汛ERP源码部署/售后更新/搭建/上线维护

一款基于FastAdminThinkPHPLayui开发的ERP管理系统&#xff0c;帮助中小企业实现ERP管理规范化&#xff0c;此系统能为你解决五大方面的经营问题&#xff1a;1.采购管理 2.销售管理 3.仓库管理 4.资金管理 5.生产管理&#xff0c;适用于&#xff1a;服装鞋帽、化妆品、机械机电…

代码审计-PHP模型开发篇动态调试反序列化变量覆盖TP框架原生POP链

知识点 1、PHP审计-动态调试-变量覆盖 2、PHP审计-动态调试-原生反序列化 3、PHP审计-动态调试-框架反序列化PHP常见漏洞关键字 SQL注入&#xff1a; select insert update delete mysql_query mysqli等 文件上传&#xff1a; $_FILES&#xff0c;type"file"&…

人工智能驱动的设计工具的兴起:彻底改变创意产业

人工智能驱动的设计工具的兴起&#xff1a;彻底改变创意产业 概述 人工智能 (AI) 正在改变创意产业&#xff0c;设计也不例外。人工智能驱动的设计工具正在彻底改变设计师的工作方式&#xff0c;提供无与伦比的效率、创造力和创新水平。从生成图像和设计到自动化日常任务&…

深度学习基础之《TensorFlow框架(17)—卷积神经网络》

一、卷积神经网络介绍 1、背景 随着人工智能需求的提升&#xff0c;我们想要做复杂的图像识别&#xff0c;做自然语言处理&#xff0c;做语义分析翻译等等&#xff0c;多层神经网络的简单叠加显然力不从心 2、卷积神经网络与传统多层神经网络对比 &#xff08;1&#xff09;传…

Java基础编程(高级部分)

1. 类变量和类方法 1.1 什么是类变量 类变量也叫静态变量/静态属性&#xff0c;是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值同样任何一个该类的对象去修改它时,修改的也是同一个变量。 1.2 定义类变量 1.3 访问类变量 类名.类变量名 或者 对…

【C语言】模拟实现深入了解:字符串函数

&#x1f525;引言 本篇将模拟实现字符串函数&#xff0c;通过底层了解更多相关细节 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&#xff1a; C笔记 &#x1f308;喜欢的诗句:无人扶我青云志 我自…

flowable多对并发网关跳转的分析

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…