跳到主要内容
工程的博客

用数据库处理大规模地理空间数据

2019年12月5日 工程的博客

分享这篇文章

这篇博客是3年前写的。请参考这些文章,以了解您的Databricks Lakehouse地理空间处理和分析的最新方法:

  1. 与H3和Photon的超级空间分析
  2. 来自Databricks实验室的高尺度空间分析项目马赛克
    2 a。用马赛克统一矢量和栅格分析
  3. Thasos如何利用马赛克和H3优化空间分析

技术的发展和融合为及时准确的地理空间数据市场注入了活力。每天,数十亿的手持设备和物联网设备以及数千个机载和卫星遥感平台都会产生数百艾字节的位置感知数据。bob体育客户端下载地理空间大数据的蓬勃发展与机器学习的进步相结合,使各行各业的组织能够构建新的产品和能力。

利用地理空间数据的地图在整个行业中广泛使用,涉及多个用例,包括灾难恢复、国防和情报、基础设施和医疗服务。利用地理空间数据的地图在整个行业中广泛使用,涉及多个用例,包括灾难恢复、国防和情报、基础设施和医疗服务。

例如,许多公司提供本地化的基于无人机的服务,如测绘和现场检查(参考面向智能云和智能边缘的发展).另一个快速增长的地理空间数据行业是自动驾驶汽车。初创公司和老牌公司都在从汽车传感器中积累大量高度上下文化的地理数据,以实现自动驾驶汽车的下一个创新(参考文献)Databricks激发了wejo创建移动数据生态系统的雄心).零售商和政府机构也在寻求利用他们的地理空间数据。例如,人流分析(参考建立行人流量洞察数据集)可以帮助确定开设新店的最佳地点,或者在公共部门,改善城市规划。尽管在地理空间数据方面进行了所有这些投资,但仍然存在一些挑战。

大规模地理空间分析的挑战

第一个挑战涉及处理流和批处理应用程序的规模。地理空间数据的激增和应用程序所需的sla超过了传统的存储和处理系统。由于数据量、速度、存储成本和严格的写时模式强制等压力,客户数据已经从现有的垂直扩展的地理数据库溢出到数据湖中很多年了。虽然企业对地理空间数据进行了投资,但很少有企业拥有适当的技术架构来为下游分析准备这些庞大而复杂的数据集。此外,鉴于高级用例通常需要可伸缩的数据,大多数人工智能驱动的计划都未能从试点到生产。

与各种空间格式的兼容性是第二个挑战。有很多不同的专业地理空间的格式已建立数十年,以及可能从中获取位置信息的附带数据源:

  • 矢量格式,如GeoJSON, KML, Shapefile和WKT
  • 栅格格式,如ESRI Grid, GeoTIFF, jpeg2000和NITF
  • 导航标准,如AIS和GPS设备使用
  • 通过JDBC / ODBC连接访问的地理数据库,如PostgreSQL / PostGIS
  • 来自高光谱、多光谱、激光雷达和雷达平台的遥感器格式bob体育客户端下载
  • OGC web标准,如WCS, WFS, WMS和WMTS
  • 有地理标记的日志,图片,视频和社交媒体
  • 带有位置引用的非结构化数据

在这篇博文中,我们将概述使用Databricks统一数据分析平台处理上述两个主要挑战的一般方法。bob体育客户端下载这是关于处理大量地理空间数据的系列博客文章的第一部分。

使用Databricks缩放地理空间工作负载

Databricks提供了一个统一的数据分析平台bob体育客户端下载大数据分析机器学习被全世界成千上万的客户使用。它由Apache Spark™、Delta Lake和MLflow提供支持,并具有广泛的第三方和可用库集成生态系统。砖UDAP为生产工作负载大规模提供企业级安全性、支持、可靠性和性能。地理空间工作负载通常很复杂,而且没有一个库适合所有用例。而Apache Spark不提供地理空间数据类型开源社区和企业在开发空间库方bob下载地址面投入了大量精力,这导致了大量可供选择的选项。

