解决方案:如何在 Amazon EMR Serverless 上执行纯 SQL 文件?

news2025/1/16 3:00:00

长久已来,SQL以其简单易用、开发效率高等优势一直是ETL的首选编程语言,在构建数据仓库和数据湖的过程中发挥着不可替代的作用。Hive和Spark SQL也正是立足于这一点,才在今天的大数据生态中牢牢占据着主力位置。在常规的Spark环境中,开发者可以使用spark-sql命令直接执行SQL文件,这是一项看似平平无奇实则非常重要的功能:一方面,这一方式极大地降低了Spark的使用门槛,用户只要会写SQL就可以使用Spark;另一方面,通过命令行驱动SQL文件的执行可以极大简化SQL作业的提交工作,使得作业提交本身被“代码化”,为大规模工程开发和自动化部署提供了便利。

但遗憾的是,Amazon EMR Serverless 未能针对执行SQL文件提供原生支持,用户只能在Scala/Python代码中嵌入SQL语句,这对于倚重纯SQL开发数仓或数据湖的用户来说并不友好。为此,我们专门开发了一组用于读取、解析和执行SQL文件的工具类,借助这组工具类,用户可以在 Amazon EMR Serverless 上直接执行SQL文件,本文将详细介绍一下这一方案。

1. 方案设计

鉴于在Spark编程环境中执行SQL语句的方法是:spark.sql("..."),我们可以设计一个通用的作业类,该类在启动时会根据传入的参数读取指定位置上的SQL文件,然后拆分成单条SQL并调用spark.sql("...")执行。为了让作业类更加灵活和通用,还可以引入通配符一次加载并执行多个SQL文件。此外,ETL作业经常需要根据作业调度工具生成的时间参数去执行相应的批次,这些参数同样会作用到SQL中,所以,作业类还应允许用户在SQL文件中嵌入自定义变量,并在提交作业时以参数形式为自定义变量赋值。基于这种设计思路,我们开发了一个项目,实现了上述功能,项目地址为:

项目名称项目地址
Amazon EMR Serverless Utilitieshttps://github.com/bluishglc/emr-serverless-utils

项目中的com.github.emr.serverless.SparkSqlJob类即为通用的SQL作业类,该类接受两个可选参数,分别是:

参数说明取值示例
–sql-files指定要执行的SQL文件路径,支持Java文件系统通配符,可指定多个文件一起执行s3://my-spark-sql-job/sqls/insert-into-*.sql
–sql-paramsK1=V1,K2=V2,...形式为SQL文件中定义的${K1},${K2},…形式的变量设值CUST_CITY=NEW YORK,ORD_DATE=2008-07-15

该方案具备如下特性:

① 允许单一SQL文件包含多条SQL语句
② 允许在SQL文件中使用${K1},${K2},…的形式定义变量,并在执行作业时使用K1=V1,K2=V2,...形式的参数进行变量赋值
③ 支持Java文件系统通配符,可一次执行多个SQL文件

下面,我们将分别在AWS控制台和命令行两种环境下介绍并演示如何使用该项目的工具类提交纯SQL作业。

2. 实操演示

2.1. 环境准备

在EMR Serverless上提交作业时需要准备一个“EMR Serverless Application”和一个“EMR Serverless Job Execution Role”,其中后者应具有S3和Glue Data Catalog的读写权限。Application可以在EMR Serverless控制台(EMR Studio)上通过向导轻松创建(全默认配置即可),Execution Role可以使用 《CDC一键入湖:当 Apache Hudi DeltaStreamer 遇见 Serverless Spark》 一文第5节提供的脚本快速创建。

接下来要准备提交作业所需的Jar包和SQL文件。首先在S3上创建一个存储桶,本文使用的桶取名:my-spark-sql-job(当您在自己的环境中操作时请注意替换桶名),然后从 [ 此处 ] 下载编译好的 emr-serverless-utils.jar包并上传至s3://my-spark-sql-job/jars/目录下:

请添加图片描述

在演示过程中还将使用到5个SQL示例文件,从 [ 此处 ] 下载解压后上传至s3://my-spark-sql-job/sqls/目录下:

请添加图片描述

2.2. 在控制台上提交纯SQL文件作业

2.2.1. 执行单一SQL文件

