2Spark Core

2Spark Core

  • 1.RDD 详解
    • 1) 为什么要有 RDD?
    • 2) RDD 是什么?
    • 3) RDD 主要属性
  • 2.RDD-API
    • 1) RDD 的创建方式
    • 2) RDD 的算子分类
    • 3) Transformation 转换算子
    • 4) Action 动作算子
  • 3. RDD 的持久化/缓存
  • 4. RDD 容错机制 Checkpoint
  • 5. RDD 依赖关系
    • 1) 宽窄依赖
    • 2) 为什么要设计宽窄依赖
  • 6. DAG 的生成和划分 Stage
  • 7. RDD 累加器和广播变量
    • 1) 累加器
    • 2) 广播变量

1.RDD 详解

1) 为什么要有 RDD?

在许多迭代式算法(比如机器学习、图算法等)和交互式数据挖掘中,不同计算阶段之间会重用中间结果,即一个阶段的输出结果会作为下一个阶段的输入。但是,之前的 MapReduce 框架采用非循环式的数据流模型,把中间结果写入到 HDFS 中,带来了大量的数据复制、磁盘 IO 和序列化开销。且这些框架只能支持一些特定的计算模式(map/reduce),并没有提供一种通用的数据抽象。
AMP 实验室发表的一篇关于 RDD 的论文:《Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing》就是为了解决这些问题的。
RDD 提供了一个抽象的数据模型,让我们不必担心底层数据的分布式特性,只需将具体的应用逻辑表达为一系列转换操作(函数),不同 RDD 之间的转换操作之间还可以形成依赖关系,进而实现管道化,从而避免了中间结果的存储,大大降低了数据复制、磁盘 IO 和序列化开销,并且还提供了更多的 API(map/reduec/filter/groupBy…)。

2) RDD 是什么?

RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是 Spark 中最基本的数据抽象,代表一个不可变、可分区、里面的元素可并行计算的集合。 单词拆解:
-Resilient :它是弹性的,RDD 里面的中的数据可以保存在内存中或者磁盘里面;
-Distributed :它里面的元素是分布式存储的,可以用于分布式计算;
-Dataset: 它是一个集合,可以存放很多元素。

3) RDD 主要属性

进入 RDD 的源码中看下:
在这里插入图片描述
RDD源码
在源码中可以看到有对 RDD 介绍的注释,我们来翻译下:
1.A list of partitions : 一组分片(Partition)/一个分区(Partition)列表,即数据集的基本组成单位。 对于 RDD 来说,每个分片都会被一个计算任务处理,分片数决定并行度。 用户可以在创建 RDD 时指定 RDD 的分片个数,如果没有指定,那么就会采用默认值。
2.A function for computing each split : 一个函数会被作用在每一个分区。 Spark 中 RDD 的计算是以分片为单位的,compute 函数会被作用到每个分区上。
3.A list of dependencies on other RDDs : 一个 RDD 会依赖于其他多个 RDD。 RDD 的每次转换都会生成一个新的 RDD,所以 RDD 之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark 可以通过这个依赖关系重新计算丢失的分区数据,而不是对 RDD 的所有分区进行重新计算。(Spark 的容错机制)
4.Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned): 可选项,对于 KV 类型的 RDD 会有一个 Partitioner,即 RDD 的分区函数,默认为 HashPartitioner。
5.Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file): 可选项,一个列表,存储存取每个 Partition 的优先位置(preferred location)。 对于一个 HDFS 文件来说,这个列表保存的就是每个 Partition 所在的块的位置。按照"移动数据不如移动计算"的理念,Spark 在进行任务调度的时候,会尽可能选择那些存有数据的 worker 节点来进行任务计算。

总结
RDD 是一个数据集的表示,不仅表示了数据集,还表示了这个数据集从哪来,如何计算,主要属性包括:
1.分区列表
2.计算函数
3.依赖关系
4.分区函数(默认是 hash)
5.最佳位置
分区列表、分区函数、最佳位置,这三个属性其实说的就是数据集在哪,在哪计算更合适,如何分区;
计算函数、依赖关系,这两个属性其实说的是数据集怎么来的。

2.RDD-API

1) RDD 的创建方式

