弹性分布式数据集RDD详细说明

news2024/12/28 23:26:56

文章目录

    • 整体介绍
      • 一、定义与特性
      • 二、操作与转换
      • 三、存储级别与持久化
      • 四、依赖关系与容错机制
      • 五、优化与性能调优
    • 常见操作
    • 支持的数据格式
      • 1.文本文件 (Text Files)
      • 2. CSV 文件
      • 3. JSON 文件
      • 4. Parquet 文件
      • 5. Sequence Files
      • 6.Hadoop文件读取
        • A. 读取HDFS上的文本文件
        • B. 使用Hadoop的InputFormat读取数据
        • 注意事项
    • 一个完整代码示例
    • RDD、Datasets和DataFrame的对比

整体介绍

弹性分布式数据集RDD(Resilient Distributed Dataset)是Apache Spark中最基本的数据抽象,代表一个不可变、可分区、元素可以并行计算的数据集合。以下是对RDD的详细说明:

一、定义与特性

  1. 定义:RDD是Spark对数据集的抽象,用于存放数据,它表示一个只读的、可分区的、其中元素可进行并行计算的集合,并且是可跨越集群节点进行并行操作的有容错机制的集合。

  2. 特性

    • 基于内存计算:RDD通过将数据加载到内存中,提高了数据处理的效率。相比于传统的磁盘存储,内存(RAM)的读写速度更快,因此RDD适用于需要快速迭代计算的任务。
    • 惰性计算:RDD的转换操作是惰性的,即它们不会立即执行,而是等到真正需要结果时才触发计算。这种机制使得Spark能够优化执行计划,提高性能。
    • 容错性:RDD采用基于血缘的高效容错机制。在RDD的设计中,数据是只读的不可修改,如果需要修改数据,必须从父RDD转换生成新的子RDD,由此在不同的RDD之间建立血缘关系。因此RDD是天生具有高容错机制的特殊集合,当一个RDD失效的时候,只需要通过重新计算上游的父RDD来重新生成丢失的RDD数据,而不需要通过数据冗余的方式实现容错。
    • 不可变性:一旦创建,RDD的内容就不能被修改。这种不可变性有助于实现数据的容错性和并行性。
    • 可分区性:RDD可以将数据集划分为多个分区,每个分区可以独立地进行操作,从而实现并行处理。分区数决定了数据如何被分配到集群中的计算节点,合适的分区数可以提高计算效率和资源利用率。

二、操作与转换

RDD操作与转换

  1. 创建RDD

    • 可以从已存在的集合(如列表或数组)创建RDD。
    • 可以从外部数据源(如HDFS、本地文件系统、Hive表等)读取数据创建RDD。
    • 可以使用已存在的RDD来创建新的RDD,通过对现有RDD进行转换操作。
  2. RDD转换(Transformations)

    • 转换操作用于从一个RDD生成新的RDD,通常是通过映射、过滤、合并等方式进行数据转换。常见的转换操作包括mapfilterflatMapreduceByKey等。
    • 转换操作是惰性的,不会立即执行计算,而是等到行动操作被触发时才执行。
  3. RDD行动(Actions)

    • 行动操作用于触发实际的计算,将RDD的结果返回到驱动程序或保存到外部存储系统。常见的行动操作包括collectcountsaveAsTextFile等。
    • 只有当行动操作被触发时,Spark才会根据依赖关系图计算RDD的结果。

三、存储级别与持久化

  1. 存储级别:RDD的存储级别决定了数据在内存和磁盘之间的存储方式。常见的存储级别包括MEMORY_ONLY(仅在内存中存储)、MEMORY_AND_DISK(在内存中存储,不够时写入磁盘)、DISK_ONLY(仅在磁盘中存储)等。
  2. 持久化:可以使用cachepersist方法将RDD存储在内存中,以供多次计算使用。持久化可以提高数据处理的效率,减少重复计算的时间。

四、依赖关系与容错机制

  1. 依赖关系:RDD之间的转换操作会创建依赖关系,这些依赖关系决定了数据如何在整个集群中流动。依赖关系分为窄依赖和宽依赖两种。
    • 窄依赖:子RDD的每个分区依赖于父RDD的一个分区。
    • 宽依赖:子RDD的每个分区可能依赖于父RDD的所有分区,这通常需要进行shuffle操作。
  2. 容错机制:RDD的容错机制基于其血缘信息和不可变性。当一个RDD的某个分区的数据计算失败时,Spark可以使用原始数据和转换操作重新计算该分区,从而实现容错。