打开EMR Serverless的控制台(EMR Studio),在选定的EMR Serverless Application下提交一个如下的Job:

请添加图片描述

① Script location:设定为此前上传的Jar包路径 s3://my-spark-sql-job/jars/emr-serverless-utils-1.0.jar
② Main class:设定为 com.github.emr.serverless.SparkSqlJob
③ Script arguments:设定为 ["--sql-files","s3://my-spark-sql-job/sqls/drop-tables.sql"]

至于其他选项,无需特别设定,保持默认配置即可,对于在生产环境中部署的作业,您可以结合自身作业的需要灵活配置,例如Spark Driver/Executor的资源分配等。需要提醒的是:通过控制台创建的作业默认会启用Glue Data Catalog(即:Additional settings -> Metastore configuration -> Use AWS Glue Data Catalog 默认是勾选的),为了方便在Glue和Athena中检查SQL脚本的执行结果,建议您不要修改此项默认配置。

上述配置描述了这样一项工作:以s3://my-spark-sql-job/jars/emr-serverless-utils-1.0.jar中的com.github.emr.serverless.SparkSqlJob作为主类,提起一个Spark作业。其中["--sql-files","s3://my-spark-sql-job/sqls/drop-tables.sql"]是传递给SparkSqlJob的参数,用于告知作业所要执行的SQL文件位置。本次作业执行的SQL文件只有三条简单的DROP TABLE语句,是一个基础示例,用以展示工具类执行单一文件内多条SQL语句的能力。

2.2.2. 执行带自定义参数的SQL文件

接下来要演示的是工具类的第二项功能:执行带自定义参数的SQL文件。新建或直接复制上一个作业(在控制台上选定上一个作业,依次点击 Actions -> Clone job),然后将“Script arguments”的值设定为:

["--sql-files","s3://my-spark-sql-job/sqls/create-tables.sql","--sql-params","APP_S3_HOME=s3://my-spark-sql-job"]

如下图所示:

请添加图片描述

这次的作业设定除了使用--sql-files参数指定了SQL文件外,还通过--sql-params参数为SQL中出现的用户自定义变量进行了赋值。根据此前的介绍,APP_S3_HOME=s3://my-spark-sql-job是一个“Key=Value”字符串,其含义是将值s3://my-spark-sql-job赋予了变量APP_S3_HOME,SQL中所有出现${APP_S3_HOME}的地方都将被s3://my-spark-sql-job所替代。查看create-tables.sql文件,在建表语句的LOCATION部分可以发现自定义变量${APP_S3_HOME}

CREATE EXTERNAL TABLE IF NOT EXISTS ORDERS (
    ... ...
)
... ...
LOCATION '${APP_S3_HOME}/data/orders/';

SparkSqlJob读取该SQL文件时,会根据键值对字符串APP_S3_HOME=s3://my-spark-sql-job将SQL文件中所有的${APP_S3_HOME}替换为s3://my-spark-sql-job,实际执行的SQL将变为:

CREATE EXTERNAL TABLE IF NOT EXISTS ORDERS (
    ... ...
)
... ...
LOCATION 's3://my-spark-sql-job/data/orders/';

提交作业并执行完毕后,可登录Athena控制台,查看数据表是否创建成功。

2.2.3. 使用通配符执行多个文件

有时候,我们需要批量执行一个文件夹下的所有SQL文件,或者使用通配符选择性的执行部分SQL文件,SparkSqlJob使用了Java文件系统通配符来支持这类需求。下面的作业就演示了通配符的使用方法,同样是新建或直接复制上一个作业,然后将“Script arguments”的值设定为:

["--sql-files","s3://my-spark-sql-job/sqls/insert-into-*.sql"]

如下图所示:

请添加图片描述

这次作业的--sql-files参数使用了路径通配符,insert-into-*.sql将同时匹配insert-into-orders.sqlinsert-into-customers.sql两个SQL文件,它们将分别向ORDERSCUSTOMERS两张表插入多条记录。执行完毕后,可以可登录Athena控制台,查看数据表中是否有数据产生。

2.2.4. 一个复合示例

最后,我们来提交一个更有代表性的复合示例:文件通配符 + 用户自定义参数。再次新建或直接复制上一个作业,然后将“Script arguments”的值设定为:

["--sql-files","s3://my-spark-sql-job/sqls/select-*.sql","--sql-params","APP_S3_HOME=s3://my-spark-sql-job,CUST_CITY=NEW YORK,ORD_DATE=2008-07-15"]

如下图所示:

![emr-serverless-snapshot-4.jpg-150.8kB][6]

本次作业的--sql-files参数使用路径通配符select-*.sql匹配select-tables.sql文件,该文件中存在三个用户自定义变量,分别是${APP_S3_HOME}${CUST_CITY}${ORD_DATE}

CREATE EXTERNAL TABLE ORDERS_CUSTOMERS
    ... ...
    LOCATION '${APP_S3_HOME}/data/orders_customers/'
AS SELECT
    ... ...
WHERE
    C.CUST_CITY = '${CUST_CITY}' AND
    O.ORD_DATE = CAST('${ORD_DATE}' AS DATE);

--sql-params参数为这三个自定义变量设置了取值,分别是:APP_S3_HOME=s3://my-spark-sql-jobCUST_CITY=NEW YORKORD_DATE=2008-07-15,于是上述SQL将被转化为如下内容去执行:

CREATE EXTERNAL TABLE ORDERS_CUSTOMERS
    ... ...
    LOCATION 's3://my-spark-sql-job/data/orders_customers/'
AS SELECT
    ... ...
WHERE
    C.CUST_CITY = 'NEW YORK' AND
    O.ORD_DATE = CAST('2008-07-15' AS DATE);

至此,通过控制台提交纯SQL文件作业的所有功能演示完毕。

2.3. 通过命令行提交纯SQL文件作业

实际上,很多EMR Serverless用户并不在控制台上提交自己的作业,而是通过AWS CLI提交,这种方式方式多见于工程代码或作业调度中。所以,我们再来介绍一下如何通过命令行提交纯SQL文件作业。

本文使用命令行提交EMR Serverless作业的方式遵循了《最佳实践:如何优雅地提交一个 Amazon EMR Serverless 作业?》一文给出的最佳实践。首先,登录一个安装了AWS CLI并配置有用户凭证的Linux环境(建议使用Amazon Linux2),先使用命令sudo yum -y install jq安装操作json文件的命令行工具:jq(后续脚本会使用到它),然后完成如下前期准备工作:

① 创建或选择一个作业专属工作目录和S3存储桶
② 创建或选择一个EMR Serverless Execution Role
③ 创建或选择一个EMR Serverless Application

接下来将所有环境相关变量悉数导出(请根据您的AWS账号和本地环境替换命令行中的相应值):

export APP_NAME='change-to-your-app-name'
export APP_S3_HOME='change-to-your-app-s3-home'
export APP_LOCAL_HOME='change-to-your-app-local-home'
export EMR_SERVERLESS_APP_ID='change-to-your-application-id'
export EMR_SERVERLESS_EXECUTION_ROLE_ARN='change-to-your-execution-role-arn'

以下是一份示例:

export APP_NAME='my-spark-sql-job'
export APP_S3_HOME='s3://my-spark-sql-job'
export APP_LOCAL_HOME='/home/ec2-user/my-spark-sql-job'
export EMR_SERVERLESS_APP_ID='00fbfel40ee59k09'
export EMR_SERVERLESS_EXECUTION_ROLE_ARN='arn:aws:iam::123456789000:role/EMR_SERVERLESS_ADMIN'

《最佳实践:如何优雅地提交一个 Amazon EMR Serverless 作业?》一文提供了多个操作Job的通用脚本,都非常实用,本文也会直接复用这些脚本,但是由于我们需要多次提交且每次的参数又有所不同,为了便于使用和简化行文,我们将原文中的部分脚本封装为一个Shell函数,取名为submit-spark-sql-job