1.由外部存储系统的数据集创建,包括本地的文件系统,还有所有 Hadoop 支持的数据集,比如 HDFS、Cassandra、HBase 等:
val rdd1 = sc.textFile(“hdfs://node1:8020/wordcount/input/words.txt”)
2.通过已有的 RDD 经过算子转换生成新的 RDD:
val rdd2=rdd1.flatMap(_.split(" "))
3.由一个已经存在的 Scala 集合创建:
val rdd3 = sc.parallelize(Array(1,2,3,4,5,6,7,8)) 或者
val rdd4 = sc.makeRDD(List(1,2,3,4,5,6,7,8))
makeRDD 方法底层调用了 parallelize 方法:
在这里插入图片描述

2) RDD 的算子分类

RDD 的算子分为两类:
1.Transformation转换操作:返回一个新的 RDD
2.Action动作操作:返回值不是 RDD(无返回值或返回其他的)
❣️ 注意:
1、RDD 不实际存储真正要计算的数据,而是记录了数据的位置在哪里,数据的转换关系(调用了什么方法,传入什么函数)。
2、RDD 中的所有转换都是惰性求值/延迟执行的,也就是说并不会直接计算。只有当发生一个要求返回结果给 Driver 的 Action 动作时,这些转换才会真正运行。
3、之所以使用惰性求值/延迟执行,是因为这样可以在 Action 时对 RDD 操作形成 DAG 有向无环图进行 Stage 的划分和并行优化,这种设计让 Spark 更加有效率地运行。

3) Transformation 转换算子

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

4) Action 动作算子

在这里插入图片描述
统计操作:
在这里插入图片描述

-需求:
给定一个键值对 RDD:

val rdd = sc.parallelize(Array(("spark",2),("hadoop",6),("hadoop",4),("spark",6)))

key 表示图书名称,value 表示某天图书销量
请计算每个键对应的平均值,也就是计算每种图书的每天平均销量。
最终结果:(“spark”,4),(“hadoop”,5)。

-答案 1:

val rdd = sc.parallelize(Array(("spark",2),("hadoop",6),("hadoop",4),("spark",6)))
val rdd2 = rdd.groupByKey()
rdd2.collect
//Array[(String, Iterable[Int])] = Array((spark,CompactBuffer(2, 6)), (hadoop,CompactBuffer(6, 4)))
rdd2.mapValues(v=>v.sum/v.size).collect
Array[(String, Int)] = Array((spark,4), (hadoop,5))

-答案 2:

val rdd = sc.parallelize(Array(("spark",2),("hadoop",6),("hadoop",4),("spark",6)))
val rdd2 = rdd.groupByKey()
rdd2.collect
//Array[(String, Iterable[Int])] = Array((spark,CompactBuffer(2, 6)), (hadoop,CompactBuffer(6, 4)))val rdd3 = rdd2.map(t=>(t._1,t._2.sum /t._2.size))
rdd3.collect
//Array[(String, Int)] = Array((spark,4), (hadoop,5))

3. RDD 的持久化/缓存

在实际开发中某些 RDD 的计算或转换可能会比较耗费时间,如果这些 RDD 后续还会频繁的被使用到,那么可以将这些 RDD 进行持久化/缓存,这样下次再使用到的时候就不用再重新计算了,提高了程序运行的效率。

val rdd1 = sc.textFile("hdfs://node01:8020/words.txt")
val rdd2 = rdd1.flatMap(x=>x.split(" ")).map((_,1)).reduceByKey(_+_)
rdd2.cache //缓存/持久化
rdd2.sortBy(_._2,false).collect//触发action,会去读取HDFS的文件,rdd2会真正执行持久化
rdd2.sortBy(_._2,false).collect//触发action,会去读缓存中的数据,执行速度会比之前快,因为rdd2已经持久化到内存中了

持久化/缓存 API 详解
-ersist 方法和 cache 方法
RDD 通过 persist 或 cache 方法可以将前面的计算结果缓存,但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 时,该 RDD 将会被缓存在计算节点的内存中,并供后面重用。
通过查看 RDD 的源码发现 cache 最终也是调用了 persist 无参方法(默认存储只存在内存中):
在这里插入图片描述
RDD源码

  • 存储级别
    默认的存储级别都是仅在内存存储一份,Spark 的存储级别还有好多种,存储级别在 object StorageLevel 中定义的。
    在这里插入图片描述
    总结:
    1.RDD 持久化/缓存的目的是为了提高后续操作的速度
    2.缓存的级别有很多,默认只存在内存中,开发中使用 memory_and_disk
    3.只有执行 action 操作的时候才会真正将 RDD 数据进行持久化/缓存
    4.实际开发中如果某一个 RDD 后续会被频繁的使用,可以将该 RDD 进行持久化/缓存

