Apache Sedona和Spark将geojson瓦片化例子

Apache Sedona很方便读取geojson、ShapeFile、geopackage等文件,提供了很多spark sql函数和rdd算子。下面例子主要用于熟悉spark和sedona的使用。

引入的maven包

<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>GeoJsonToMvt</artifactId><version>0.1</version><packaging>jar</packaging><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><scala.version>2.13.8</scala.version><geotrellis.version>3.7.1</geotrellis.version><spark.version>3.3.4</spark.version><spray.json.version>1.3.6</spray.json.version></properties><dependencies><dependency><groupId>org.scala-lang</groupId><artifactId>scala-library</artifactId><version>${scala.version}</version></dependency><dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.13</artifactId><version>${spark.version}</version></dependency><dependency><groupId>org.apache.spark</groupId><artifactId>spark-sql_2.13</artifactId><version>${spark.version}</version></dependency><dependency><groupId>org.apache.spark</groupId><artifactId>spark-sql_2.13</artifactId><version>${spark.version}</version></dependency><dependency><groupId>io.spray</groupId><artifactId>spray-json_2.13</artifactId><version>${spray.json.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.13.4</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.4</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.13.4</version></dependency><dependency><groupId>org.locationtech.jts</groupId><artifactId>jts-core</artifactId><version>1.19.0</version></dependency><dependency><groupId>org.geotools</groupId><artifactId>gt-main</artifactId><version>25.4</version></dependency><dependency><groupId>org.geotools</groupId><artifactId>gt-epsg-hsql</artifactId><version>25.4</version></dependency><dependency><groupId>org.apache.sedona</groupId><artifactId>sedona-viz-3.0_2.13</artifactId><version>1.4.1</version></dependency><dependency><groupId>org.apache.sedona</groupId><artifactId>sedona-core-3.0_2.13</artifactId><version>1.4.1</version></dependency><dependency><groupId>org.apache.sedona</groupId><artifactId>sedona-sql-3.0_2.13</artifactId><version>1.4.1</version></dependency><dependency><groupId>org.apache.sedona</groupId><artifactId>sedona-spark-3.0_2.13</artifactId> <!-- 替换为你的 Spark 和 Scala 版本 --><version>1.6.1</version> <!-- 替换为你的 Sedona 版本 --></dependency><dependency><groupId>org.locationtech.proj4j</groupId><artifactId>proj4j</artifactId><version>1.1.0</version></dependency></dependencies><repositories><repository><id>osgeo</id><name>OSGeo Release Repository</name><url>https://repo.osgeo.org/repository/release/</url></repository></repositories><build><plugins><plugin><groupId>org.scala-tools</groupId><artifactId>maven-scala-plugin</artifactId><version>2.15.2</version><executions><execution><goals><goal>compile</goal><goal>testCompile</goal></goals></execution></executions></plugin></plugins></build>
</project>

下面是java实现的spark代码 部分是由AI(Gemini2.0)生成代码

import org.apache.sedona.spark.SedonaContext;
import org.apache.sedona.viz.core.Serde.SedonaVizKryoRegistrator;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.RowFactory;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.Metadata;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.io.WKTReader;
import scala.Tuple3;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;import static java.lang.Math.cos;
import static java.lang.Math.floor;
import static java.lang.Math.pow;
import static java.lang.Math.toRadians;
import static org.apache.spark.sql.functions.*;public class GeoJsonToTilesJava {public static void main(String[] args) throws Exception {System.setProperty("org.geotools.referencing.forceXY", "true");// 创建SparkSessionSparkSession config = SedonaContext.builder().master("local[*]") // Delete this if run in cluster mode.appName("readTestJava") // Change this to a proper name.config("spark.kryo.registrator", SedonaVizKryoRegistrator.class.getName()).config("spark.sql.extensions", "org.apache.sedona.viz.sql.SedonaVizExtensions,org.apache.sedona.sql.SedonaSqlExtensions").config("spark.serializer", "org.apache.spark.serializer.KryoSerializer").getOrCreate();SparkSession sedona = SedonaContext.create(config);Dataset<Row> df = sedona.read().format("geojson").option("multiPolygon", "true").load("src/main/resources/guangdong.json").selectExpr("explode(features) as features") // Explode the envelope to get one feature per row..select("features.*") // Unpack the features struct..withColumn("name", expr("properties['name']")).drop("properties").drop("type");Dataset<Row> df1 = df;df1.show();//Dataset<Row> filteredDF = df.filter(expr("ST_Y(ST_Centroid(ST_GeomFromGeoJSON(geometry))) BETWEEN -85.05 AND 85.05"));// 创建坐标转换器try {Dataset<Row> geomDF = df.withColumn("sedona_geom",expr("ST_AsEWKT(ST_Transform(geometry,'epsg:4326','epsg:3857',true))"));// 使用 UDF 创建 Sedona Geometry 列//Dataset<Row> geomDF = df.withColumn("sedona_geom", callUDF("createSedonaGeometry", col("geometry")));geomDF.show();// 修改: getTileIndexUDF 的返回值类型, 并保证如果坐标为空,则返回一个 null structorg.apache.spark.sql.api.java.UDF2<String, Integer, Row> getTileIndexUDF = (centroidStr, zoom)->{if (centroidStr == null || centroidStr.isEmpty()) {return RowFactory.create(null, null, null);} else {String[] str = centroidStr.replace("POINT (", "").replace(")", "").split(" ");List<Double> coordinates = new ArrayList<>();coordinates.add(Double.parseDouble(str[0]));coordinates.add(Double.parseDouble(str[1]));Tuple3<Integer,Integer,Integer> tileIndex = getTileIndex(coordinates,zoom);return RowFactory.create(tileIndex._1(), tileIndex._2(), tileIndex._3());}};//CRS.decode("EPSG:4326", true);// 注册 UDFStructType tileIndexSchema = new StructType(new StructField[]{new StructField("x", DataTypes.IntegerType, true, Metadata.empty()),new StructField("y", DataTypes.IntegerType, true, Metadata.empty()),new StructField("z", DataTypes.IntegerType, true, Metadata.empty())});sedona.udf().register("getTileIndexUDF", getTileIndexUDF, tileIndexSchema);org.apache.spark.sql.api.java.UDF1<String,String> getCentroid = (geomStr)->{if (geomStr == null || geomStr.isEmpty()) {return null;} else {GeometryFactory factory = new GeometryFactory();WKTReader wktReader = new WKTReader(factory);org.locationtech.jts.geom.Geometry geom = wktReader.read(geomStr);return geom.getCentroid().toString();}};// 注册 UDFsedona.udf().register("getCentroid", getCentroid, DataTypes.StringType);List<Integer> zooms = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);//  关键修改:直接在原始的 geomDF 上面进行循环操作for (Integer zoom : zooms){Dataset<Row> tilesDF = geomDF.withColumn("centroid",callUDF("getCentroid", col("sedona_geom"))).withColumn("tile", callUDF("getTileIndexUDF", col("centroid"), lit(zoom)));tilesDF.show();Dataset<Row>  groupedTiles = tilesDF.filter(col("tile").isNotNull()).groupBy(col("tile")).agg(collect_list("sedona_geom").alias("features"));groupedTiles.write().format("json").mode("overwrite").save("D:/temp/output/zoom_" + zoom);}sedona.stop();}catch (Exception e){e.printStackTrace();}}private static Tuple3<Integer, Integer, Integer> getTileIndex(List<Double> coordinates, int zoom) {if (coordinates == null || coordinates.isEmpty()) {return null;} else {double x = coordinates.get(0);double y = coordinates.get(1);double res = 156543.03392 * cos(toRadians(0)) / pow(2, zoom);int tileX = (int) floor((x + 20037508.34) / (res * 256));int tileY = (int) floor((20037508.34 - y) / (res * 256));return new Tuple3<>(tileX,tileY,zoom);}}
}

参考链接
https://sedona.apache.org/1.7.0/tutorial/sql/
https://sedona.apache.org/1.7.0/api/sql/Function/
谷歌双子座AIhttps://aistudio.google.com/

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

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

相关文章

鼠标自动移动防止锁屏的办公神器 —— 定时执行专家

目录 ◆ 如何设置 ◇ 方法1&#xff1a;使用【执行Nircmd命令】任务 ◇ 方法2&#xff1a;使用【模拟键盘输入】任务 ◆ 定时执行专家介绍 ◆ 定时执行专家最新版下载 ◆ 如何设置 ◇ 方法1&#xff1a;使用【执行Nircmd命令】任务 1、点击工具栏第一个图标【新建任务】&…

2025新年源码免费送

2025很开门很开门的源码免费传递。不需要馒头就能获取4套大开门源码。 听泉偷宝&#xff0c;又进来偷我源码啦&#x1f44a;&#x1f44a;&#x1f44a;。欢迎偷源码 &#x1f525;&#x1f525;&#x1f525; 获取免费源码以及更多源码&#xff0c;可以私信联系我 我们常常…

微信小程序实现登录注册

文章目录 1. 官方文档教程2. 注册实现3. 登录实现4. 关于作者其它项目视频教程介绍 1. 官方文档教程 https://developers.weixin.qq.com/miniprogram/dev/framework/路由跳转的几种方式&#xff1a; https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.switchTab…

1. Doris分布式环境搭建

一. 环境准备 本次测试集群采用3台机器hadoop1、hadoop2、hadoop3, Frontend和Backend部署在同一台机器上&#xff0c;Frontend部署3台组成高可用&#xff0c;Backend部署3个节点&#xff0c;组成3副本存储。 主机IP操作系统FrontendBackendhadoop1192.168.47.128Centos7Foll…

docker-compose安装canal并利用rabbitmq同步多个mysql数据

必看&#xff1a;本文默认已经安装好了docker-compose、rabbitmq、mysql并且mysql开启了binlog日志&#xff0c;不需要再安装&#xff1b; 流程图 如上图所示&#xff0c;左边是MQ模式流程图&#xff0c;右边则是TCP模式的流程图&#xff1b; 最终的目的是利用canal监听多个M…

ue5动画重定向,一键重定向。ue4小白人替换成ue5

这就是我们下载的 初学者动画内容包 点击设置选中列 绿色的是动画 黄色的关卡 蓝色是蓝图 ctrla 全选 ctrl鼠标左键 选中所有动画 重定向动画资产 不要选错&#xff0c;只要绿色 选择目标网格体 选择所有的绿色 动画 导出动画 添加前缀ycn 导出 一定要提前新建好存放的…

scrapy爬取图片

scrapy 爬取图片 环境准备 python3.10scrapy pillowpycharm 简要介绍scrapy Scrapy 是一个开源的 Python 爬虫框架&#xff0c;专为爬取网页数据和进行 Web 抓取而设计。它的主要特点包括&#xff1a; 高效的抓取性能&#xff1a;Scrapy 采用了异步机制&#xff0c;能够高效…

Hadoop3.x 万字解析,从入门到剖析源码

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

RabbitMQ介绍与使用

RabbitMQ官网 RabbitMQ 介绍 RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;基于 AMQP&#xff08;高级消息队列协议&#xff09;标准&#xff0c;使用 Erlang 编程语言构建。它是消息队列&#xff08;MQ&#xff09;的一种&#xff0c;广泛应用于分布式系统中&#x…

【爬虫】单个网站链接爬取文献数据:标题、摘要、作者等信息

源码链接&#xff1a; https://github.com/Niceeggplant/Single—Site-Crawler.git 一、项目概述 从指定网页中提取文章关键信息的工具。通过输入文章的 URL&#xff0c;程序将自动抓取网页内容 二、技术选型与原理 requests 库&#xff1a;这是 Python 中用于发送 HTTP 请求…

混合专家模型 (MoE)笔记摘要

ref&#xff1a; https://huggingface.co/blog/zh/moe#%E4%BB%80%E4%B9%88%E6%98%AF%E6%B7%B7%E5%90%88%E4%B8%93%E5%AE%B6%E6%A8%A1%E5%9E%8B 简短总结 混合专家模型 (MoEs): 与稠密模型相比&#xff0c; 预训练速度更快 与具有相同参数数量的模型相比&#xff0c;具有更快的…

解决idea中无法拖动tab标签页的问题

1、按 Ctrl Alt S 打开设置&#xff0c;找到路径 File | Settings | Appearance & Behavior | Appearance 2、去掉勾选 Drag-and-drop with Alt pressed only 即可

六、Angular 发送请求/ HttpClient 模块

一、应用 HttpClient 模块 angular/common/http 中的 HttpClient 类基于浏览器提供的 XMLHttpRequest 接口。要想使用 HtpClient 模块&#xff0c;就要先导入 Anqular 的 HttpClientModule。大多数 Web 应用程序都会在根模块 AppModule 中导入它。 编辑 src/app/app.module.ts…

基于单片机的无线智能窗帘控制器的设计

摘 要 : 本文以单片机为控制核心 , 基于 PT2262/ 2272 无线收发模块 , 实现了窗帘的无线远程智能控制 . 该控制器通过高频无线收发模块实现了遥控窗帘的开合控制; 根据外部光线强弱实现自动开关窗帘 ; 根据设定时间自动完成开关过程; 通过语音播报当前环境温湿度信息以…

android刷机

android ota和img包下载地址&#xff1a; https://developers.google.com/android/images?hlzh-cn android启动过程 线刷 格式&#xff1a;ota格式 模式&#xff1a;recovery 优点&#xff1a;方便、简单&#xff0c;刷机方法通用&#xff0c;不会破坏手机底层数据&#xff0…

Vivado中Tri_mode_ethernet_mac的时序约束、分析、调整——(一)时序约束的基本概念

1、基本概念 推荐阅读&#xff0c;Ally Zhou编写的《Vivado使用误区与进阶》系列文章&#xff0c;熟悉基本概念、tcl语句的使用。 《Vivado使用误区与进阶》电子书开放下载&#xff01;&#xff01; 2、Vivado中的语法例程 1&#xff09;语法例程 约束的语句可以参考vivado…

设计模式 行为型 责任链模式(Chain of Responsibility Pattern)与 常见技术框架应用 解析

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许将请求沿着处理者链进行发送。每个处理者对象都有机会处理该请求&#xff0c;直到某个处理者决定处理该请求为止。这种模式的主要目的是避免请求的发送者和接收者之间…

ubuntu 20.04 安装docker--小白学习之路

更新包 sudo apt-get update # 安装需要的软件包以使apt能够通过HTTPS使用仓库 sudo apt-get install ca-certificates curl gnupg lsb-release 使用清华大学源 # 添加Docker官方的GPG密钥 curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo…

Linux之线程池与单例模式

目录 线程池 线程池代码 单例模式 饿汉模式单例模式 懒汉模式单例模式 在前几期&#xff0c;我们已经学习了多线程的创建和控制&#xff0c;学习了多线程中的同步和互斥&#xff0c;学习了多线程中的条件变量和信号量&#xff0c;基于此我们实现了基于阻塞队列和基于环形队…

The Dedicated Few (10 player)

The Dedicated Few (10 player) 少数精锐&#xff08;10人&#xff09; &#xff1a;以少于9人的阵容击败纳克萨玛斯的所有首领&#xff08;10人&#xff09; 历时2小时做完了&#xff0c;不容易啊&#xff0c;别人可以的咱也可以。 World of Warcraft [CLASSIC][80猎人][G…