缩放地理空间操作通常有三种模式,例如空间连接或最近邻居:

  1. 使用专门构建的库,扩展Apache Spark进行地理空间分析。GeoSparkGeoMesaGeoTrellis,Rasterframes我们的客户使用了一些这样的库。这些框架通常提供多种语言绑定,具有比非正式方法更好的伸缩性和性能,但也可能伴随着学习曲线。
  2. 包装单节点库,例如GeoPandas地理空间数据抽象库(GDAL),或Java拓扑服务(JTS)在特别用户定义函数(udf)用于Spark DataFrames以分布式方式处理。这是扩展现有工作负载的最简单方法,无需大量重写代码;然而,它可能会带来性能上的缺陷,因为它本质上更像是升降和转换。
  3. 使用网格系统索引数据并利用生成的索引执行空间操作是处理非常大规模或计算受限的工作负载的常用方法。S2GeoHex和超级的H3是这样的网格系统的例子。网格近似地理特征,如多边形或点与一组固定的可识别单元,从而避免昂贵的地理空间操作,从而提供更好的缩放行为。实现者可以在固定于单一精度的网格之间进行选择,这种网格可能有点有损耗但性能更好,或者具有多个精度的网格可能性能更差,但可以减轻损失。

下面的示例通常是围绕纽约市出租车接送数据集展开的在这里纽约出租车专区带有几何图形的数据也将被用作多边形集。该数据包含了纽约市五个行政区以及社区的多边形。这笔记本将引导您完成准备工作和清理工作,将初始CSV文件转换为三角洲湖泊表作为可靠的高性能数据源。

我们的基础DataFrame是出租车接送数据三角洲湖表使用砖。