submit-spark-sql-job() {
    sqlFiles="$1"
    sqlParams="$2"
    cat << EOF > $APP_LOCAL_HOME/start-job-run.json
{
    "name":"my-spark-sql-job",
    "applicationId":"$EMR_SERVERLESS_APP_ID",
    "executionRoleArn":"$EMR_SERVERLESS_EXECUTION_ROLE_ARN",
    "jobDriver":{
        "sparkSubmit":{
        "entryPoint":"$APP_S3_HOME/jars/emr-serverless-utils-1.0.jar",
        "entryPointArguments":[
            $([[ -n "$sqlFiles" ]] && echo "\"--sql-files\", \"$sqlFiles\"")
            $([[ -n "$sqlParams" ]] && echo ",\"--sql-params\", \"$sqlParams\"")
        ],
         "sparkSubmitParameters":"--class com.github.emr.serverless.SparkSqlJob --conf spark.hadoop.hive.metastore.client.factory.class=com.amazonaws.glue.catalog.metastore.AWSGlueDataCatalogHiveClientFactory"
        }
   },
   "configurationOverrides":{
        "monitoringConfiguration":{
            "s3MonitoringConfiguration":{
                "logUri":"$APP_S3_HOME/logs"
            }
        }
   }
}
EOF
    jq . $APP_LOCAL_HOME/start-job-run.json
    export EMR_SERVERLESS_JOB_RUN_ID=$(aws emr-serverless start-job-run \
        --no-paginate --no-cli-pager --output text \
        --name my-spark-sql-job \
        --application-id $EMR_SERVERLESS_APP_ID \
        --execution-role-arn $EMR_SERVERLESS_EXECUTION_ROLE_ARN \
        --execution-timeout-minutes 0 \
        --cli-input-json file://$APP_LOCAL_HOME/start-job-run.json \
        --query jobRunId)
    now=$(date +%s)sec
    while true; do
        jobStatus=$(aws emr-serverless get-job-run \
                        --no-paginate --no-cli-pager --output text \
                        --application-id $EMR_SERVERLESS_APP_ID \
                        --job-run-id $EMR_SERVERLESS_JOB_RUN_ID \
                        --query jobRun.state)
        if [ "$jobStatus" = "PENDING" ] || [ "$jobStatus" = "SCHEDULED" ] || [ "$jobStatus" = "RUNNING" ]; then
            for i in {0..5}; do
                echo -ne "\E[33;5m>>> The job [ $EMR_SERVERLESS_JOB_RUN_ID ] state is [ $jobStatus ], duration [ $(date -u --date now-$now +%H:%M:%S) ] ....\r\E[0m"
                sleep 1
            done
        else
            printf "The job [ $EMR_SERVERLESS_JOB_RUN_ID ] is [ $jobStatus ]%50s\n\n"
            break
        fi
    done
}

该函数接受两个位置参数:

① 第一位置上的参数用于指定SQL文件路径,其值会传递给SparkSqlJob--sql-files
② 第二位置上的参数用于指定SQL文件中的用户自定义变量,其值会传递给SparkSqlJob--sql-params

函数中使用的Jar包和SQL文件与《2.1. 环境准备》一节准备的Jar包和SQL文件一致,所以使用脚本提交作业前同样需要完成2.1节的环境准备工作。接下来,我们就使用该函数完成与2.2节一样的操作。

2.3.1. 执行单一SQL文件

本节操作与2.2.1节完全一致,只是改用了命令行方式实现,命令如下:

submit-spark-sql-job "$APP_S3_HOME/sqls/drop-tables.sql"

2.3.2. 执行带自定义参数的SQL文件

本节操作与2.2.2节完全一致,只是改用了命令行方式实现,命令如下:

submit-spark-sql-job "$APP_S3_HOME/sqls/create-tables.sql" "APP_S3_HOME=$APP_S3_HOME"

2.3.3. 使用通配符执行多个文件

本节操作与2.2.3节完全一致,只是改用了命令行方式实现,命令如下:

submit-spark-sql-job "$APP_S3_HOME/sqls/insert-into-*.sql"

2.3.4. 一个复合示例

本节操作与2.2.4节完全一致,只是改用了命令行方式实现,命令如下:

submit-spark-sql-job "$APP_S3_HOME/sqls/select-tables.sql" "APP_S3_HOME=$APP_S3_HOME,CUST_CITY=NEW YORK,ORD_DATE=2008-07-15"

3. 在源代码中调用工具类

尽管在Spark编程环境中可以使用spark.sql(...)形式直接执行SQL语句,但是,从前文示例中可以看出 emr-serverless-utils 提供的SQL文件执行能力更便捷也更强大一些,所以,最后我们简单介绍一下如何在源代码中调用相关的工具类获得上述SQL文件的处理能力。具体做法非常简单,你只需要:

① 将emr-serverless-utils-1.0.jar加载到你的类路径中
② 声明隐式类型转换
③ 在spark上直接调用execSqlFile()


# 初始化SparkSession及其他操作
...

# 声明隐式类型转换
import com.github.emr.serverless.SparkSqlSupport._

# 在spark上直接调用execSqlFile()
spark.execSqlFile("s3://YOUR/XXX.sql")

# 在spark上直接调用execSqlFile()
spark.execSqlFile("s3://YOUR/XXX.sql", "K1=V1,K2=V2,...")

# 其他操作
...

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

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

相关文章

目前互联网企业知识库使用情况?企业知识库搭建缺陷有什么?

目前互联网企业普遍使用知识库作为内部和外部知识管理的工具。知识库通过集中存储和组织企业内部的知识和信息&#xff0c;使其易于访问和共享 目前互联网企业知识库使用情况&#xff1a; 内部知识管理&#xff1a; 知识库用于内部员工的知识共享和知识管理。企业可以将各个…

5款专业思维导图软件推荐:提升效率,促进协作!

思维导图作为一种有效的信息组织和可视化工具&#xff0c;已经广泛地应用于学习、工作和生活中。通过思维导图&#xff0c;我们能够以高效的方式把握和处理大量信息。 但到了挑选软件的环节&#xff0c;市面上层出不穷的思维导图软件&#xff0c;容易让人看花眼&#xff0c;不知…

matlab使用教程(17)—广度优先和深度优先搜索

1.可视化广度优先搜索和深度优先搜索 此示例说明如何定义这样的函数&#xff1a;该函数通过突出显示图的节点和边来显示 bfsearch 和 dfsearch 的可视化结果。 创建并绘制一个有向图。 s [1 2 3 3 3 3 4 5 6 7 8 9 9 9 10]; t [7 6 1 5 6 8 2 4 4 3 7 1 6 8 2]; G dig…

【Bug解决】1、Nacos启动成功,但却无法访问(提示:无法访问此网站,192.168.10.133的响应时间过长)

项目场景&#xff1a; 在虚拟机上通过Docker创建Nacos容器&#xff0c;已经创建成功&#xff0c;查看Nacos启动日志也是成功。但通过端口号加8848/nacos&#xff08;如&#xff1a;http://192.168.88.10:8848/nacos&#xff09;无法访问到Nacos管理页面。 问题描述 原因分析&a…

DC电源模块生产用料扎实的表现

BOSHIDA DC电源模块生产用料扎实的表现 随着现代科技的不断发展&#xff0c;DC电源模块已经被广泛应用于各种电子设备中。不同于其它电子元器件&#xff0c;DC电源模块生产所需用料的扎实程度对其性能的影响非常大。下面&#xff0c;本文将就DC电源模块生产用料扎实的表现进行…

互联网 vs IC 谁更有前景?

1、行业发展趋势 互联网行业 去年&#xff0c;阿里、腾讯裁员的消息双双冲上热搜&#xff0c;引发网友讨论。有消息称腾阿里、腾讯预计裁员 10%&#xff5e;30%&#xff0c;阿里多个业务线已确认裁员名单。 中国互联网的黄金时期已经过了&#xff0c;这个信号越来越明显。最…

卷积神经网络全解:(AlexNet/VGG/ GoogleNet/LeNet/卷积/激活/池化/全连接)

CNN&#xff0c;卷积神经网络&#xff0c;Convolution Neural Network 卷积计算公式&#xff1a; N &#xff08;W-F2p&#xff09;/s1 1 经典网络 按照时间顺序 1.1 LeNet LeNet是 Yann LeCun在1998年提出&#xff0c;用于解决手写数字识别的视觉任务。自那时起&#x…

八大排序超详解(动图+源码)

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大家三连关注&…

高效提升工作效率,亚马逊云科技热门课程带你入门生成式AI

当前人工智能仍处于飞速发展阶段&#xff0c;作为当下最先进的科学技术之一&#xff0c;相信大家对AIGC关注已久。今天&#xff0c;引用亚马逊云科技最新发布的七项生成式AI新功能来跟大家聊聊近期的热门生成式AI&#xff01; 有人说&#xff0c;生成式AI将带来充满创造性的新世…