五、优化与性能调优

  1. 合理使用缓存:通过缓存常用的RDD,可以减少重复计算的时间,提高数据处理的效率。
  2. 选择合适的分区器:根据数据的特征和计算任务的需求,选择合适的分区器可以优化数据的存储和计算过程。
  3. 调整分区数量:根据集群的配置和计算任务的需求,调整RDD的分区数量可以提高计算效率和资源利用率。

综上所述,RDD是Spark中最重要的抽象之一,它为分布式数据处理提供了一个强大而灵活的模型。通过理解和使用RDD的特性、操作、存储级别、依赖关系以及优化方法,可以构建高效的数据处理流程,并充分利用Spark集群的计算资源。

常见操作

以下是RDD(弹性分布式数据集)的操作及其说明的表格形式展示:

RDD操作说明示例
创建操作
sc.parallelize从本地集合创建RDDval rdd = sc.parallelize(1 to 10)
sc.textFile从外部文件创建RDDval rdd = sc.textFile(“hdfs://…”)
转换操作(Transformation)返回一个新的RDD
map对RDD中的每个元素应用一个函数val mappedRdd = rdd.map(x => x * 2)
filter过滤RDD中的元素,返回满足条件的元素val filteredRdd = rdd.filter(_ > 5)
flatMap类似于map,但每个输入元素可以映射到0或多个输出元素val flatMappedRdd = rdd.flatMap(x => 1 to x)
mapPartitions对RDD的每个分区应用一个函数val mapPartitionsRdd = rdd.mapPartitions(iter => iter.map(_ * 2))
mapPartitionsWithIndex对RDD的每个分区及其索引应用一个函数val indexedRdd = rdd.mapPartitionsWithIndex((index, iter) => iter.map(x => (index, x)))
reduceByKey对键值对RDD中相同键的值进行归约val reducedRdd = rdd.reduceByKey(_ + _)
groupByKey对键值对RDD中相同键的值进行分组val groupedRdd = rdd.groupByKey()
sortByKey对键值对RDD的键进行排序val sortedRdd = rdd.sortByKey()
join对两个键值对RDD中相同键的值进行内连接val joinedRdd = rdd1.join(rdd2)
cogroup对两个键值对RDD中相同键的值进行分组,并返回每个键对应的两个值集合val cogroupedRdd = rdd1.cogroup(rdd2)
行动操作(Action)向驱动程序返回结果或写入外部系统
collect将RDD的所有元素收集到驱动程序中val collected = rdd.collect()
count返回RDD中元素的个数val count = rdd.count()
take返回RDD中的前n个元素val taken = rdd.take(5)
saveAsTextFile将RDD的内容保存到文本文件中rdd.saveAsTextFile(“hdfs://…”)
foreach对RDD中的每个元素应用一个函数(通常用于副作用)rdd.foreach(println)

请注意,以上表格仅列出了RDD的一些常见操作,并非全部。RDD的操作非常丰富,可以根据具体需求选择合适的操作来处理数据。同时,RDD的操作具有惰性特性,即转换操作不会立即执行,而是等到行动操作被触发时才执行。这种机制有助于优化计算过程,提高性能。

支持的数据格式

Apache Spark 的 Resilient Distributed Datasets (RDDs) 支持多种数据格式的读取。以下是一些常见的数据格式及其对应的 Java 代码样例:
spark支持的数据格式

1.文本文件 (Text Files)

import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.SparkConf;

public class TextFileRDD {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("TextFileRDD").setMaster("local");
        JavaSparkContext sc = new JavaSparkContext(conf);

        // 读取文本文件
        JavaRDD<String> textFile = sc.textFile("path/to/textfile.txt");

        // 打印前10行
        textFile.take(10).forEach(System.out::println);

        sc.stop();
    }
}

2. CSV 文件

Spark 官方没有直接提供 CSV 文件的读取功能,但你可以使用 spark-csv 库(Spark 2.0 及以前)或者 DataFrameReader(Spark 2.0 及以后)来读取 CSV 文件。

使用 DataFrameReader 读取 CSV 文件:

import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;

public class CSVFileRDD {
    public static void main(String[] args) {
        SparkSession spark = SparkSession.builder()
                .appName("CSVFileRDD")
                .master("local")
                .getOrCreate();

        // 读取CSV文件
        Dataset<Row> csvDF = spark.read().option("header", "true").csv("path/to/csvfile.csv");

        // 显示内容
        csvDF.show();

        spark.stop();
    }
}

3. JSON 文件

import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;

public class JSONFileRDD {
    public static void main(String[] args) {
        SparkSession spark = SparkSession.builder()
                .appName("JSONFileRDD")
                .master("local")
                .getOrCreate();

        // 读取JSON文件
        Dataset<Row> jsonDF = spark.read().json("path/to/jsonfile.json");

        // 显示内容
        jsonDF.show();

        spark.stop();
    }
}

4. Parquet 文件

import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;

public class ParquetFileRDD {
    public static void main(String[] args) {
        SparkSession spark = SparkSession.builder()
                .appName("ParquetFileRDD")
                .master("local")
                .getOrCreate();

        // 读取Parquet文件
        Dataset<Row> parquetDF = spark.read().parquet("path/to/parquetfile.parquet");

        // 显示内容
        parquetDF.show();

        spark.stop();
    }
}

5. Sequence Files

import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.SparkConf;
import scala.Tuple2;

public class SequenceFileRDD {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("SequenceFileRDD").setMaster("local");
        JavaSparkContext sc = new JavaSparkContext(conf);

        // 读取SequenceFile
        JavaPairRDD<IntWritable, Text> sequenceFile = sc.sequenceFile("path/to/sequencefile", IntWritable.class, Text.class);

        // 打印键值对
        sequenceFile.collect().forEach(tuple -> System.out.println(tuple._1() + " : " + tuple._2()));

        sc.stop();
    }
}

