使用Apache Sedona将CSV经纬度数据与Overture Maps建筑物数据集进行空间关联的技术咨询
Apache Sedona将CSV经纬度数据与Overture Maps建筑物数据集进行空间关联的技术咨询
嗨,看你是Sedona和Spark的新手,想要把自己CSV里的经纬度点和Overture Maps的建筑物数据做空间关联,这个需求在地理空间分析里很常见,我来帮你梳理下可行的方案、代码优化点,以及更高效的实现思路~
核心思路:空间关联的正确姿势
你的需求本质是点-in-多边形的空间匹配——找到每个经纬度点所在的建筑物多边形。最直接的方式就是用Sedona的空间判断函数结合关联操作,但要注意性能优化,不然大数据量下会很慢。
完整代码示例(补全并优化你的代码)
先把你没写完的代码补全,同时加入关键的预处理和优化步骤:
from sedona.spark import * from pyspark.sql import functions as F from pyspark.sql.types import DoubleType import time # 初始化Sedona上下文(适配Spark 3.x,确保依赖包版本兼容) config = ( SedonaContext.builder() .config("spark.hadoop.fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.AnonymousAWSCredentialsProvider") .config("fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.AnonymousAWSCredentialsProvider") # 指定Sedona和GeoTools的依赖包,版本要和Spark版本匹配 .config('spark.jars.packages', 'org.apache.sedona:sedona-spark-shaded-3.0_2.12:1.5.1,org.datasyslab:geotools-wrapper:1.5.1-28.2') .getOrCreate() ) sedona = SedonaContext.create(config) # ---------------------- # 1. 处理自己的CSV经纬度数据 # ---------------------- # 加载CSV,关闭自动推断类型,手动转换经纬度为Double df_csv = sedona.read.csv("s3a://your-bucket/your-latlon-data.csv", header=True, inferSchema=False) df_csv = df_csv.withColumn("lat", F.col("lat").cast(DoubleType())) df_csv = df_csv.withColumn("lon", F.col("lon").cast(DoubleType())) # 生成WGS84坐标系(EPSG:4326)的点几何对象(注意Sedona中点的顺序是lon, lat) df_csv = df_csv.withColumn("point_geom", F.expr("ST_Point(lon, lat)")) # 过滤无效经纬度(避免后续空间计算出错) df_csv = df_csv.filter((F.col("lat").between(-90, 90)) & (F.col("lon").between(-180, 180))) # ---------------------- # 2. 加载并预处理Overture建筑物数据 # ---------------------- # Overture Maps公开建筑数据的路径(注意版本可能更新,确认最新路径) overture_buildings_path = "s3://overturemaps-us-west-2/release/2024-03-15-alpha.0/theme=buildings/type=building/" df_buildings = sedona.read.parquet(overture_buildings_path) # 只保留需要的列(减少数据量,提升性能),比如几何列、建筑ID、名称、高度 df_buildings = df_buildings.select("geometry", "id", "names", "height") # ---------------------- # 3. 空间索引与关联(关键优化) # ---------------------- # 给建筑物的几何列创建空间索引,大幅提升点-in-多边形的匹配速度 df_buildings = df_buildings.createSpatialIndex("geometry") # 用ST_Within做空间关联:判断点是否在建筑物多边形内 # 用left join保留所有CSV里的点,即使没有匹配到建筑物 result_df = df_csv.join( df_buildings, F.expr("ST_Within(point_geom, geometry)"), how="left" ) # 查看前10条结果 result_df.show(10) # 保存匹配结果(可选,比如存到S3的Parquet文件) result_df.write.parquet("s3a://your-bucket/matched-building-results.parquet", mode="overwrite")
更高效的优化方案
如果你的经纬度点数量很多,或者Overture数据范围太大(比如全球建筑),可以先缩小数据范围再关联:
- 计算CSV数据的边界框:先找出你所有经纬度点的最小/最大经纬度,生成一个边界多边形
- 预过滤建筑物数据:只保留和这个边界框相交的建筑物,减少后续关联的数据量
示例代码:
# 计算CSV数据的边界框 bbox = df_csv.select( F.min("lon").alias("min_lon"), F.max("lon").alias("max_lon"), F.min("lat").alias("min_lat"), F.max("lat").alias("max_lat") ).first() # 用边界框过滤建筑物数据,只保留范围内的建筑 df_buildings_filtered = df_buildings.filter( F.expr(f"ST_Intersects(geometry, ST_PolygonFromEnvelope({bbox.min_lon}, {bbox.min_lat}, {bbox.max_lon}, {bbox.max_lat}))") ) # 再给过滤后的建筑数据创建索引,然后关联 df_buildings_filtered = df_buildings_filtered.createSpatialIndex("geometry") result_df = df_csv.join(df_buildings_filtered, F.expr("ST_Within(point_geom, geometry)"), how="left")
注意事项
- 版本兼容:Sedona的依赖包版本要和你的Spark版本匹配,比如Spark 3.2+可以用Sedona 1.5.x
- CRS一致性:Overture Maps的几何数据默认是WGS84(EPSG:4326),所以你的点几何也要用这个坐标系,不要做不必要的投影转换
- 分区调整:如果数据量很大,可以调整Spark的分区数(比如
spark.sql.shuffle.partitions),避免小分区或超大分区影响性能
备注:内容来源于stack exchange,提问作者user28073171
相关产品推荐
相关产品推荐

