Doris集成Spark读写的简单示例

news2024/11/16 19:32:09

Doris集成Spark读写的简单示例


文章目录

  • Doris集成Spark读写的简单示例
    • 0、写在前面
    • 1、Spark Doris Connector介绍
    • 2、基本示例
      • 2.1 提前准备表和数据
      • 2.2 新建项目
      • 2.3 使用SQL方式进行读写
        • 2.3.1 代码
        • 2.3.2 相关Error
      • 2.4 使用DataFrame方式读写数据(**batch**)
        • 2.4.1 代码
        • 2.4.2 写入数据
        • 2.4.2 读取数据
      • 2.5 RDD演示
      • 2.6 写入数据的其他方式
    • 3. 配置项说明
      • 3.1 通用配置项
      • 3.2 SQL 和 Dataframe 专有配置
      • 3.3 RDD 专有配置
      • 3.4 Doris 和 Spark 列类型映射关系
    • 4. 使用 **JDBC** 的方式
    • 5. 其他集成系统
    • 6. 参考资料


0、写在前面

  • Doris版本:Doris-1.1.5
  • Spark版本:Spark-3.0.0
  • IDEA版本:IntelliJ IDEA 2019.2.3
  • Scala版本:Scala-2.12.11

1、Spark Doris Connector介绍

  • 介绍

Spark Doris Connector 支持通过 Spark 读取 Doris 中存储的数据,也支持通过Spark写入数据到Doris。

代码库地址:https://github.com/apache/incubator-doris-spark-connector

  • 版本兼容
ConnectorSparkDorisJavaScala
2.3.4-2.11.xx2.x0.12+82.11
3.1.2-2.12.xx3.x0.12.+82.12
3.2.0-2.12.xx3.2.x0.12.+82.12
  • 使用Maven进行管理
<dependency>
  <groupId>org.apache.doris</groupId>
   <!-- spark3.x使用这个版本 -->
  <artifactId>spark-doris-connector-3.1_2.12</artifactId>
   <!-- spark2.x使用这个版本 -->
  <!--artifactId>spark-doris-connector-2.3_2.11</artifactId-->
  <version>1.1.0</version>
</dependency>

Note:同时此处的Spark Doris Connector版本不要使用官网的1.0.1版本,下文会演示相关error

2、基本示例

2.1 提前准备表和数据

开启doris的fe、be

-- 创建表table1
CREATE TABLE table1 (
    siteid INT DEFAULT '10',
    citycode SMALLINT,
    username VARCHAR(32) DEFAULT '', 
    pv BIGINT SUM DEFAULT '0'
)
AGGREGATE KEY(siteid, citycode, username) 
DISTRIBUTED BY HASH(siteid) BUCKETS 10
PROPERTIES("replication_num" = "1");

-- 插入数据
insert into table1 values (1,1,'jim',2),
(2,1,'grace',2),
(3,2,'tom',2),
(4,3,'bush',3),
(5,3,'helen',3);

2.2 新建项目

  • 新建一个名为doris-module的Maven工程

  • 准备Spark环境:pom.xml