6.Hadoop文件读取

在Apache Spark中读取Hadoop数据通常涉及访问存储在Hadoop分布式文件系统(HDFS)上的数据,或者通过Hadoop的输入格式(InputFormat)读取数据。以下是一些使用Spark读取Hadoop数据的Java代码示例:

A. 读取HDFS上的文本文件

这是最简单的情况,因为Spark可以直接通过textFile方法读取HDFS上的文本文件,就像读取本地文件系统上的文件一样。

import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.SparkConf;

public class HDFSTextFileReader {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("HDFSTextFileReader").setMaster("local");
        JavaSparkContext sc = new JavaSparkContext(conf);

        // 假设HDFS上的文件路径为hdfs://namenode:port/path/to/textfile.txt
        String hdfsFilePath = "hdfs://namenode:port/path/to/textfile.txt";
        JavaRDD<String> textFile = sc.textFile(hdfsFilePath);

        // 处理数据,例如打印前10行
        textFile.take(10).forEach(System.out::println);

        sc.stop();
    }
}
B. 使用Hadoop的InputFormat读取数据

对于存储在Hadoop中的非文本数据,或者需要更复杂的数据解析,你可以使用Hadoop的InputFormat。这通常涉及创建一个Hadoop配置对象,并设置必要的属性,然后使用Spark的newAPIHadoopFilenewAPIHadoopRDD方法。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.SparkConf;
import scala.Tuple2;

public class HadoopInputFormatReader {
    public static void main(String[] args) throws Exception {
        SparkConf conf = new SparkConf().setAppName("HadoopInputFormatReader").setMaster("local");
        JavaSparkContext sc = new JavaSparkContext(conf);

        // 创建Hadoop配置对象
        Configuration hadoopConf = new Configuration();
        Job job = Job.getInstance(hadoopConf, "Read from Hadoop InputFormat");
        job.setJarByClass(HadoopInputFormatReader.class);

        // 设置输入路径
        FileInputFormat.addInputPath(job, new Path("hdfs://namenode:port/path/to/hadoopfile"));

        // 使用newAPIHadoopRDD读取数据
        JavaPairRDD<LongWritable, Text> hadoopRDD = sc.newAPIHadoopRDD(
                hadoopConf,
                job.getInputFormatClass(),
                LongWritable.class,
                Text.class
        );

        // 处理数据,例如打印键值对
        hadoopRDD.collect().forEach(tuple -> System.out.println(tuple._1() + " : " + tuple._2().toString()));

        sc.stop();
    }
}