4. RDD 容错机制 Checkpoint

-持久化的局限:
持久化/缓存可以把数据放在内存中,虽然是快速的,但是也是最不可靠的;也可以把数据放在磁盘上,也不是完全可靠的!例如磁盘会损坏等。
-问题解决:
Checkpoint 的产生就是为了更加可靠的数据持久化,在 Checkpoint 的时候一般把数据放在在 HDFS 上,这就天然的借助了 HDFS 天生的高容错、高可靠来实现数据最大程度上的安全,实现了 RDD 的容错和高可用。
用法:

SparkContext.setCheckpointDir("目录") //HDFS的目录RDD.checkpoint

-总结:
-开发中如何保证数据的安全性性及读取效率: 可以对频繁使用且重要的数据,先做缓存/持久化,再做 checkpint 操作。
-持久化和 Checkpoint 的区别:
1.位置: Persist 和 Cache 只能保存在本地的磁盘和内存中(或者堆外内存–实验中) Checkpoint 可以保存数据到 HDFS 这类可靠的存储上。
2.生命周期: Cache 和 Persist 的 RDD 会在程序结束后会被清除或者手动调用 unpersist 方法 Checkpoint 的 RDD 在程序结束后依然存在,不会被删除。

5. RDD 依赖关系

1) 宽窄依赖

-两种依赖关系类型: RDD 和它依赖的父 RDD 的关系有两种不同的类型,即 宽依赖(wide dependency/shuffle dependency) 窄依赖(narrow dependency)
在这里插入图片描述
图解:
在这里插入图片描述
宽窄依赖
-如何区分宽窄依赖:
窄依赖:父 RDD 的一个分区只会被子 RDD 的一个分区依赖;
宽依赖:父 RDD 的一个分区会被子 RDD 的多个分区依赖(涉及到 shuffle)。

2) 为什么要设计宽窄依赖

1.对于窄依赖:
窄依赖的多个分区可以并行计算;
窄依赖的一个分区的数据如果丢失只需要重新计算对应的分区的数据就可以了。
2.对于宽依赖:
划分 Stage(阶段)的依据:对于宽依赖,必须等到上一阶段计算完成才能计算下一阶段。

6. DAG 的生成和划分 Stage

  1. DAG 介绍
    -DAG 是什么:
    DAG(Directed Acyclic Graph 有向无环图)指的是数据转换执行的过程,有方向,无闭环(其实就是 RDD 执行的流程);
    原始的 RDD 通过一系列的转换操作就形成了 DAG 有向无环图,任务执行时,可以按照 DAG 的描述,执行真正的计算(数据被操作的一个过程)。
    -DAG 的边界
    开始:通过 SparkContext 创建的 RDD;
    结束:触发 Action,一旦触发 Action 就形成了一个完整的 DAG。
  2. DAG 划分 Stage
    在这里插入图片描述
    DAG划分Stage
    一个 Spark 程序可以有多个 DAG(有几个 Action,就有几个 DAG,上图最后只有一个 Action(图中未表现),那么就是一个 DAG)。
    一个 DAG 可以有多个 Stage(根据宽依赖/shuffle 进行划分)。
    同一个 Stage 可以有多个 Task 并行执行(task 数=分区数,如上图,Stage1 中有三个分区 P1、P2、P3,对应的也有三个 Task)。
    可以看到这个 DAG 中只 reduceByKey 操作是一个宽依赖,Spark 内核会以此为边界将其前后划分成不同的 Stage。
    同时我们可以注意到,在图中 Stage1 中,从 textFile 到 flatMap 到 map 都是窄依赖,这几步操作可以形成一个流水线操作,通过 flatMap 操作生成的 partition 可以不用等待整个 RDD 计算结束,而是继续进行 map 操作,这样大大提高了计算的效率。