AMEYA360:村田共模扼流线圈,针对车载应用的高频噪声

近年来&#xff0c;随着ADAS(高级驾驶辅助系统)精度的提高&#xff0c;汽车行业开始安装大量毫米波雷达、LiDAR等高速传感设备。如果噪声从外部进入这些设备&#xff0c;系统可能无法正常工作。相反&#xff0c;如果这些设备产生噪声&#xff0c;则可能会对其他设备产生不利影响…

mysql 02 数据库的约束

为防止错误的数据被插入到数据表&#xff0c;MySQL中定义了一些维护数据库完整性的规则&#xff1b;这些规则常称为表的约束。常见约束如下&#xff1a; 主键约束 主键约束即primary key用于唯一的标识表中的每一行。被标识为主键的数据在表中是唯一的且其值不能为空。这点类似…

ICT产教融合创新实训基地软件测试实训室建设方案

一 、系统概述 ICT产教融合创新&#xff0c;简单来说&#xff0c;就是信息与通信技术&#xff08;ICT&#xff09;与产业界、教育界的融合创新。这个概念强调了在现代社会中&#xff0c;信息技术与产业发展以及教育培训之间相互关联的重要性。 ICT产教融合创新的核心思想包括以…

【正点原子STM32连载】第十章 跑马灯实验 摘自【正点原子】APM32F407最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html# 第十…

数字孪生技术对环境保护有哪些作用?

数字孪生技术在环境保护中的作用不容忽视&#xff0c;为我们创造了全新的可能性和解决方案。在追求可持续发展的今天&#xff0c;数字孪生以其独特的能力&#xff0c;正逐渐改变着环境保护的方式。 数字孪生技术首先在环境监测方面发挥了巨大作用。通过传感器和数据采集设备&a…

JVM整体回忆笔记

模块三 内存的分配 指针碰撞 空闲列表 分配内存的时候出现并发问题&#xff0c;几个线程同时抢同一块内存区域 CAS方法解决 本地线程分配缓冲&#xff08;-XX&#xff1a;UseTLAB&#xff09;,jvm默认开启 对象的组成 对象头、实例数据、对齐填充&#xff08;保证对象8个字节…

Sonar:Class variable fields should not have public accessibility

公有类变量字段不遵守封闭原则&#xff0c;主要有三个问题&#xff1a; 无法添加验证等附加行为。内部表示暴露在外&#xff0c;事后无法更改。成员值可能会在代码的任何地方发生变化&#xff0c;并且可能不符合程序员的假设。 通过使用私有属性和访问方法&#xff08;set 和…

输出倒逼输入系列之 阻塞 or 等待?

操作系统线程状态 《趣谈Linux 操作系统》第12章节&#xff0c;讲到 进程的数据结构&#xff0c;其中涉及到任务状态&#xff0c;这里简单概述一下 首先在操作系统中&#xff0c;不管是进程还是线程&#xff0c;都统一是 任务的概念&#xff0c;它的数据结构 为 task_strcut。…

深度学习1:通过模型评价指标优化训练

P(Positive)表示预测为正样本&#xff0c;N(negative)表示预测为负样本&#xff0c;T(True)表示预测正确,F(False)表示预测错误。 TP&#xff1a;正样本预测正确的数量&#xff08;正确检测&#xff09; FP&#xff1a;负样本预测正确数量&#xff08;误检测&#xff09; TN…

Python入门--安装和环境配置

要开始使用Python&#xff0c;您需要先安装Python环境。下面是安装Python环境的简单步骤&#xff1a; 1.访问Python官网&#xff08;https://www.python.org/&#xff09;&#xff0c;点击“下载”按钮。 2.选择适合您系统的版本下载&#xff0c;可选择Windows、macOS、Linux…

uniapp中map使用点聚合渲染marker覆盖物

效果如图&#xff1a; 一、什么是点聚合 当地图上需要展示的标记点 marker 过多时&#xff0c;可能会导致界面上 marker 出现压盖&#xff0c;展示不全&#xff0c;并导致整体性能变差。针对此类问题&#xff0c;推出点聚合能力。 点聚合官网教程 二、基本用法 template…