在这个例子中,我们假设Hadoop文件是使用LongWritable作为键(通常是偏移量)和Text作为值(行内容)存储的。你需要根据你的Hadoop文件格式调整键和值的类型。

注意事项
  1. Hadoop配置:确保你的Hadoop配置(如core-site.xmlhdfs-site.xml)在Spark的classpath中,或者通过编程方式设置必要的配置属性。
  2. 依赖项:在你的项目中包含Hadoop和Spark的依赖项。
  3. HDFS访问:确保Spark能够访问HDFS。这通常意味着Spark集群的节点需要配置为能够访问HDFS的namenode和datanode。
  4. 性能考虑:对于大规模数据集,避免使用collect()方法将数据从集群拉取到驱动程序。相反,使用转换和行动操作在集群上处理数据。
    这些示例展示了如何使用 Java 代码在 Spark 中读取不同类型的文件。根据具体需求,你可能需要调整路径、选项和其他参数。

一个完整代码示例

以下是一个使用Java编写的基本RDD(弹性分布式数据集)代码示例,该示例展示了如何在Apache Spark中创建RDD、执行转换操作以及行动操作。

首先,请确保您已经设置好Spark环境,并导入了必要的Spark库。

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import java.util.Arrays;
import java.util.List;

public class RDDExample {
    public static void main(String[] args) {
        // 配置Spark
        SparkConf conf = new SparkConf().setAppName("RDD Example").setMaster("local");
        JavaSparkContext sc = new JavaSparkContext(conf);

        // 从本地集合创建RDD
        List<Integer> data = Arrays.asList(1, 2, 3, 4, 5);
        JavaRDD<Integer> rdd = sc.parallelize(data);

        // 转换操作:将每个元素乘以2
        JavaRDD<Integer> transformedRDD = rdd.map(x -> x * 2);

        // 行动操作:收集RDD中的所有元素并打印
        List<Integer> collectedData = transformedRDD.collect();
        for (Integer num : collectedData) {
            System.out.println(num);
        }

        // 关闭Spark上下文
        sc.close();
    }
}

在这个示例中,我们:

  1. 配置了Spark环境,并创建了一个JavaSparkContext对象,它是与Spark集群交互的主要入口点。
  2. 使用sc.parallelize方法从本地集合创建了一个RDD。
  3. 对RDD执行了一个转换操作,使用map函数将RDD中的每个元素乘以2。
  4. 使用collect行动操作将转换后的RDD收集到驱动程序中,并打印出结果。
  5. 最后,关闭了Spark上下文以释放资源。

请注意,setMaster("local")配置意味着Spark将在本地模式下运行,仅使用一个线程。如果您想在集群上运行此代码,请将setMaster的值更改为集群管理器(如YARN、Mesos或Spark Standalone)的URL。

此外,由于collect操作会将数据从集群节点收集到驱动程序中,因此在处理大量数据时可能会导致内存溢出。在实际应用中,应谨慎使用此类行动操作,并考虑使用其他行动操作(如saveAsTextFile)将结果写入外部存储系统。

RDD、Datasets和DataFrame的对比

以下是RDD、Datasets和DataFrame的对比表格,展示了它们之间的主要区别和特性:

特性/组件RDDDataFrameDatasets
基础弹性分布式数据集,Spark最基础的数据结构分布式数据集合,带有Schema元信息的二维表格结构化API的基本类型,基于DataFrame的扩展
数据格式可处理结构化或非结构化数据仅使用结构化和半结构化数据可处理结构化或非结构化数据
Schema信息需要手动定义可以根据数据自动发现可以自动发现文件的Schema信息
类型安全编译时类型安全性较弱,主要在运行时检测属性错误提供编译时类型安全性提供编译时类型安全性,且支持强类型、面向对象编程的接口
序列化使用Java序列化,开销较大使用off-heap内存减少开销,动态生成字节码使用Spark内部的Tungsten二进制格式进行序列化,无需垃圾回收
优化无内置优化引擎,不能使用Spark高级优化器使用Catalyst优化器进行查询优化使用优化器优化执行计划
API支持提供Java、Scala、Python和R语言的API提供Java、Scala、Python和R语言的APIScala和Java支持较完善,Python和R语言的API在开发中
操作便捷性底层操作,需要手动管理Schema和分区高级抽象,易于使用,支持SQL操作兼具DataFrame的便捷性和RDD的功能性
适用场景需要对数据集进行底层转换和操作时需要高级抽象和便捷操作时,如探索性分析和汇总统计需要类型安全和自定义结构时,如处理复杂数据类型和转换