-为什么要划分 Stage? --并行计算
一个复杂的业务逻辑如果有 shuffle,那么就意味着前面阶段产生结果后,才能执行下一个阶段,即下一个阶段的计算要依赖上一个阶段的数据。那么我们按照 shuffle 进行划分(也就是按照宽依赖就行划分),就可以将一个 DAG 划分成多个 Stage/阶段,在同一个 Stage 中,会有多个算子操作,可以形成一个 pipeline 流水线,流水线内的多个平行的分区可以并行执行。

-如何划分 DAG 的 stage?
对于窄依赖,partition 的转换处理在 stage 中完成计算,不划分(将窄依赖尽量放在在同一个 stage 中,可以实现流水线计算)。
对于宽依赖,由于有 shuffle 的存在,只能在父 RDD 处理完成后,才能开始接下来的计算,也就是说需要要划分 stage。

总结:
Spark 会根据 shuffle/宽依赖使用回溯算法来对 DAG 进行 Stage 划分,从后往前,遇到宽依赖就断开,遇到窄依赖就把当前的 RDD 加入到当前的 stage/阶段中
具体的划分算法请参见 AMP 实验室发表的论文: 《Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing》
http://xueshu.baidu.com/usercenter/paper/show?paperid=b33564e60f0a7e7a1889a9da10963461&site=xueshu_se

7. RDD 累加器和广播变量

在默认情况下,当 Spark 在集群的多个不同节点的多个任务上并行运行一个函数时,它会把函数中涉及到的每个变量,在每个任务上都生成一个副本。但是,有时候需要在多个任务之间共享变量,或者在任务(Task)和任务控制节点(Driver Program)之间共享变量。
为了满足这种需求,Spark 提供了两种类型的变量:
1.累加器 accumulators:累加器支持在所有不同节点之间进行累加计算(比如计数或者求和)。
2.广播变量 broadcast variables:广播变量用来把变量在所有节点的内存之间进行共享,在每个机器上缓存一个只读的变量,而不是为机器上的每个任务都生成一个副本。

1) 累加器

  1. 不使用累加器
var counter = 0
val data = Seq(1, 2, 3)
data.foreach(x => counter += x)
println("Counter value: "+ counter)

运行结果:

Counter value: 6

如果我们将 data 转换成 RDD,再来重新计算:

var counter = 0
val data = Seq(1, 2, 3)
var rdd = sc.parallelize(data)
rdd.foreach(x => counter += x)
println("Counter value: "+ counter)

运行结果:

Counter value: 0
  1. 使用累加器
    通常在向 Spark 传递函数时,比如使用 map() 函数或者用 filter() 传条件时,可以使用驱动器程序中定义的变量,但是集群中运行的每个任务都会得到这些变量的一份新的副本,更新这些副本的值也不会影响驱动器中的对应变量。这时使用累加器就可以实现我们想要的效果:
    val xx: Accumulator[Int] = sc.accumulator(0)
  2. 代码示例:
import org.apache.spark.rdd.RDD
import org.apache.spark.{Accumulator, SparkConf, SparkContext}object AccumulatorTest {def main(args: Array[String]): Unit = {val conf: SparkConf = new SparkConf().setAppName("wc").setMaster("local[*]")val sc: SparkContext = new SparkContext(conf)sc.setLogLevel("WARN")//使用scala集合完成累加var counter1: Int = 0;var data = Seq(1,2,3)data.foreach(x => counter1 += x )println(counter1)//6println("+++++++++++++++++++++++++")//使用RDD进行累加var counter2: Int = 0;val dataRDD: RDD[Int] = sc.parallelize(data) //分布式集合的[1,2,3]dataRDD.foreach(x => counter2 += x)println(counter2)//0//注意:上面的RDD操作运行结果是0//因为foreach中的函数是传递给Worker中的Executor执行,用到了counter2变量//而counter2变量在Driver端定义的,在传递给Executor的时候,各个Executor都有了一份counter2//最后各个Executor将各自个x加到自己的counter2上面了,和Driver端的counter2没有关系//那这个问题得解决啊!不能因为使用了Spark连累加都做不了了啊!//如果解决?---使用累加器val counter3: Accumulator[Int] = sc.accumulator(0)dataRDD.foreach(x => counter3 += x)println(counter3)//6}
}

2) 广播变量

  1. 不使用广播变量
  2. 使用广播变量
  3. 代码示例:
    关键词:sc.broadcast()