% scalaval draw = spark.read.format(“δ”) .load (“/毫升/博客/地理/δ/ nyc-green”显示器(dfRaw)//显示前10列

使用Databricks从Delta Lake表读取地理空间数据的示例。使用Databricks从Delta Lake表读取地理空间数据的示例。

使用Apache Spark的地理空间库进行地理空间操作

在过去几年中,开发了几个库来扩展Apache Spark的地理空间分析功能。这些框架主要负责以一致的方式注册常用的用户定义类型(UDT)和函数(UDF),从而减轻了用户和团队编写特别空间逻辑的负担。请注意,在这篇博文中,我们使用了几种不同的空间框架来突出不同的功能。我们知道,除了上面提到的那些框架之外,还存在其他框架,您可能也想使用Databricks来处理您的空间工作负载。

前面,我们将基本数据加载到DataFrame中。现在我们需要将纬度/经度属性转换为点几何图形。为了实现这一点,我们将使用udf以分布式的方式对数据框架执行操作。请参阅本文末尾提供的笔记,了解将这些框架添加到集群以及注册udf和udt的初始化调用的详细信息。首先,我们有添加对于我们的集群来说,GeoMesa是一个特别擅长处理矢量数据的框架。对于摄入,我们主要利用它与JTS的集成火花SQL它允许我们轻松地转换和使用注册的JTS几何类。我们将使用函数st_makePoint,给定纬度和经度,它将创建一个Point几何对象。由于函数是UDF,我们可以直接将其应用于列。

% scalaval df = draw.withColumn (“pickup_point”, st_makePoint(坳(“pickup_longitude”)、坳(“pickup_latitude”))).withColumn (“dropoff_point”, st_makePoint(坳(“dropoff_longitude”)、坳(“dropoff_latitude”)))显示器(df.select (“dropoff_point”“dropoff_datetime”))

使用udf以分布式方式对dataframe执行操作,将地理空间数据纬度/经度属性转换为点几何。使用udf以分布式方式对dataframe执行操作,将地理空间数据纬度/经度属性转换为点几何。

我们还可以执行分布式空间连接,在本例中使用GeoMesa提供的st_contains UDF来生成针对拾取点的所有多边形的最终连接。

% scalaval joinedDF = wktDF。加入(df, st_contains(美元)“the_geom”美元,“pickup_point”显示器(joinedDF.select (“区域”“区”“pickup_point”“pickup_datetime”))

例如,使用GeoMesa提供的st_contains UDF根据拾取点生成所有多边形的最终连接。例如,使用GeoMesa提供的st_contains UDF根据拾取点生成所有多边形的最终连接。

在udf中包装单节点库

除了使用专门构建的分布式空间框架外,现有的单节点库还可以包装在专门的udf中,以便以分布式方式对dataframe执行地理空间操作。这种模式适用于所有Spark语言绑定(Scala、Java、Python、R和SQL),是一种通过最小的代码更改来利用现有工作负载的简单方法。为了演示一个单节点示例,让我们加载NYC自治区数据并为其定义UDF find_borough(…)点包容操作,将每个GPS位置分配给一个行政区使用地质地图。这也可以用矢量化UDF为了更好的表现。

% python#用地质地图阅读行政区的多边形GDF = gpd .read_file(“/ dbfs / ml /博客/地理/ nyc_boroughs.geojson”B_gdf = sc.broadcast(gdf)#广播geopandas数据帧到集群的所有节点deffind_borough纬度、经度):MGDF = b_gdf.value.apply(λx: [“boro_name”]如果x (“几何”] .intersects(点(经度、纬度))Idx = mddf .first_valid_index()返回mgdf.loc [idx]如果idx没有一个其他的没有一个
              find_borough = udf(find_borough, StringType())

现在我们可以应用UDF向Spark DataFrame中添加一列,该列为每个拾取点分配一个自治区名称。

% python#从delta读取坐标Df = spark.read。格式“δ”) .load (“/毫升/博客/地理/δ/ nyc-green”df_with_boroughs = df.withColumn(“pickup_borough”, find_borough_udf(坳(“pickup_latitude”)、坳(pickup_longitude)))显示器(df_with_boroughs.select (“pickup_datetime”“pickup_latitude”“pickup_longitude”“pickup_borough”))

单节点示例的结果,其中使用Geopandas将每个GPS位置分配给NYC区。单节点示例的结果,其中使用Geopandas将每个GPS位置分配给NYC区。

空间索引的网格系统

地理空间操作本质上计算成本很高。多边形中的点、空间连接、最近的邻居或与路由的连接都涉及复杂的操作。通过索引网格系统,目标是完全避免地理空间操作。这种方法带来了最具可伸缩性的实现,但需要注意近似操作。下面是H3的一个简单例子。

使用H3缩放空间操作本质上是一个两步过程。第一步是为定义为UDF geoToH3(…)的每个特征(点、多边形……)计算H3索引。第二步是将这些索引用于空间操作,例如空间连接(多边形中的点、k-nearest neighbors等),在本例中定义为UDF multiPolygonToH3(…)。

% scala进口com.uber.h3core.H3Core进口com.uber.h3core.util.GeoCoord进口scala.collection.JavaConversions._进口scala.collection.JavaConverters._对象H3扩展可序列化的{val instance = H3Core.newInstance()}val geoToH3 = udf{纬度:Double,经度:Double,分辨率:Int) = >H3.instance。geoToH3(纬度,经度,分辨率)}val polygonToH3 = udf{几何:几何,分辨率:Int) = >var点号:List[GeoCoord] = List()var洞:[java.util列表。List[GeoCoord]] = List()如果(几何。getGeometryType = =“多边形”){点数=列表(几何.getCoordinates ().toList. map (coord=>GeoCoord (coord。Y,坐标。x)): _*)}H3.instance。polyfill(点,洞。作为Java, resolution).toList}val multiPolygonToH3 = udf{几何:几何,分辨率:Int) = >var点号:List[GeoCoord] = List()var洞:[java.util列表。List[GeoCoord]] = List()如果(几何。getGeometryType = =“多个多边形”){val numGeometries =几何。getnumgeometries ()如果(numGeometries >0){点数=列表(几何.getGeometryN (0.getCoordinates ().toList. map (coord=>GeoCoord (coord。Y,坐标。x)): _*)}如果(numGeometries >1){洞= (1to (numGeometries - .1) .toList.map (n=>{列表(几何.getGeometryN (n).getCoordinates ().toList. map (coord=>GeoCoord (coord。y,坐标。x)): _*).asJava})}}H3.instance。polyfill(点,洞。作为Java, resolution).toList}

现在,我们可以将这两个udf应用于NYC出租车数据以及自治区多边形集,以生成H3指数。

% scalaVal res =7// H3指数分辨率为1.2kmval dfH3 = df.withColumn(“h3index”geoToH3(坳(“pickup_latitude”)、坳(“pickup_longitude”),点燃(res))val wktDFH3 = wktDF.withColumn (“h3index”, multiPolygonToH3(坳(“the_geom”),点燃(res))).withColumn (“h3index”爆炸(美元)“h3index”))

给定一组lat/lon点和一组多边形几何图形,现在可以使用h3index字段作为连接条件来执行空间连接。例如,这些分配可用于聚合每个多边形内的点的数量。通常有数百万或数十亿个点必须匹配到数千或数百万个多边形,这就需要一个可伸缩的方法。在这篇博客中,还有其他技术没有涉及到,当近似值不够时,这些技术可以用于索引,以支持空间操作。

% scalaval dfWithBoroughH3 = dfH3.join(wktDFH3“h3index”显示器(df_with_borough_h3.select (“区域”“区”“pickup_point”“pickup_datetime”“h3index”))

DataFrame表,表示一组latat /lon点和多边形几何图形的空间连接,使用特定字段作为连接条件。DataFrame表,表示一组latat /lon点和多边形几何图形的空间连接,使用特定字段作为连接条件。

下面是出租车下车位置的可视化图,纬度和经度以7 (1.22km边长)的分辨率分组,并根据每个分组中的聚合计数进行着色。

出租车下车位置的地理空间可视化,以7的分辨率(1.22km边长)对纬度和经度进行分组,并根据每个分组中的聚合计数进行着色。出租车下车位置的地理空间可视化,以7的分辨率(1.22km边长)对纬度和经度进行分组,并根据每个分组中的聚合计数进行着色。

处理空间格式与数据

地理空间数据涉及到地球上物理位置或范围的参考点,如纬度和经度,以及由属性描述的特征。虽然有许多文件格式可供选择,但我们选择了一些代表性的矢量和光栅格式来演示如何使用Databricks读取。

矢量数据

矢量数据是世界的一种表示,存储在x(经度),y(纬度)坐标(度)中,如果考虑到海拔,也存储在z(高度,米)中。矢量数据的三种基本符号类型是点、线和多边形。Well-known-text(预留)GeoJSON,Shapefile下面是一些流行的矢量数据存储格式。

让我们读取带有存储为WKT的几何图形的NYC Taxi Zone数据。我们想要返回的数据结构是一个DataFrame,它将允许我们标准化其他api和可用数据源,比如博客中其他地方使用的那些。我们能够轻松地将字段the_geom中的WKT文本内容转换为相应的JTS几何类通过st_geomFromWKT(…)UDF调用。

% scalaval wktDFText = sqlContext.read。格式“csv”.option (“头”“真正的”.option (“inferSchema”“真正的”.load (“/ ml /博客/地理/ nyc_taxi_zones.wkt.csv”val wktDF = wktDFText.withColumn(“the_geom”, st_geomFromWKT(坳(“the_geom”))) .cache

许多开源GIS包都使用GeoJSON来编码各种地bob下载地址理数据结构,包括它们的特征、属性和空间范围。对于本例,我们将根据工作流程采用的方法来读取NYC Borough Boundaries。由于数据是符合JSON的,我们可以使用Databricks内置的带有.option("multiline","true")的JSON读取器来加载带有嵌套模式的数据。

% pythonJson_df = spark.read.option(“多行”“真正的”) . json (“nyc_boroughs.geojson”

使用Databricks内置JSON阅读器的例子。使用Databricks内置JSON阅读器.option("multiline","true")以嵌套模式加载数据的示例。

从那里,我们可以选择使用Spark的内置爆炸功能将任何字段提升到顶级列。例如,我们可能希望打开几何图形、属性和类型,然后将几何图形转换为相应的JTS类,如WKT示例所示。

% pythonpyspark.sql进口功能作为FJson_explode_df = (json_df.select(“特征”“类型”F.explode (F.col (“features.properties”) .alias (“属性”) .select (“*”, F.explode (F.col (“features.geometry”) .alias (“几何”) .drop (“特征”))
              显示器(json_explode_df)

使用Spark内置的爆炸函数将字段提升到顶层,显示在DataFrame表中。使用Spark内置的爆炸函数将字段提升到顶层,显示在DataFrame表中。

我们还可以使用现有的DataFrame在笔记本中可视化NYC Taxi Zone数据,或者直接使用诸如叶形,一个用于呈现空间数据的Python库。数据库文件系统(DBFS)在分布式存储层上运行,允许代码使用熟悉的文件系统标准处理数据格式。DBFS有一个保险丝山允许本地API调用来执行文件读写操作,这使得使用非分布式API加载数据进行交互呈现变得非常容易。在下面的Python open(…)命令中,“/dbfs/…”前缀允许使用FUSE Mount。

% python进口叶形进口json开放“/ dbfs / ml /博客/地理/ nyc_boroughs.geojson”“r”作为myfile:boro_data = myfile.read ()#使用FuseMount从DBFS读取GeoJSON
              M =叶子。地图(位置= [40.7128, -74.0060),瓷砖=雄蕊地形的zoom_start =12folium.GeoJson (json.loads (boro_data) .add_to (m)#来显示,也可以使用displayHTML(…)变体

我们还可以可视化NYC Taxi Zone数据,例如,在笔记本中使用现有的DataFrame或直接使用Folium(用于渲染地理空间数据的Python库)等库渲染数据。我们还可以可视化NYC Taxi Zone数据,例如,在笔记本中使用现有的DataFrame或直接使用Folium(用于渲染地理空间数据的Python库)等库渲染数据。

Shapefile是ESRI开发的一种流行的矢量格式,用于存储地理特征的几何位置和属性信息。该格式由具有公共文件名前缀(*)的文件集合组成。轴马力,*。Shx和*。DBF是必须的)存储在同一目录。shapefile的替代方法是KML,也被我们的客户使用,但为了简洁,没有显示出来。对于本例,让我们使用NYC Building shapefile。虽然有许多方法可以演示读取shapefile,但我们将给出一个使用GeoSpark的示例。内置ShapefileReader用于生成rawSpatialDf DataFrame。

% scalavarspatialRDD =SpatialRDD(几何)spatialRDD = shapefilereader . readgeometryrdd (sc,“/毫升/博客/地理/ shapefile /纽约”varrawSpatialDf = Adapter.toDf(spatialRDD,spark)rawSpatialDf.createOrReplaceTempView (“rawSpatialDf”//DataFrame现在可用于SQL, Python和R

通过注册rawSpatialDf作为临时视图,我们可以轻松地使用纯Spark SQL语法来处理DataFrame,包括应用UDF来将形状文件WKT转换为几何。

%sql选择*ST_GeomFromWKT(几何)作为几何- GeoSpark UDF转换WKT为几何rawspatialdf

此外,我们可以使用内置可视化的Databricks进行内联分析,例如绘制纽约市最高的建筑图表。

%sql选择名字圆((num_floors作为),0作为num_floors——从字符串到数字rawspatialdf在哪里名字订单通过num_floorsDESC限制5

Databricks内置的可视化内联分析图表,例如,纽约市最高的建筑物。Databricks内置的可视化内联分析图表,例如,纽约市最高的建筑物。

栅格数据

栅格数据将特征信息存储在一个由单元格(或像素)组成的矩阵中,该矩阵被组织成行和列(离散或连续)。卫星图像、摄影测量和扫描地图都是基于栅格的地球观测(EO)数据。

下面的Python示例使用以数据帧为中心的空间分析框架RasterFrames进行读取两个乐队GeoTIFF Landsat-8图像(红色和近红外),并将它们组合成归一化差异植被指数.我们可以利用这些数据来评估纽约市周围的植物健康状况。rf_ipython模块用于将RasterFrame内容操作为各种视觉上有用的形式,例如下面的红色、NIR和NDVI平头列使用颜色坡道呈现,使用Databricks内置的displayHTML(…)命令在笔记本中显示结果。

% python#构造一个CSV“目录”的RasterFrames '光栅'阅读器# catalogs也可以是Spark或

RasterFrame内容可以通过200多个栅格和矢量函数进行过滤、转换、汇总、重采样和栅格化。RasterFrame内容可以通过200多个栅格和矢量函数进行过滤、转换、汇总、重采样和栅格化。

通过其习俗火花数据源,光栅帧可以读取各种光栅格式,包括GeoTIFF, JP2000, MRF,和HDF,从一个服务数组.它还支持读取矢量格式GeoJSON和WKT/WKB。可以对RasterFrame内容进行过滤、转换、汇总、重采样和栅格化200+光栅和矢量函数,例如上面例子中使用的st_reproject(…)和st_centroid(…)。它提供了Python、SQL和Scala的api,以及与Spark ML的互操作性。

GeoDatabases

对于较小规模的数据,地理数据库可以基于文件,对于中等规模的数据,可以通过JDBC / ODBC连接访问。你可以使用Databricks查询许多内置的SQL数据库JDBC / ODBC数据源.连接到PostgreSQL下面所示的应用程序通常用于较小规模的工作负载PostGIS扩展。这种连接模式允许客户保持对现有数据库的按原样访问。

% scala显示器(sqlContext.read。格式“jdbc”.option (“url”jdbcUrl).option (“司机”“org.postgresql.Driver”.option (“数据表”"""(SELECT * FROM yellow_tripdata_stagingOFFSET 5 LIMIT 10) AS t""") //谓词下推.option (“用户”jdbcUsername).option (“jdbcPassword”jdbcPassword).load)

数据库地理空间分析入门

企业和政府机构试图将空间引用数据与企业数据源结合使用,以获得可操作的见解,并交付广泛的创新用例。在这篇博客中,我们演示了如何Databricks统一数据分析平台bob体育客户端下载可以轻松扩展地理空间工作负载,使我们的客户能够利用云的力量来捕获、存储和分析大规模数据。

在即将发布的博客中,我们将深入探讨使用Databricks进行大规模地理空间处理的更高级主题。通过回顾,您将发现关于空间格式和突出显示框架的更多细节数据准备笔记本GeoMesa + H3笔记本GeoSpark笔记本GeoPandas笔记本,Rasterframes笔记本.另外,请继续关注我们的新章节文档特别针对感兴趣的地理空间主题。

下一个步骤

免费试用Databricks

相关的帖子

看到所有工程的博客的帖子