这个表格概括了RDD、DataFrame和Datasets在Spark中的主要特性和区别。RDD提供了最底层的数据抽象,适用于需要细粒度控制和自定义操作的场景。DataFrame则提供了更高层次的抽象,易于使用且支持SQL操作,适用于数据分析和探索性场景。Datasets则结合了RDD和DataFrame的优点,提供了类型安全和面向对象编程的接口,适用于需要处理复杂数据类型和转换的场景。在选择使用哪个组件时,需要根据具体的应用场景和需求来决定。

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

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

相关文章

(Linux驱动学习 - 8).信号异步通知

一.异步通知简介 1.信号简介 信号类似于我们硬件上使用的“中断”&#xff0c;只不过信号是软件层次上的。算是在软件层次上对中断的一种模拟&#xff0c;驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了&#xff0c;应用程序获取到信号以后就可以从驱动设备中…

论文阅读——联邦忘却学习研究综述

文章基本信息 作者&#xff1a; 王鹏飞魏宗正周东生宋威肖蕴明孙庚于硕张强 机构&#xff1a; 大连理工大学计算机科学与技术学院大连理工大学社会计算与认知智能教育部重点实验室大连大学先进设计与智能计算教育部重点实验室美国西北大学计算机科学系吉林大学计算机科学与…

QT调用libusb库stm32407上下位机

安富莱USB上位机教程 参考安富莱的视频&#xff0c;不过这里 调用是libusb最新的库 可以参考上一个文章&#xff1a; QT调用最新的libusb库 https://editor.csdn.net/md/?articleId142733711 调试结果&#xff1a; 资源地址&#xff1a; 上位机&#xff1a;https://downl…

基于pytorch的手写数字识别-训练+使用

import pandas as pd import numpy as np import torch import matplotlib import matplotlib.pyplot as plt from torch.utils.data import TensorDataset, DataLoadermatplotlib.use(tkAgg)# 设置图形配置 config {"font.family": serif,"mathtext.fontset&q…

Maven 高级之分模块设计与继承、聚合

在软件开发中&#xff0c;随着项目规模的扩大&#xff0c;代码量和复杂度不断增加&#xff0c;传统的一体化开发模式逐渐暴露出诸多问题。为了解决这些问题&#xff0c;模块化开发应运而生&#xff0c;而 Maven 正是模块化开发的利器&#xff0c;它提供的继承和聚合机制为构建和…

fiddler抓包20_弱网模拟

课程大纲 ① 打开CustomRules.js文件&#xff1a;Fiddler快捷键“CtrlR”(或鼠标点击&#xff0c;菜单栏 - Rules - Customize Rules)。 ② 设置速率&#xff1a;“CtrlF”&#xff0c;搜索 “m_SimulateModem”&#xff0c;定位至函数。在函数里设置上传、下载速率&#xff0c…