import org.apache.spark.broadcast.Broadcast
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}object BroadcastVariablesTest {def main(args: Array[String]): Unit = {val conf: SparkConf = new SparkConf().setAppName("wc").setMaster("local[*]")val sc: SparkContext = new SparkContext(conf)sc.setLogLevel("WARN")//不使用广播变量val kvFruit: RDD[(Int, String)] = sc.parallelize(List((1,"apple"),(2,"orange"),(3,"banana"),(4,"grape")))val fruitMap: collection.Map[Int, String] =kvFruit.collectAsMap//scala.collection.Map[Int,String] = Map(2 -> orange, 4 -> grape, 1 -> apple, 3 -> banana)val fruitIds: RDD[Int] = sc.parallelize(List(2,4,1,3))//根据水果编号取水果名称val fruitNames: RDD[String] = fruitIds.map(x=>fruitMap(x))fruitNames.foreach(println)//注意:以上代码看似一点问题没有,但是考虑到数据量如果较大,且Task数较多,//那么会导致,被各个Task共用到的fruitMap会被多次传输//应该要减少fruitMap的传输,一台机器上一个,被该台机器中的Task共用即可//如何做到?---使用广播变量//注意:广播变量的值不能被修改,如需修改可以将数据存到外部数据源,如MySQL、Redisprintln("=====================")val BroadcastFruitMap: Broadcast[collection.Map[Int, String]] = sc.broadcast(fruitMap)val fruitNames2: RDD[String] = fruitIds.map(x=>BroadcastFruitMap.value(x))fruitNames2.foreach(println)}
}

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

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

相关文章

归子莫的科技周刊#2:白天搬砖,夜里读诗

归子莫的科技周刊#2:白天搬砖,夜里读诗 本周刊开源,欢迎投稿。 刊期:2025.1.5 - 2025.1.11。原文地址。 封面图 下班在深圳看到的夕阳,能遇到是一种偶然的机会,能拍下更是一种幸运。 白天搬砖,…

机器学习第一道菜(一):线性回归的理论模型

机器学习第一道菜(一):线性回归的理论模型 一、问题:千金买笑1.1 散点图1.2 机器学习能搞啥 二、模型的建立2.1 线性回归2.2 回归模型 前面讲了机器学习的“四大绝技”,今天,开始研究第一绝技“回归”&…

http转化为https生成自签名证书

背景 项目开发阶段前后交互采用http协议,演示环境采用htttps协议 ,此处为个人demo案例 组件 后端:springBoot 前端:vue web 服务:tomcat 部署环境:linux 生成自签名证书 创建目录 存储证书位置 # mkdir -p…

【安卓开发】【Android】总结:安卓技能树

【持续更新】 对笔者在安卓开发的实践中认为必要的知识点和遇到的问题进行总结。 一、基础知识部分 1、Android Studio软件使用 软件界面 最新的版本是瓢虫(Ladybug),bug的确挺多。笔者更习惯使用电鳗(Electric Eel&#xff0…

PT8M2302 触控 A/D 型 8-Bit MCU

1. 产品概述 PT8M2302 是一款可多次编程( MTP ) A/D 型 8 位 MCU ,其包括 2K*16bit MTP ROM 、 256*8bit SRAM、 ADC 、 PWM 、 Touch 等功能,具有高性能精简指令集、低工作电压、低功耗特性且完全集 成触控按键功能。为…

HunyuanVideo 文生视频模型实践

HunyuanVideo 文生视频模型实践 flyfish 运行 HunyuanVideo 模型使用文本生成视频的推荐配置(batch size 1): 模型分辨率(height/width/frame)峰值显存HunyuanVideo720px1280px129f60GHunyuanVideo544px960px129f45G 本项目适用于使用 N…

【网络 MAC 学习专栏 -- 如何理解 PHY 的 Link Up】

请阅读【嵌入式开发学习必备专栏 Cache | MMU | AMBA BUS | CoreSight | Trace32 | CoreLink | ARM GCC | CSH】 文章目录 OverviewClause 22/Clause 45Clause 22Clause 45 PHY Link 状态的软件实现 转自: 开心果 Need Car 2022年10月20日 09:50 上海 Overview PHY…

npm发布组件(vue3+webpack)

1.初始化Vue项目 vue create my-app 2.本地运行 npm run serve 3.新增目录和文件 1. src/package/index.js 2. src/package/wlz-btn/index.vue 3. src/package/wlz-input/index.vue // src\package\index.js import WlzBtn from "./wlz-btn"; import WlzInput …

数据库(MySQL)练习

数据库(MySQL)练习 一、练习1.15练习1.16练习 二、注意事项2.1 第四天 一、练习 1.15练习 win11安装配置MySQL超详细教程: https://baijiahao.baidu.com/s?id1786910666566008458&wfrspider&forpc 准备工作: mysql -uroot -p #以…

基于华为云车牌识别服务设计的停车场计费系统【华为开发者空间-鸿蒙】

文章目录 手把手的技术干货教程,记录从0到1的开发过程。一、前言1.1 内容简介1.2 云主机1.3 开发环境1.4 功能说明 二、华为云开发者空间2.1 进入开发者空间2.2 配置云主机2.3 安装系统2.4 启动云主机2.5 全屏切换2.6 共享桌面2.5 测试Python开发环境2.6 安装reques…

如何在前端给视频进行去除绿幕并替换背景?-----Vue3!!

最近在做这个这项目奇店桶装水小程序V1.3.9安装包骑手端V2.0.1小程序前端 最近,我在进行前端开发时,遇到了一个难题“如何给前端的视频进行去除绿幕并替换背景”。这是一个“数字人项目”所需,我一直在冥思苦想。终于有了一个解决方法…

Yolov8 目标检测剪枝学习记录

最近在进行YOLOv8系列的轻量化,目前在网络结构方面的优化已经接近极限了,所以想要学习一下模型剪枝是否能够进一步优化模型的性能 这里主要参考了torch-pruning的基本使用,v8模型剪枝,Jetson nano部署剪枝YOLOv8 下面只是记录一个…

AWS Lambda

AWS Lambda 是 Amazon Web Services(AWS)提供的无服务器计算服务,它让开发者能够运行代码而不需要管理服务器或基础设施。AWS Lambda 会自动处理代码的执行、扩展和计费,开发者只需关注编写和部署代码,而无需担心底层硬…

MySQL-索引

目录 🌴概念 🌵作用 🌱使用场景 🎄使用 查看索引 创建索引 删除索引 🌴概念 索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引,并指定索引的类…

自动化办公|xlwings简介

xlwings 是一个开源的 Python 库,旨在实现 Python 与 Microsoft Excel 的无缝集成。它允许用户使用 Python 脚本自动化 Excel 操作,读取和写入数据,执行宏,甚至调用 VBA 脚本。这使得数据分析、报告生成和其他与 Excel 相关的任务…

【物联网】ARM核介绍

文章目录 芯片产业链1. CPU核(1)ARM(2)MIPS(3)PowerPc(4)Intel(5)RISC-V 2. SOC芯片(1)主流厂家(2)产品解决方案 3. 产品 ARM核发展1. 不同架构的特点分析(1)VFP(2)Jazelle(3)Thumb(4)TrustZone(5)SIMD(6)NEON ARM核(ARMv7)工作模式1. 权限级别(privilege level)2. ARM process…

SuperMap iClient3D for Cesium立体地图选中+下钻特效

在大屏展示系统中,对行政区划数据制作了立体效果,如果希望选中某一行政区划进行重点介绍,目前常见的方式是通过修改选中对象色彩、边线等方式进行实现;这里提供另外一种偏移动效的思路,并提供下钻功能,让地…

Linux的常用命令(三)

目录 六、网络通信命令 1.网络通信命令ping 2.网络通信命令ifconfig 七、系统命令 1. 系统命令shutdown 2. 系统命令reboot 八、vi编辑器 六、网络通信命令 1.网络通信命令ping 命令名称:ping 命令所在路径:/usr/sbin/ping 执行权限&#xff…

SQL Prompt 插件

SQL Prompt 插件 注:SQL Prompt插件提供智能代码补全、SQL格式化、代码自动提示和快捷输入等功能,非常方便,可以自行去尝试体会。 1、问题 SSMS(SQL Server Management Studio)是SQL Server自带的管理工具&#xff0c…

《小迪安全》学习笔记05

目录 读取: 写入: (其中的读取和写入时我认为比较重要的,所以单独做成了目录,这里的读取和写入是指在进行sql注入的时候与本地文件进行的交互) 好久没发博客了。。。从这篇开始的小迪安全学习笔记就开始…