<properties>
    <scala.binary.version>2.12</scala.binary.version>
    <spark.version>3.0.0</spark.version>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>

    <!-- Spark 的依赖引入 -->
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_${scala.binary.version}</artifactId>
        <scope>provided</scope>
        <version>${spark.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-sql_${scala.binary.version}</artifactId>
        <scope>provided</scope>
        <version>${spark.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-hive_${scala.binary.version}</artifactId>
        <scope>provided</scope>
        <version>${spark.version}</version>
    </dependency>
    <!-- 引入 Scala -->
    <dependency>
        <groupId>org.scala-lang</groupId>
        <artifactId>scala-library</artifactId>
        <version>2.12.11</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.47</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.49</version>
    </dependency>

    <!--spark-doris-connector-->
    <dependency>
        <groupId>org.apache.doris</groupId>
        <artifactId>spark-doris-connector-3.1_2.12</artifactId>
        <!--<artifactId>spark-doris-connector- 2.3_2.11</artifactId>-->
        <version>1.1.0</version>
    </dependency>

</dependencies>

<build>
    <plugins>
        <!--编译 scala 所需插件-->
        <plugin>
            <groupId>org.scala-tools</groupId>
            <artifactId>maven-scala-plugin</artifactId>
            <version>2.15.1</version>
            <executions>
                <execution>
                    <id>compile-scala</id>
                    <goals>
                        <goal>add-source</goal>
                        <goal>compile</goal>
                    </goals>
                </execution>
                <execution>
                    <id>test-compile-scala</id>
                    <goals>
                        <goal>add-source</goal>
                        <goal>testCompile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>net.alchim31.maven</groupId>
            <artifactId>scala-maven-plugin</artifactId>
            <version>3.2.2</version>
            <executions>
                <execution>
                    <!-- 声明绑定到 maven 的 compile 阶段 -->
                    <goals>
                        <goal>compile</goal>
                        <goal>testCompile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

        <!-- assembly 打包插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <archive>
                    <manifest>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with- dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
        <!--<plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.6.1</version>
                    &lt;!&ndash; 所有的编译都依照 JDK1.8 &ndash;&gt;
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>-->
    </plugins>
</build>

2.3 使用SQL方式进行读写

2.3.1 代码

import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession

object SQLDemo {
    def main(args: Array[String]): Unit = {
        // TODO 如果要打包提交集群执行,请注释掉(此处直接在本地演示)
        val sparkConf = new SparkConf().setAppName("SQLDemo").setMaster("local[2]") 
        val	sparkSession = SparkSession.builder().config(sparkConf).getOrCreate()

        sparkSession.sql( """
                            |CREATE TEMPORARY VIEW spark_doris
                            |USING doris
                            |OPTIONS(
                            | "table.identifier"="test_db.table1",
                            | "fenodes"="node01:8030",
                            | "user"="test",
                            | "password"="test"
                            |); """.stripMargin)

        // 读取数据
        	sparkSession.sql("select * from spark_doris").show()
        // 写入数据
//        sparkSession.sql("insert into spark_doris values(99,99,'haha',5)")
    }
}

读取数据运行结果:

在这里插入图片描述

验证结果正确性:进入fe连接MySQL,查询table1表的数据,结果如下

在这里插入图片描述

运行结果与实际结果相一致

  • 写入数据

运行结束,查询table1表的数据,结果如下:

在这里插入图片描述

可以看到,利用spark写入数据到Doris已经成功了

2.3.2 相关Error

一开始,右键项目Add framework support没有Scala

  • 选中scala相关依赖并删除掉(如下图所示)

在这里插入图片描述

在这里插入图片描述

重新右键Add framework support就可以添加Scala环境了

java.lang.NoClassDefFoundError: org/apache/spark/SparkConf

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/spark/SparkConf
	at cn.whybigdata.doris.spark.SQLDemo$.main(SQLDemo.scala:7)
	at cn.whybigdata.doris.spark.SQLDemo.main(SQLDemo.scala)
Caused by: java.lang.ClassNotFoundException: org.apache.spark.SparkConf
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 2 more

Process finished with exit code 1

因为在pom.xml文件中,spark-core_x.xx、spark-sql_x.xx、spark-hive_x.xx都是provided的范围,解决方案如下:

  • 选择Edit Run/Debug configuration ,选中需要执行的Application,勾选Include dependencies with "Provided" scope即可,如下图所示

在这里插入图片描述

上述方式只对当前.scala程序起作用,如果要对该项目的所有Application起作用,可以选择template,然后选择Application,勾选Include dependencies with "Provided" scope即可

在这里插入图片描述

还有一种更直接的方式:直接注释掉spark-core_x.xx、spark-sql_x.xx、spark-hive_x.xx依赖的scope范围,但是这种方式不推荐,因为大多数情况下是选择打包到集群上执行,而非本地,而集群一般都是已经拥有spark这些以来环境的,使用provided的scope范围,在集群中执行时是不会加载的。

  • [Bug] spark doris connector read table error: Doris FE’s response cannot map to schema.

原因是1.0.1版本的spark-doris-connector自身的bug,已经在1.1.0版本修复了

2.4 使用DataFrame方式读写数据(batch

2.4.1 代码

import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession

object DataFrameDemo {
    def main(args: Array[String]): Unit = {
        //TODO 如果要打包提交集群执行,请注释掉
        val sparkConf = new SparkConf().setAppName("DataFrameDemo").setMaster("local[2]")
        val	sparkSession = SparkSession.builder().config(sparkConf).getOrCreate()

        // TODO 写入数据
//        import sparkSession.implicits._
//        val mockDataDF = List(
//            (11,23, "haha", 8),
//            (11, 3, "hehe", 9),
//            (11, 3, "heihei", 10)
//        ).toDF("siteid", "citycode", "username","pv")
//        mockDataDF.show(5)
//
//        mockDataDF.write.format("doris")
//          .option("doris.table.identifier", "test_db.table1")
//          .option("doris.fenodes", "node01:8030")
//          .option("user", "test")
//          .option("password", "test")
//          // 指定你要写入的字段
//          //	.option("doris.write.fields", "user")
//          .save()

        // TODO 读取数据
        val dorisSparkDF = sparkSession.read.format("doris")
          .option("doris.table.identifier", "test_db.table1")
          .option("doris.fenodes", "hadoop102:8030")
          .option("user", "test")
          .option("password", "test")
          .load()
        dorisSparkDF.show()
    }
}

2.4.2 写入数据

运行结果:

在这里插入图片描述

验证:

在这里插入图片描述

2.4.2 读取数据

运行结果:

在这里插入图片描述

2.5 RDD演示

RDD目前只支持读取数据

  • 代码
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.SparkSession


object RDDDemo {
    def main(args: Array[String]): Unit = {
        //TODO 如果要打包提交集群执行,请注释掉
        val sparkConf = new SparkConf().setAppName("RDDDemo").setMaster("local[2]")
        val	sc = new SparkContext(sparkConf)

        // TODO 读取数据
        import org.apache.doris.spark._
        val dorisSparkRDD = sc.dorisRDD(
            tableIdentifier = Some("test_db.table1"),
            cfg = Some(Map(
                "doris.fenodes" -> "node01:8030",
                "doris.request.auth.user" -> "test",
                "doris.request.auth.password" -> "test"
            ))
        )

        dorisSparkRDD.collect().foreach(println)

    }
}

运行结果:

在这里插入图片描述

2.6 写入数据的其他方式

关于通过Saprk写入数据到Doris,还可以通过StructStreaming的方式,

  • 官方示例
## stream sink(StructuredStreaming)
val kafkaSource = spark.readStream
  .option("kafka.bootstrap.servers", "$YOUR_KAFKA_SERVERS")
  .option("startingOffsets", "latest")
  .option("subscribe", "$YOUR_KAFKA_TOPICS")
  .format("kafka")
  .load()
kafkaSource.selectExpr("CAST(key AS STRING)", "CAST(value as STRING)")
  .writeStream
  .format("doris")
  .option("checkpointLocation", "$YOUR_CHECKPOINT_LOCATION")
  .option("doris.table.identifier", "$YOUR_DORIS_DATABASE_NAME.$YOUR_DORIS_TABLE_NAME")
    .option("doris.fenodes", "$YOUR_DORIS_FE_HOSTNAME:$YOUR_DORIS_FE_RESFUL_PORT")
  .option("user", "$YOUR_DORIS_USERNAME")
  .option("password", "$YOUR_DORIS_PASSWORD")
  //其它选项
  //指定你要写入的字段
  .option("doris.write.fields","$YOUR_FIELDS_TO_WRITE")
  .start()
  .awaitTermination()

3. 配置项说明

3.1 通用配置项

KeyDefault ValueComment
doris.fenodesDoris FE http 地址,支持多个地址,使用逗号分隔
doris.table.identifierDoris 表名,如:db1.tbl1
doris.request.retries3向Doris发送请求的重试次数
doris.request.connect.timeout.ms30000向Doris发送请求的连接超时时间
doris.request.read.timeout.ms30000向Doris发送请求的读取超时时间
doris.request.query.timeout.s3600查询doris的超时时间,默认值为1小时,-1表示无超时限制
doris.request.tablet.sizeInteger.MAX_VALUE一个RDD Partition对应的Doris Tablet个数。 此数值设置越小,则会生成越多的Partition。从而提升Spark侧的并行度,但同时会对Doris造成更大的压力。
doris.batch.size1024一次从BE读取数据的最大行数。增大此数值可减少Spark与Doris之间建立连接的次数。 从而减轻网络延迟所带来的额外时间开销。
doris.exec.mem.limit2147483648单个查询的内存限制。默认为 2GB,单位为字节
doris.deserialize.arrow.asyncfalse是否支持异步转换Arrow格式到spark-doris-connector迭代所需的RowBatch
doris.deserialize.queue.size64异步转换Arrow格式的内部处理队列,当doris.deserialize.arrow.async为true时生效
doris.write.fields指定写入Doris表的字段或者字段顺序,多列之间使用逗号分隔。 默认写入时要按照Doris表字段顺序写入全部字段。
sink.batch.size10000单次写BE的最大行数
sink.max-retries1写BE失败之后的重试次数
sink.properties.*Stream Load 的导入参数。 例如: ‘sink.properties.column_separator’ = ', ’
doris.sink.task.partition.sizeDoris写入任务对应的 Partition 个数。Spark RDD 经过过滤等操作,最后写入的 Partition 数可能会比较大,但每个 Partition 对应的记录数比较少,导致写入频率增加和计算资源浪费。 此数值设置越小,可以降低 Doris 写入频率,减少 Doris 合并压力。该参数配合 doris.sink.task.use.repartition 使用。
doris.sink.task.use.repartitionfalse是否采用 repartition 方式控制 Doris写入 Partition数。默认值为 false,采用 coalesce 方式控制(注意: 如果在写入之前没有 Spark action 算子,可能会导致整个计算并行度降低)。 如果设置为 true,则采用 repartition 方式(注意: 可设置最后 Partition 数,但会额外增加 shuffle 开销)。

3.2 SQL 和 Dataframe 专有配置

KeyDefault ValueComment
user访问Doris的用户名
password访问Doris的密码
doris.filter.query.in.max.count100谓词下推中,in表达式value列表元素最大数量。超过此数量,则in表达式条件过滤在Spark侧处理。

3.3 RDD 专有配置

KeyDefault ValueComment
doris.request.auth.user访问Doris的用户名
doris.request.auth.password访问Doris的密码
doris.read.field读取Doris表的列名列表,多列之间使用逗号分隔
doris.filter.query过滤读取数据的表达式,此表达式透传给Doris。Doris使用此表达式完成源端数据过滤。

3.4 Doris 和 Spark 列类型映射关系

Doris TypeSpark Type
NULL_TYPEDataTypes.NullType
BOOLEANDataTypes.BooleanType
TINYINTDataTypes.ByteType
SMALLINTDataTypes.ShortType
INTDataTypes.IntegerType
BIGINTDataTypes.LongType
FLOATDataTypes.FloatType
DOUBLEDataTypes.DoubleType
DATEDataTypes.StringType1
DATETIMEDataTypes.StringType1
BINARYDataTypes.BinaryType
DECIMALDecimalType
CHARDataTypes.StringType
LARGEINTDataTypes.StringType
VARCHARDataTypes.StringType
DECIMALV2DecimalType
TIMEDataTypes.DoubleType
HLLUnsupported datatype

Note:Connector中,将DATEDATETIME映射为String。由于Doris底层存储引擎处理逻辑,直接使用时间类型时,覆盖的时间范围无法满足需求。所以使用 String 类型直接返回对应的时间可读文本。

4. 使用 JDBC 的方式

这种方式是早期写法,不推荐,原因是:Spark 无法感知Doris 的数据分布,会导致打到 Doris 的查询压力非常大

  • 代码:
import java.util.Properties
import org.apache.spark.SparkConf
import org.apache.spark.sql.{SaveMode, SparkSession}

object JDBCDemo {
    def main(args: Array[String]): Unit = {
        val	sparkConf = new SparkConf().setAppName("JDBCDemo").setMaster("local[2]")
        val	sparkSession = SparkSession.builder().config(sparkConf).getOrCreate()

        // TODO 写入数据
//        import sparkSession.implicits._
//        val mockDataDF = List(
//            (21,23, "bj", 8),
//            (21,13, "sh", 9),
//            (21,31, "sz", 10)
//        ).toDF("siteid", "citycode", "username","pv")
//
//        val prop = new Properties()
//        prop.setProperty("user", "test")
//        prop.setProperty("password", "test")
//
//        mockDataDF.write.mode(SaveMode.Append)
//          .jdbc("jdbc:mysql://node01:9030/test_db", "table1", prop)

        // TODO 读取数据
        val df=sparkSession.read.format("jdbc")
        .option("url","jdbc:mysql://node01:9030/test_db")
        .option("user","test")
        .option("password","test")
        .option("dbtable","table1")
        .load()

        df.show()
    }
}
  • 写入数据

在这里插入图片描述

  • 读取数据

在这里插入图片描述

5. 其他集成系统

Doris还可以与Flink、DataX、MySQL、Logstash、ODBC外部表集成使用,可以直接参考官网

6. 参考资料

  • https://doris.apache.org/zh-CN/docs/dev/ecosystem/spark-doris-connector
  • https://9to5answer.com/java-lang-noclassdeffounderror-org-apache-spark-sql-sparksession
  • https://github.com/apache/doris-spark-connector/issues/39

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

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

相关文章

CS5261typec转HDMI|CS5260typec转VGA视频转换方案参考设计与PCB板开发

CS5261typec转HDMI|CS5260typec转VGA视频转换方案参考设计与PCB板开发 CS5261 CS5260分别是Type-C转HDMI或者VGA高性能 视频转换芯片&#xff0c;CS5261 是Type-C转HDMI 4K30HZ转换芯片 CS5260是Type-C转VGA 转换芯片。CS5261与CS5260两种芯片的功能和参数特性如下&#xff1…

热乎的面经——初出茅庐

⭐️前言⭐️ 本篇文章记录博主与2023.03.04面试上海柯布西公司&#xff0c;一面所被问及的面试问题&#xff0c;回答答案仅供参考。 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获&am…

EdgeYOLO学习笔记

EdgeYOLO学习笔记 EdgeYOLO: An Edge-Real-Time Object Detector Abstract 本文基于最先进的YOLO框架&#xff0c;提出了一种高效、低复杂度、无锚的目标检测器&#xff0c;该检测器可以在边缘计算平台上实时实现。为了有效抑制训练过程中的过拟合&#xff0c;我们开发了一种…

git分支

分支什么是分支在版本控制过程中&#xff0c;同时推进多个任务&#xff0c;为每个任务&#xff0c;我们就可以创建每个任务的单独分支。使用分支意味着程序员可以把自己的工作从开发主线上分离开来&#xff0c;开发自己分支的时候&#xff0c;不会影响主线分支的运行。对于初学…

DOM型XSS

DOM型XSSDOM是什么DOM型XSSDOM型XSS实操DOM是什么 DOM就是Document。 文档是由节点构成的集合&#xff0c;在DOM里存在许多不同类型的节点&#xff0c;主要有&#xff1a;元素节点、文本节点&#xff0c;属性节点。 元素节点&#xff1a;好比< body >< p >< h …

Go语言函数高级篇

Go语言函数高级篇1.高阶函数函数作为参数函数作为返回值2.匿名函数3.defer4.内置函数1.高阶函数 高阶函数分为函数作为参数和函数作为返回值两部分。 函数作为参数 函数可以作为参数&#xff1a; package mainimport "fmt"func add(x, y int) int {return x y }…

论文解析[11] CAT: Cross Attention in Vision Transformer

发表时间&#xff1a;2021 论文地址&#xff1a;https://arxiv.org/abs/2106.05786v1 文章目录摘要3 方法3.1 总体结构3.1.1 Inner-Patch Self-Attention Block3.1.2 Cross-Patch Self-Attention Block3.1.3 Cross Attention based Transformer结论摘要 使用图像patch来替换tr…

【Servlet篇4】cookie和session

在这一篇文章当中&#xff0c;我们提到了什么是cookie和session。 【网络原理8】HTTP请求篇_革凡成圣211的博客-CSDN博客HTTP的常见属性&#xff0c;URL&#xff0c;User-Agent&#xff0c;Refer,get 和post的区别https://blog.csdn.net/weixin_56738054/article/details/1291…

[数据集][VOC][目标检测]河道垃圾水面漂浮物数据集目标检测可用yolo训练-1304张介绍

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;1304 标注数量(xml文件个数)&#xff1a;1304 标注类别数&#xff1a;1 标注类别名称:["trash"] …

如何从错误中成长?

在上一篇文章“技术人的犯错成本”里&#xff0c;我和你聊了技术人可能会犯的各式各样的错误&#xff0c;也举了很多例子&#xff0c;说明了技术人犯错的成本。在竞争激烈的互联网时代&#xff0c;试错当然是好事&#xff0c;但了解错误成本&#xff0c;避免不应该犯的错误&…

测试概念及模型

今日目标掌握测试用例包含的基本内容使用等价类方法设计出测试用例1. 软件测试分类&#xff08;复习&#xff09;1.1 按阶段划分单元测试测试&#xff1a;针对单个功能进行测试&#xff0c;如&#xff1a;登录、购物车等开发&#xff08;更多的理解&#xff09;&#xff1a;针对…

C/C++实现发送邮件功能(附源码)

C++常用功能源码系列 本文是C/C++常用功能代码封装专栏的导航贴。部分来源于实战项目中的部分功能提炼,希望能够达到你在自己的项目中拿来就用的效果,这样更好的服务于工作实践。 专栏介绍:专栏讲本人近10年后端开发常用的案例,以高质量的代码提取出来,并对其进行了介绍。…

Linux -- 作业控制进程

作业控制 &#xff1a;官方 &#xff1a; 作业控制是一个命令行功能&#xff0c;允许一个shell 实例来运行和管理多个命令。作用 &#xff1a; 使用作业控制&#xff0c;可以选择性暂停&#xff0c;恢复&#xff0c;以及异步运行命令&#xff0c;让 shell 可以在子进程运行期…

【1599. 经营摩天轮的最大利润】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 你正在经营一座摩天轮&#xff0c;该摩天轮共有 4 个座舱 &#xff0c;每个座舱 最多可以容纳 4 位游客 。你可以 逆时针 轮转座舱&#xff0c;但每次轮转都需要支付一定的运行成本 runningCost 。摩…

基于flask+bootstrap+echarts+mysql的鱼村小馆订餐后台管理系统

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

[1.3.3]计算机系统概述——系统调用

文章目录第一章 计算机系统概述系统调用&#xff08;一&#xff09;什么是系统调用&#xff0c;有何作用&#xff08;二&#xff09;系统调用与库函数的区别&#xff08;三&#xff09;小例子&#xff1a;为什么系统调用是必须的&#xff08;四&#xff09;什么功能要用到系统调…

English Learning - L2-4 英音地道语音语调 双元音 [eɪ] [aɪ] [aʊ] [əʊ] [ɔɪ] 2023.03.2 周四

English Learning - L2-4 英音地道语音语调 双元音 [eɪ] [aɪ] [aʊ] [əʊ] [ɔɪ] 2023.03.2 周四节奏发音对比双元音概述双元音 [eɪ]发音技巧对应单词的发音对应句子的发音双元音 [aɪ]发音技巧对应单词的发音对应句子的发音双元音 [aʊ]发音技巧对应单词的发音对应句子的…

Android kotlin 系列讲解(进阶篇)高级项目架构模式 - MVVM

<<返回总目录 1、MVVM是什么 MVVM是Model-View-ViewModel的缩写&#xff0c;是一种高级项目架构模式。 MVVM架构可以将程序结构主要分成三个部分&#xff1a; Model&#xff1a;数据模型部分&#xff0c;包括从服务端获取的json数据或者从本地获取的数据等等View&…

【GlobalMapper精品教程】056:图像融合(高光谱+全色)操作案例教程

本文讲解GlobalMapperV24.0汉化版图像增强:融合(高光谱+全色)操作案例教程 文章目录 一、图像融合概述二、图像融合案例1. 加载数据2. 图像融合3. 图像导出一、图像融合概述 图像融合是指将不同类型传感器的影像进行融合,既能使图向具有较高的空间分辨率,又具有多光谱的特…

工具篇(五)炫酷排版,尽在LaTeX:让你的文档飞升吧!

作者的话 作为一个文本排版工具&#xff0c;latex一直以来都备受科研工作者、学生和出版社的青睐。但是对于初学者来说&#xff0c;latex的学习曲线可能会有些陡峭。因此&#xff0c;我写这篇博客旨在为初学者提供一个简单易懂的latex教程&#xff0c;让大家能够快速入门并掌握…