ESP8266模块(WIFI STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 3.ESP8266基础AT指令介绍 4.ESP8266基础工作模式 三、程序设计 main.c文件 esp8266.h文件 esp8266.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 ESP8266是一款嵌入式系统级芯片&#xff0c;它集成了Wi…

将自己写好的项目部署在自己的云服务器上

准备工作 这里呢我要下载的终端软件是Xshell 如图&#xff1a; 自己准备好服务器&#xff0c;我这里的是阿里云的服务器&#xff0c; 如图&#xff1a; 这两个准备好之后呢&#xff0c;然后对我们的项目进行打包。 如图&#xff1a; 这里双击打包就行了。 找到自己打成jar包…

零基础多图详解图神经网络(GNN/GCN)【李沐论文精读】

A Gentle Introduction to Graph Neural Networks 在上图中&#xff0c;每一层都是一层网络&#xff0c;每一层的节点都受到下一层中自身节点和邻居节点的影响。如果网络比较深&#xff0c;是可以处理到一幅图中较大范围的节点。 前言 图神经网络在应用上还只是起步阶段&…

基于SpringBoot健身房管理系统【附源码】

效果如下&#xff1a; 系统首页界面 系统注册详细页面 健身课程详细页面 后台登录界面 管理员主页面 员工界面 健身教练界面 员工主页面 健身教练主页面 研究背景 随着生活水平的提高和健康意识的增强&#xff0c;现代人越来越注重健身。健身房作为一种专业的健身场所&#x…

日期类的实现(C++)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 前言 日期类是六个成员函数学习的总结和拓展&#xff0c;是实践的体现 创建文件 构造函…

HCIP--以太网交换安全(二)

端口安全 一、端口安全概述 1.1、端口安全概述&#xff1a;端口安全是一种网络设备防护措施&#xff0c;通过将接口学习的MAC地址设为安全地址防止非法用户通信。 1.2、端口安全原理&#xff1a; 类型 定义 特点 安全动态MAC地址 使能端口而未是能Stichy MAC功能是转换的…

在VMware WorkStation上安装飞牛OS(NAS系统)

对于NAS系统&#xff0c;小白相信很多小伙伴都不陌生&#xff0c;在许多场景下也能看得到&#xff0c;它其实可以算是文件存储服务器&#xff0c;当然&#xff0c;你如果给它加上其他服务的话&#xff0c;它也能变成网页服务器、Office协同办公服务器等等。 有许多小伙伴都拿这…

信息安全工程师(38)防火墙类型与实现技术

一、防火墙类型 按软、硬件形式分类 软件防火墙&#xff1a;通过软件实现防火墙功能&#xff0c;通常安装在个人计算机或服务器上&#xff0c;用于保护单个设备或小型网络。硬件防火墙&#xff1a;采用专门的硬件设备来实现防火墙功能&#xff0c;通常部署在企业网络边界或数据…

基于SpringBoot图书馆预约与占座小程序【附源码】

效果如下&#xff1a; 首页界面 用户登录界面 查看座位界面 管理员登录界面 管理员主界面 座位分布信息界面 预约信息界面 研究背景 随着互联网技术的不断进步和智能手机的广泛普及&#xff0c;图书馆作为知识获取和学习的重要场所&#xff0c;其管理方式也在逐步向信息化和智…

系统架构设计师论文《论企业应用系统的数据持久层架构设计》精选试读

论文真题 数据持久层&#xff08;Data Persistence Layer&#xff09;通常位于企业应用系统的业务逻辑层和数据源层之间&#xff0c;为整个项目提供一个高层、统一、安全、并发的数据持久机制&#xff0c;完成对各种数据进行持久化的编程工作&#xff0c;并为系统业务逻辑层提…

【电路基础 · 4】电路的图;KCL、KVL巩固;支路电流法

一、电路的图 1.线性电路的一般的分析方法 2.计算方法 掌握计算方法。 3.支路 branch 和 节点 node 对于支路&#xff0c;经常取电压、电流为同向。 4.KCL 巩固 巩固一下之前学习的 KCL。 但是需要注意&#xff1a; 对于一个电路&#xff0c;如果有 n 个节点&#xff0c;那…

浅学React和JSX

用antd做个人博客卡到前端了&#xff0c;迫不得已来学react&#xff0c;也是干上全栈了-- --学自尚硅谷张天禹react React就是js框架&#xff0c;可以理解为对js做了封装&#xff0c;那么封装后的肯定用起来更方便。 相关JS库 react.js&#xff1a;React核心库。react-dom.js&a…

计算机基本组成和工作原理(Basic Components and Working Principles of Computers)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

node配置swagger

安装swagger npm install swagger-jsdoc swagger-ui-express 创建 swagger.js 配置文件 ​ const path require(path); const express require(express); const swaggerUI require(swagger-ui-express); const swaggerJsDoc require(swagger-jsdoc); // 修改 swaggerDoc…